.. | .. |
---|
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 | } |
---|