1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Freescale Management Complex (MC) bus driver MSI support 4 * 5 * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. 6 * Author: German Rivera <German.Rivera@freescale.com> 7 * 8 */ 9 10 #include <linux/of_irq.h> 11 #include <linux/irq.h> 12 #include <linux/irqdomain.h> 13 #include <linux/msi.h> 14 #include <linux/acpi_iort.h> 15 16 #include "fsl-mc-private.h" 17 18 static void fsl_mc_write_msi_msg(struct msi_desc *msi_desc, struct msi_msg *msg) 19 { 20 struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(msi_desc->dev); 21 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 22 struct fsl_mc_device_irq *mc_dev_irq = &mc_bus->irq_resources[msi_desc->msi_index]; 23 struct fsl_mc_device *owner_mc_dev = mc_dev_irq->mc_dev; 24 struct dprc_irq_cfg irq_cfg; 25 int error; 26 27 msi_desc->msg = *msg; 28 29 /* 30 * msi_desc->msg.address is 0x0 when this function is invoked in 31 * the free_irq() code path. In this case, for the MC, we don't 32 * really need to "unprogram" the MSI, so we just return. 33 */ 34 if (msi_desc->msg.address_lo == 0x0 && msi_desc->msg.address_hi == 0x0) 35 return; 36 37 if (!owner_mc_dev) 38 return; 39 40 irq_cfg.paddr = ((u64)msi_desc->msg.address_hi << 32) | 41 msi_desc->msg.address_lo; 42 irq_cfg.val = msi_desc->msg.data; 43 irq_cfg.irq_num = msi_desc->irq; 44 45 if (owner_mc_dev == mc_bus_dev) { 46 /* 47 * IRQ is for the mc_bus_dev's DPRC itself 48 */ 49 error = dprc_set_irq(mc_bus_dev->mc_io, 50 MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, 51 mc_bus_dev->mc_handle, 52 mc_dev_irq->dev_irq_index, 53 &irq_cfg); 54 if (error < 0) { 55 dev_err(&owner_mc_dev->dev, 56 "dprc_set_irq() failed: %d\n", error); 57 } 58 } else { 59 /* 60 * IRQ is for for a child device of mc_bus_dev 61 */ 62 error = dprc_set_obj_irq(mc_bus_dev->mc_io, 63 MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, 64 mc_bus_dev->mc_handle, 65 owner_mc_dev->obj_desc.type, 66 owner_mc_dev->obj_desc.id, 67 mc_dev_irq->dev_irq_index, 68 &irq_cfg); 69 if (error < 0) { 70 dev_err(&owner_mc_dev->dev, 71 "dprc_obj_set_irq() failed: %d\n", error); 72 } 73 } 74 } 75 76 struct irq_domain *fsl_mc_get_msi_parent(struct device *dev) 77 { 78 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 79 struct device *root_dprc_dev; 80 struct device *bus_dev; 81 82 fsl_mc_get_root_dprc(dev, &root_dprc_dev); 83 bus_dev = root_dprc_dev->parent; 84 85 return (bus_dev->of_node ? 86 of_msi_get_domain(bus_dev, bus_dev->of_node, DOMAIN_BUS_NEXUS) : 87 iort_get_device_domain(bus_dev, mc_dev->icid, DOMAIN_BUS_NEXUS)); 88 } 89 90 int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count) 91 { 92 int error = msi_setup_device_data(dev); 93 if (error) 94 return error; 95 96 error = platform_device_msi_init_and_alloc_irqs(dev, irq_count, fsl_mc_write_msi_msg); 97 if (error) 98 dev_err(dev, "Failed to allocate IRQs\n"); 99 return error; 100 } 101 102 void fsl_mc_msi_domain_free_irqs(struct device *dev) 103 { 104 msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); 105 } 106 107 u32 fsl_mc_get_msi_id(struct device *dev) 108 { 109 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 110 struct device *root_dprc_dev; 111 112 fsl_mc_get_root_dprc(dev, &root_dprc_dev); 113 114 return (root_dprc_dev->parent->of_node ? 115 of_msi_xlate(dev, NULL, mc_dev->icid) : 116 iort_msi_map_id(dev, mc_dev->icid)); 117 } 118