| .. | .. |
|---|
| 7 | 7 | * |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | |
|---|
| 10 | +#include <linux/acpi.h> |
|---|
| 11 | +#include <linux/acpi_iort.h> |
|---|
| 10 | 12 | #include <linux/of_device.h> |
|---|
| 11 | 13 | #include <linux/of_address.h> |
|---|
| 12 | 14 | #include <linux/irq.h> |
|---|
| .. | .. |
|---|
| 22 | 24 | .irq_eoi = irq_chip_eoi_parent, |
|---|
| 23 | 25 | .irq_set_affinity = msi_domain_set_affinity |
|---|
| 24 | 26 | }; |
|---|
| 27 | + |
|---|
| 28 | +static u32 fsl_mc_msi_domain_get_msi_id(struct irq_domain *domain, |
|---|
| 29 | + struct fsl_mc_device *mc_dev) |
|---|
| 30 | +{ |
|---|
| 31 | + struct device_node *of_node; |
|---|
| 32 | + u32 out_id; |
|---|
| 33 | + |
|---|
| 34 | + of_node = irq_domain_get_of_node(domain); |
|---|
| 35 | + out_id = of_node ? of_msi_map_id(&mc_dev->dev, of_node, mc_dev->icid) : |
|---|
| 36 | + iort_msi_map_id(&mc_dev->dev, mc_dev->icid); |
|---|
| 37 | + |
|---|
| 38 | + return out_id; |
|---|
| 39 | +} |
|---|
| 25 | 40 | |
|---|
| 26 | 41 | static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, |
|---|
| 27 | 42 | struct device *dev, |
|---|
| .. | .. |
|---|
| 43 | 58 | * NOTE: This device id corresponds to the IOMMU stream ID |
|---|
| 44 | 59 | * associated with the DPRC object (ICID). |
|---|
| 45 | 60 | */ |
|---|
| 46 | | - info->scratchpad[0].ul = mc_bus_dev->icid; |
|---|
| 61 | + info->scratchpad[0].ul = fsl_mc_msi_domain_get_msi_id(msi_domain, |
|---|
| 62 | + mc_bus_dev); |
|---|
| 47 | 63 | msi_info = msi_get_domain_info(msi_domain->parent); |
|---|
| 48 | 64 | |
|---|
| 49 | 65 | /* Allocate at least 32 MSIs, and always as a power of 2 */ |
|---|
| .. | .. |
|---|
| 66 | 82 | {}, |
|---|
| 67 | 83 | }; |
|---|
| 68 | 84 | |
|---|
| 69 | | -static int __init its_fsl_mc_msi_init(void) |
|---|
| 85 | +static void __init its_fsl_mc_msi_init_one(struct fwnode_handle *handle, |
|---|
| 86 | + const char *name) |
|---|
| 70 | 87 | { |
|---|
| 71 | | - struct device_node *np; |
|---|
| 72 | 88 | struct irq_domain *parent; |
|---|
| 73 | 89 | struct irq_domain *mc_msi_domain; |
|---|
| 90 | + |
|---|
| 91 | + parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS); |
|---|
| 92 | + if (!parent || !msi_get_domain_info(parent)) { |
|---|
| 93 | + pr_err("%s: unable to locate ITS domain\n", name); |
|---|
| 94 | + return; |
|---|
| 95 | + } |
|---|
| 96 | + |
|---|
| 97 | + mc_msi_domain = fsl_mc_msi_create_irq_domain(handle, |
|---|
| 98 | + &its_fsl_mc_msi_domain_info, |
|---|
| 99 | + parent); |
|---|
| 100 | + if (!mc_msi_domain) { |
|---|
| 101 | + pr_err("%s: unable to create fsl-mc domain\n", name); |
|---|
| 102 | + return; |
|---|
| 103 | + } |
|---|
| 104 | + |
|---|
| 105 | + pr_info("fsl-mc MSI: %s domain created\n", name); |
|---|
| 106 | +} |
|---|
| 107 | + |
|---|
| 108 | +#ifdef CONFIG_ACPI |
|---|
| 109 | +static int __init |
|---|
| 110 | +its_fsl_mc_msi_parse_madt(union acpi_subtable_headers *header, |
|---|
| 111 | + const unsigned long end) |
|---|
| 112 | +{ |
|---|
| 113 | + struct acpi_madt_generic_translator *its_entry; |
|---|
| 114 | + struct fwnode_handle *dom_handle; |
|---|
| 115 | + const char *node_name; |
|---|
| 116 | + int err = 0; |
|---|
| 117 | + |
|---|
| 118 | + its_entry = (struct acpi_madt_generic_translator *)header; |
|---|
| 119 | + node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx", |
|---|
| 120 | + (long)its_entry->base_address); |
|---|
| 121 | + |
|---|
| 122 | + dom_handle = iort_find_domain_token(its_entry->translation_id); |
|---|
| 123 | + if (!dom_handle) { |
|---|
| 124 | + pr_err("%s: Unable to locate ITS domain handle\n", node_name); |
|---|
| 125 | + err = -ENXIO; |
|---|
| 126 | + goto out; |
|---|
| 127 | + } |
|---|
| 128 | + |
|---|
| 129 | + its_fsl_mc_msi_init_one(dom_handle, node_name); |
|---|
| 130 | + |
|---|
| 131 | +out: |
|---|
| 132 | + kfree(node_name); |
|---|
| 133 | + return err; |
|---|
| 134 | +} |
|---|
| 135 | + |
|---|
| 136 | + |
|---|
| 137 | +static void __init its_fsl_mc_acpi_msi_init(void) |
|---|
| 138 | +{ |
|---|
| 139 | + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, |
|---|
| 140 | + its_fsl_mc_msi_parse_madt, 0); |
|---|
| 141 | +} |
|---|
| 142 | +#else |
|---|
| 143 | +static inline void its_fsl_mc_acpi_msi_init(void) { } |
|---|
| 144 | +#endif |
|---|
| 145 | + |
|---|
| 146 | +static void __init its_fsl_mc_of_msi_init(void) |
|---|
| 147 | +{ |
|---|
| 148 | + struct device_node *np; |
|---|
| 74 | 149 | |
|---|
| 75 | 150 | for (np = of_find_matching_node(NULL, its_device_id); np; |
|---|
| 76 | 151 | np = of_find_matching_node(np, its_device_id)) { |
|---|
| .. | .. |
|---|
| 79 | 154 | if (!of_property_read_bool(np, "msi-controller")) |
|---|
| 80 | 155 | continue; |
|---|
| 81 | 156 | |
|---|
| 82 | | - parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); |
|---|
| 83 | | - if (!parent || !msi_get_domain_info(parent)) { |
|---|
| 84 | | - pr_err("%pOF: unable to locate ITS domain\n", np); |
|---|
| 85 | | - continue; |
|---|
| 86 | | - } |
|---|
| 87 | | - |
|---|
| 88 | | - mc_msi_domain = fsl_mc_msi_create_irq_domain( |
|---|
| 89 | | - of_node_to_fwnode(np), |
|---|
| 90 | | - &its_fsl_mc_msi_domain_info, |
|---|
| 91 | | - parent); |
|---|
| 92 | | - if (!mc_msi_domain) { |
|---|
| 93 | | - pr_err("%pOF: unable to create fsl-mc domain\n", np); |
|---|
| 94 | | - continue; |
|---|
| 95 | | - } |
|---|
| 96 | | - |
|---|
| 97 | | - pr_info("fsl-mc MSI: %pOF domain created\n", np); |
|---|
| 157 | + its_fsl_mc_msi_init_one(of_node_to_fwnode(np), |
|---|
| 158 | + np->full_name); |
|---|
| 98 | 159 | } |
|---|
| 160 | +} |
|---|
| 161 | + |
|---|
| 162 | +static int __init its_fsl_mc_msi_init(void) |
|---|
| 163 | +{ |
|---|
| 164 | + its_fsl_mc_of_msi_init(); |
|---|
| 165 | + its_fsl_mc_acpi_msi_init(); |
|---|
| 99 | 166 | |
|---|
| 100 | 167 | return 0; |
|---|
| 101 | 168 | } |
|---|