Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bus: fsl-mc: Add ACPI support for fsl-mc

Add ACPI support in the fsl-mc driver. Driver parses MC DSDT table to
extract memory and other resources.

Interrupt (GIC ITS) information is extracted from the MADT table
by drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c.

IORT table is parsed to configure DMA.

Signed-off-by: Makarand Pawagi <makarand.pawagi@nxp.com>
Signed-off-by: Diana Craciun <diana.craciun@oss.nxp.com>
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
Link: https://lore.kernel.org/r/20200619082013.13661-13-lorenzo.pieralisi@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Makarand Pawagi and committed by
Catalin Marinas
6305166c 998fb7ba

+149 -51
+55 -18
drivers/bus/fsl-mc/fsl-mc-bus.c
··· 18 18 #include <linux/bitops.h> 19 19 #include <linux/msi.h> 20 20 #include <linux/dma-mapping.h> 21 + #include <linux/acpi.h> 22 + #include <linux/iommu.h> 21 23 22 24 #include "fsl-mc-private.h" 23 25 ··· 40 38 struct fsl_mc_device *root_mc_bus_dev; 41 39 u8 num_translation_ranges; 42 40 struct fsl_mc_addr_translation_range *translation_ranges; 41 + void *fsl_mc_regs; 43 42 }; 44 43 45 44 /** ··· 58 55 u64 end_mc_offset; 59 56 phys_addr_t start_phys_addr; 60 57 }; 58 + 59 + #define FSL_MC_FAPR 0x28 60 + #define MC_FAPR_PL BIT(18) 61 + #define MC_FAPR_BMT BIT(17) 61 62 62 63 /** 63 64 * fsl_mc_bus_match - device to driver matching callback ··· 131 124 while (dev_is_fsl_mc(dma_dev)) 132 125 dma_dev = dma_dev->parent; 133 126 134 - return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id); 127 + if (dev_of_node(dma_dev)) 128 + return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id); 129 + 130 + return acpi_dma_configure_id(dev, DEV_DMA_COHERENT, &input_id); 135 131 } 136 132 137 133 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, ··· 875 865 struct fsl_mc_io *mc_io = NULL; 876 866 int container_id; 877 867 phys_addr_t mc_portal_phys_addr; 878 - u32 mc_portal_size; 879 - struct resource res; 868 + u32 mc_portal_size, mc_stream_id; 869 + struct resource *plat_res; 870 + 871 + if (!iommu_present(&fsl_mc_bus_type)) 872 + return -EPROBE_DEFER; 880 873 881 874 mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); 882 875 if (!mc) ··· 887 874 888 875 platform_set_drvdata(pdev, mc); 889 876 877 + plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 878 + mc->fsl_mc_regs = devm_ioremap_resource(&pdev->dev, plat_res); 879 + if (IS_ERR(mc->fsl_mc_regs)) 880 + return PTR_ERR(mc->fsl_mc_regs); 881 + 882 + if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) { 883 + mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR); 884 + /* 885 + * HW ORs the PL and BMT bit, places the result in bit 15 of 886 + * the StreamID and ORs in the ICID. Calculate it accordingly. 887 + */ 888 + mc_stream_id = (mc_stream_id & 0xffff) | 889 + ((mc_stream_id & (MC_FAPR_PL | MC_FAPR_BMT)) ? 890 + 0x4000 : 0); 891 + error = acpi_dma_configure_id(&pdev->dev, DEV_DMA_COHERENT, 892 + &mc_stream_id); 893 + if (error) 894 + dev_warn(&pdev->dev, "failed to configure dma: %d.\n", 895 + error); 896 + } 897 + 890 898 /* 891 899 * Get physical address of MC portal for the root DPRC: 892 900 */ 893 - error = of_address_to_resource(pdev->dev.of_node, 0, &res); 894 - if (error < 0) { 895 - dev_err(&pdev->dev, 896 - "of_address_to_resource() failed for %pOF\n", 897 - pdev->dev.of_node); 898 - return error; 899 - } 900 - 901 - mc_portal_phys_addr = res.start; 902 - mc_portal_size = resource_size(&res); 901 + plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 902 + mc_portal_phys_addr = plat_res->start; 903 + mc_portal_size = resource_size(plat_res); 903 904 error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, 904 905 mc_portal_size, NULL, 905 906 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); ··· 930 903 dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n", 931 904 mc_version.major, mc_version.minor, mc_version.revision); 932 905 933 - error = get_mc_addr_translation_ranges(&pdev->dev, 934 - &mc->translation_ranges, 935 - &mc->num_translation_ranges); 936 - if (error < 0) 937 - goto error_cleanup_mc_io; 906 + if (dev_of_node(&pdev->dev)) { 907 + error = get_mc_addr_translation_ranges(&pdev->dev, 908 + &mc->translation_ranges, 909 + &mc->num_translation_ranges); 910 + if (error < 0) 911 + goto error_cleanup_mc_io; 912 + } 938 913 939 914 error = dprc_get_container_id(mc_io, 0, &container_id); 940 915 if (error < 0) { ··· 963 934 goto error_cleanup_mc_io; 964 935 965 936 mc->root_mc_bus_dev = mc_bus_dev; 937 + mc_bus_dev->dev.fwnode = pdev->dev.fwnode; 966 938 return 0; 967 939 968 940 error_cleanup_mc_io: ··· 997 967 998 968 MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table); 999 969 970 + static const struct acpi_device_id fsl_mc_bus_acpi_match_table[] = { 971 + {"NXP0008", 0 }, 972 + { } 973 + }; 974 + MODULE_DEVICE_TABLE(acpi, fsl_mc_bus_acpi_match_table); 975 + 1000 976 static struct platform_driver fsl_mc_bus_driver = { 1001 977 .driver = { 1002 978 .name = "fsl_mc_bus", 1003 979 .pm = NULL, 1004 980 .of_match_table = fsl_mc_bus_match_table, 981 + .acpi_match_table = fsl_mc_bus_acpi_match_table, 1005 982 }, 1006 983 .probe = fsl_mc_bus_probe, 1007 984 .remove = fsl_mc_bus_remove,
+21 -14
drivers/bus/fsl-mc/fsl-mc-msi.c
··· 13 13 #include <linux/irq.h> 14 14 #include <linux/irqdomain.h> 15 15 #include <linux/msi.h> 16 + #include <linux/acpi_iort.h> 16 17 17 18 #include "fsl-mc-private.h" 18 19 ··· 180 179 181 180 struct irq_domain *fsl_mc_find_msi_domain(struct device *dev) 182 181 { 183 - struct irq_domain *msi_domain = NULL; 182 + struct device *root_dprc_dev; 183 + struct device *bus_dev; 184 + struct irq_domain *msi_domain; 184 185 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 185 186 186 - msi_domain = of_msi_map_get_device_domain(dev, mc_dev->icid, 187 + fsl_mc_get_root_dprc(dev, &root_dprc_dev); 188 + bus_dev = root_dprc_dev->parent; 189 + 190 + if (bus_dev->of_node) { 191 + msi_domain = of_msi_map_get_device_domain(dev, 192 + mc_dev->icid, 187 193 DOMAIN_BUS_FSL_MC_MSI); 188 194 189 - /* 190 - * if the msi-map property is missing assume that all the 191 - * child containers inherit the domain from the parent 192 - */ 193 - if (!msi_domain) { 194 - struct device *root_dprc_dev; 195 - struct device *bus_dev; 195 + /* 196 + * if the msi-map property is missing assume that all the 197 + * child containers inherit the domain from the parent 198 + */ 199 + if (!msi_domain) 196 200 197 - fsl_mc_get_root_dprc(dev, &root_dprc_dev); 198 - bus_dev = root_dprc_dev->parent; 199 - msi_domain = of_msi_get_domain(bus_dev, 200 - bus_dev->of_node, 201 - DOMAIN_BUS_FSL_MC_MSI); 201 + msi_domain = of_msi_get_domain(bus_dev, 202 + bus_dev->of_node, 203 + DOMAIN_BUS_FSL_MC_MSI); 204 + } else { 205 + msi_domain = iort_get_device_domain(dev, mc_dev->icid, 206 + DOMAIN_BUS_FSL_MC_MSI); 202 207 } 203 208 204 209 return msi_domain;
+73 -19
drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
··· 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> ··· 32 30 u32 out_id; 33 31 34 32 of_node = irq_domain_get_of_node(domain); 35 - out_id = of_msi_map_id(&mc_dev->dev, of_node, mc_dev->icid); 33 + out_id = of_node ? of_msi_map_id(&mc_dev->dev, of_node, mc_dev->icid) : 34 + iort_msi_map_id(&mc_dev->dev, mc_dev->icid); 36 35 37 36 return out_id; 38 37 } ··· 82 79 {}, 83 80 }; 84 81 85 - static int __init its_fsl_mc_msi_init(void) 82 + static void __init its_fsl_mc_msi_init_one(struct fwnode_handle *handle, 83 + const char *name) 86 84 { 87 - struct device_node *np; 88 85 struct irq_domain *parent; 89 86 struct irq_domain *mc_msi_domain; 87 + 88 + parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS); 89 + if (!parent || !msi_get_domain_info(parent)) { 90 + pr_err("%s: unable to locate ITS domain\n", name); 91 + return; 92 + } 93 + 94 + mc_msi_domain = fsl_mc_msi_create_irq_domain(handle, 95 + &its_fsl_mc_msi_domain_info, 96 + parent); 97 + if (!mc_msi_domain) { 98 + pr_err("%s: unable to create fsl-mc domain\n", name); 99 + return; 100 + } 101 + 102 + pr_info("fsl-mc MSI: %s domain created\n", name); 103 + } 104 + 105 + #ifdef CONFIG_ACPI 106 + static int __init 107 + its_fsl_mc_msi_parse_madt(union acpi_subtable_headers *header, 108 + const unsigned long end) 109 + { 110 + struct acpi_madt_generic_translator *its_entry; 111 + struct fwnode_handle *dom_handle; 112 + const char *node_name; 113 + int err = 0; 114 + 115 + its_entry = (struct acpi_madt_generic_translator *)header; 116 + node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx", 117 + (long)its_entry->base_address); 118 + 119 + dom_handle = iort_find_domain_token(its_entry->translation_id); 120 + if (!dom_handle) { 121 + pr_err("%s: Unable to locate ITS domain handle\n", node_name); 122 + err = -ENXIO; 123 + goto out; 124 + } 125 + 126 + its_fsl_mc_msi_init_one(dom_handle, node_name); 127 + 128 + out: 129 + kfree(node_name); 130 + return err; 131 + } 132 + 133 + 134 + static void __init its_fsl_mc_acpi_msi_init(void) 135 + { 136 + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 137 + its_fsl_mc_msi_parse_madt, 0); 138 + } 139 + #else 140 + static inline void its_fsl_mc_acpi_msi_init(void) { } 141 + #endif 142 + 143 + static void __init its_fsl_mc_of_msi_init(void) 144 + { 145 + struct device_node *np; 90 146 91 147 for (np = of_find_matching_node(NULL, its_device_id); np; 92 148 np = of_find_matching_node(np, its_device_id)) { ··· 154 92 if (!of_property_read_bool(np, "msi-controller")) 155 93 continue; 156 94 157 - parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); 158 - if (!parent || !msi_get_domain_info(parent)) { 159 - pr_err("%pOF: unable to locate ITS domain\n", np); 160 - continue; 161 - } 162 - 163 - mc_msi_domain = fsl_mc_msi_create_irq_domain( 164 - of_node_to_fwnode(np), 165 - &its_fsl_mc_msi_domain_info, 166 - parent); 167 - if (!mc_msi_domain) { 168 - pr_err("%pOF: unable to create fsl-mc domain\n", np); 169 - continue; 170 - } 171 - 172 - pr_info("fsl-mc MSI: %pOF domain created\n", np); 95 + its_fsl_mc_msi_init_one(of_node_to_fwnode(np), 96 + np->full_name); 173 97 } 98 + } 99 + 100 + static int __init its_fsl_mc_msi_init(void) 101 + { 102 + its_fsl_mc_of_msi_init(); 103 + its_fsl_mc_acpi_msi_init(); 174 104 175 105 return 0; 176 106 }