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

Configure Feed

Select the types of activity you want to include in your feed.

irqchip/gic-v5: Add ACPI ITS probing

On ACPI ARM64 systems the GICv5 ITS configuration and translate frames
are described in the MADT table.

Refactor the current GICv5 ITS driver code to share common functions
between ACPI and OF and implement ACPI probing in the GICv5 ITS driver.

Add iort_msi_xlate() to map a device ID and retrieve an MSI controller
fwnode node for ACPI systems and update pci_msi_map_rid_ctlr_node() to
use it in its ACPI code path.

Add the required functions to IORT code for deviceID retrieval and IRQ
domain registration and look-up so that the GICv5 ITS driver in an
ACPI based system can be successfully probed.

Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Acked-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260115-gicv5-host-acpi-v3-5-c13a9a150388@kernel.org
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Lorenzo Pieralisi and committed by
Rafael J. Wysocki
a97efa5b 35866efa

+244 -45
+77 -21
drivers/acpi/arm64/iort.c
··· 595 595 } 596 596 597 597 /** 598 - * iort_pmsi_get_dev_id() - Get the device id for a device 598 + * iort_msi_xlate() - Map a MSI input ID for a device 599 599 * @dev: The device for which the mapping is to be done. 600 - * @dev_id: The device ID found. 600 + * @input_id: The device input ID. 601 + * @fwnode: Pointer to store the fwnode. 601 602 * 602 - * Returns: 0 for successful find a dev id, -ENODEV on error 603 + * Returns: mapped MSI ID on success, input ID otherwise 604 + * On success, the fwnode pointer is initialized to the MSI 605 + * controller fwnode handle. 603 606 */ 604 - int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) 607 + u32 iort_msi_xlate(struct device *dev, u32 input_id, struct fwnode_handle **fwnode) 605 608 { 606 - int i, index; 609 + struct acpi_iort_its_group *its; 607 610 struct acpi_iort_node *node; 611 + u32 dev_id; 608 612 609 613 node = iort_find_dev_node(dev); 610 614 if (!node) 611 - return -ENODEV; 615 + return input_id; 612 616 613 - index = iort_get_id_mapping_index(node); 614 - /* if there is a valid index, go get the dev_id directly */ 615 - if (index >= 0) { 616 - if (iort_node_get_id(node, dev_id, index)) 617 - return 0; 618 - } else { 619 - for (i = 0; i < node->mapping_count; i++) { 620 - if (iort_node_map_platform_id(node, dev_id, 621 - IORT_MSI_TYPE, i)) 622 - return 0; 623 - } 624 - } 617 + node = iort_node_map_id(node, input_id, &dev_id, IORT_MSI_TYPE); 618 + if (!node) 619 + return input_id; 625 620 626 - return -ENODEV; 621 + /* Move to ITS specific data */ 622 + its = (struct acpi_iort_its_group *)node->node_data; 623 + 624 + *fwnode = iort_find_domain_token(its->identifiers[0]); 625 + 626 + return dev_id; 627 627 } 628 628 629 - static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base) 629 + int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base) 630 630 { 631 631 struct iort_its_msi_chip *its_msi_chip; 632 632 int ret = -ENODEV; 633 633 634 634 spin_lock(&iort_msi_chip_lock); 635 635 list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) { 636 - if (its_msi_chip->translation_id == its_id) { 636 + if (its_msi_chip->fw_node == node) { 637 637 *base = its_msi_chip->base_addr; 638 638 ret = 0; 639 639 break; ··· 642 642 spin_unlock(&iort_msi_chip_lock); 643 643 644 644 return ret; 645 + } 646 + 647 + static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base) 648 + { 649 + struct fwnode_handle *fwnode = iort_find_domain_token(its_id); 650 + 651 + if (!fwnode) 652 + return -ENODEV; 653 + 654 + return iort_its_translate_pa(fwnode, base); 655 + } 656 + 657 + /** 658 + * iort_pmsi_get_msi_info() - Get the device id and translate frame PA for a device 659 + * @dev: The device for which the mapping is to be done. 660 + * @dev_id: The device ID found. 661 + * @pa: optional pointer to store translate frame address. 662 + * 663 + * Returns: 0 for successful devid and pa retrieval, -ENODEV on error 664 + */ 665 + int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa) 666 + { 667 + struct acpi_iort_node *node, *parent = NULL; 668 + struct acpi_iort_its_group *its; 669 + int i, index; 670 + 671 + node = iort_find_dev_node(dev); 672 + if (!node) 673 + return -ENODEV; 674 + 675 + index = iort_get_id_mapping_index(node); 676 + /* if there is a valid index, go get the dev_id directly */ 677 + if (index >= 0) { 678 + parent = iort_node_get_id(node, dev_id, index); 679 + } else { 680 + for (i = 0; i < node->mapping_count; i++) { 681 + parent = iort_node_map_platform_id(node, dev_id, 682 + IORT_MSI_TYPE, i); 683 + if (parent) 684 + break; 685 + } 686 + } 687 + 688 + if (!parent) 689 + return -ENODEV; 690 + 691 + if (pa) { 692 + int ret; 693 + 694 + its = (struct acpi_iort_its_group *)node->node_data; 695 + ret = iort_find_its_base(its->identifiers[0], pa); 696 + if (ret) 697 + return ret; 698 + } 699 + 700 + return 0; 645 701 } 646 702 647 703 /**
+20 -19
drivers/irqchip/irq-gic-its-msi-parent.c
··· 19 19 MSI_FLAG_PCI_MSIX | \ 20 20 MSI_FLAG_MULTI_PCI_MSI) 21 21 22 - static int its_translate_frame_address(struct device_node *msi_node, phys_addr_t *pa) 22 + static int its_translate_frame_address(struct fwnode_handle *msi_node, phys_addr_t *pa) 23 23 { 24 24 struct resource res; 25 25 int ret; 26 26 27 - ret = of_property_match_string(msi_node, "reg-names", "ns-translate"); 28 - if (ret < 0) 29 - return ret; 27 + if (is_of_node(msi_node)) { 28 + struct device_node *msi_np = to_of_node(msi_node); 30 29 31 - ret = of_address_to_resource(msi_node, ret, &res); 32 - if (ret) 33 - return ret; 30 + ret = of_property_match_string(msi_np, "reg-names", "ns-translate"); 31 + if (ret < 0) 32 + return ret; 33 + 34 + ret = of_address_to_resource(msi_np, ret, &res); 35 + if (ret) 36 + return ret; 37 + } else { 38 + ret = iort_its_translate_pa(msi_node, &res.start); 39 + } 34 40 35 41 *pa = res.start; 36 42 return 0; ··· 126 120 if (!msi_node) 127 121 return -ENODEV; 128 122 129 - ret = its_translate_frame_address(to_of_node(msi_node), &pa); 123 + ret = its_translate_frame_address(msi_node, &pa); 130 124 if (ret) 131 125 return -ENODEV; 132 126 ··· 167 161 ret = -EINVAL; 168 162 169 163 if (!ret && pa) 170 - ret = its_translate_frame_address(it.node, pa); 164 + ret = its_translate_frame_address(of_fwnode_handle(it.node), pa); 171 165 172 166 if (!ret) 173 167 *dev_id = args; ··· 182 176 return of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &msi_ctrl, dev_id); 183 177 } 184 178 185 - int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) 186 - { 187 - return -1; 188 - } 189 - 190 179 static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, 191 180 int nvec, msi_alloc_info_t *info) 192 181 { ··· 192 191 if (dev->of_node) 193 192 ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, NULL); 194 193 else 195 - ret = iort_pmsi_get_dev_id(dev, &dev_id); 194 + ret = iort_pmsi_get_msi_info(dev, &dev_id, NULL); 196 195 if (ret) 197 196 return ret; 198 197 ··· 215 214 u32 dev_id; 216 215 int ret; 217 216 218 - if (!dev->of_node) 219 - return -ENODEV; 220 - 221 - ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); 217 + if (dev->of_node) 218 + ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); 219 + else 220 + ret = iort_pmsi_get_msi_info(dev, &dev_id, &pa); 222 221 if (ret) 223 222 return ret; 224 223
+5 -2
drivers/irqchip/irq-gic-v5-irs.c
··· 814 814 { 815 815 struct gicv5_irs_chip_data *irs_data; 816 816 817 - list_for_each_entry(irs_data, &irs_nodes, entry) 818 - gicv5_its_of_probe(to_of_node(irs_data->fwnode)); 817 + if (acpi_disabled) 818 + list_for_each_entry(irs_data, &irs_nodes, entry) 819 + gicv5_its_of_probe(to_of_node(irs_data->fwnode)); 820 + else 821 + gicv5_its_acpi_probe(); 819 822 } 820 823 821 824 int __init gicv5_irs_of_probe(struct device_node *parent)
+130 -2
drivers/irqchip/irq-gic-v5-its.c
··· 5 5 6 6 #define pr_fmt(fmt) "GICv5 ITS: " fmt 7 7 8 + #include <linux/acpi.h> 9 + #include <linux/acpi_iort.h> 8 10 #include <linux/bitmap.h> 9 11 #include <linux/iommu.h> 10 12 #include <linux/init.h> ··· 1117 1115 } 1118 1116 1119 1117 static int __init gicv5_its_init_bases(void __iomem *its_base, struct fwnode_handle *handle, 1120 - struct irq_domain *parent_domain) 1118 + struct irq_domain *parent_domain, bool noncoherent) 1121 1119 { 1122 1120 struct device_node *np = to_of_node(handle); 1123 1121 struct gicv5_its_chip_data *its_node; ··· 1210 1208 } 1211 1209 1212 1210 ret = gicv5_its_init_bases(its_base, of_fwnode_handle(node), 1213 - gicv5_global_data.lpi_domain); 1211 + gicv5_global_data.lpi_domain, 1212 + of_property_read_bool(node, "dma-noncoherent")); 1214 1213 if (ret) 1215 1214 goto out_unmap; 1216 1215 ··· 1234 1231 pr_err("Failed to init ITS %s\n", np->full_name); 1235 1232 } 1236 1233 } 1234 + 1235 + #ifdef CONFIG_ACPI 1236 + 1237 + #define ACPI_GICV5_ITS_MEM_SIZE (SZ_64K) 1238 + 1239 + static struct acpi_madt_gicv5_translator *current_its_entry __initdata; 1240 + static struct fwnode_handle *current_its_fwnode __initdata; 1241 + 1242 + static int __init gic_acpi_parse_madt_its_translate(union acpi_subtable_headers *header, 1243 + const unsigned long end) 1244 + { 1245 + struct acpi_madt_gicv5_translate_frame *its_frame; 1246 + struct fwnode_handle *msi_dom_handle; 1247 + struct resource res = {}; 1248 + int err; 1249 + 1250 + its_frame = (struct acpi_madt_gicv5_translate_frame *)header; 1251 + if (its_frame->linked_translator_id != current_its_entry->translator_id) 1252 + return 0; 1253 + 1254 + res.start = its_frame->base_address; 1255 + res.end = its_frame->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1; 1256 + res.flags = IORESOURCE_MEM; 1257 + 1258 + msi_dom_handle = irq_domain_alloc_parented_fwnode(&res.start, current_its_fwnode); 1259 + if (!msi_dom_handle) { 1260 + pr_err("ITS@%pa: Unable to allocate GICv5 ITS translate domain token\n", 1261 + &res.start); 1262 + return -ENOMEM; 1263 + } 1264 + 1265 + err = iort_register_domain_token(its_frame->translate_frame_id, res.start, 1266 + msi_dom_handle); 1267 + if (err) { 1268 + pr_err("ITS@%pa: Unable to register GICv5 ITS domain token (ITS TRANSLATE FRAME ID %d) to IORT\n", 1269 + &res.start, its_frame->translate_frame_id); 1270 + irq_domain_free_fwnode(msi_dom_handle); 1271 + return err; 1272 + } 1273 + 1274 + return 0; 1275 + } 1276 + 1277 + static int __init gic_acpi_free_madt_its_translate(union acpi_subtable_headers *header, 1278 + const unsigned long end) 1279 + { 1280 + struct acpi_madt_gicv5_translate_frame *its_frame; 1281 + struct fwnode_handle *msi_dom_handle; 1282 + 1283 + its_frame = (struct acpi_madt_gicv5_translate_frame *)header; 1284 + if (its_frame->linked_translator_id != current_its_entry->translator_id) 1285 + return 0; 1286 + 1287 + msi_dom_handle = iort_find_domain_token(its_frame->translate_frame_id); 1288 + if (!msi_dom_handle) 1289 + return 0; 1290 + 1291 + iort_deregister_domain_token(its_frame->translate_frame_id); 1292 + irq_domain_free_fwnode(msi_dom_handle); 1293 + 1294 + return 0; 1295 + } 1296 + 1297 + static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, 1298 + const unsigned long end) 1299 + { 1300 + struct acpi_madt_gicv5_translator *its_entry; 1301 + struct fwnode_handle *dom_handle; 1302 + struct resource res = {}; 1303 + void __iomem *its_base; 1304 + int err; 1305 + 1306 + its_entry = (struct acpi_madt_gicv5_translator *)header; 1307 + res.start = its_entry->base_address; 1308 + res.end = its_entry->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1; 1309 + res.flags = IORESOURCE_MEM; 1310 + 1311 + if (!request_mem_region(res.start, resource_size(&res), "GICv5 ITS")) 1312 + return -EBUSY; 1313 + 1314 + dom_handle = irq_domain_alloc_fwnode(&res.start); 1315 + if (!dom_handle) { 1316 + pr_err("ITS@%pa: Unable to allocate GICv5 ITS domain token\n", 1317 + &res.start); 1318 + err = -ENOMEM; 1319 + goto out_rel_res; 1320 + } 1321 + 1322 + current_its_entry = its_entry; 1323 + current_its_fwnode = dom_handle; 1324 + 1325 + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE, 1326 + gic_acpi_parse_madt_its_translate, 0); 1327 + 1328 + its_base = ioremap(res.start, ACPI_GICV5_ITS_MEM_SIZE); 1329 + if (!its_base) { 1330 + err = -ENOMEM; 1331 + goto out_unregister; 1332 + } 1333 + 1334 + err = gicv5_its_init_bases(its_base, dom_handle, gicv5_global_data.lpi_domain, 1335 + its_entry->flags & ACPI_MADT_GICV5_ITS_NON_COHERENT); 1336 + if (err) 1337 + goto out_unmap; 1338 + 1339 + return 0; 1340 + 1341 + out_unmap: 1342 + iounmap(its_base); 1343 + out_unregister: 1344 + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE, 1345 + gic_acpi_free_madt_its_translate, 0); 1346 + irq_domain_free_fwnode(dom_handle); 1347 + out_rel_res: 1348 + release_mem_region(res.start, resource_size(&res)); 1349 + return err; 1350 + } 1351 + 1352 + void __init gicv5_its_acpi_probe(void) 1353 + { 1354 + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS, gic_acpi_parse_madt_its, 0); 1355 + } 1356 + #else 1357 + void __init gicv5_its_acpi_probe(void) { } 1358 + #endif
+2
drivers/pci/msi/irqdomain.c
··· 401 401 rid = of_msi_xlate(&pdev->dev, &msi_ctlr_node, rid); 402 402 if (msi_ctlr_node) 403 403 *node = of_fwnode_handle(msi_ctlr_node); 404 + } else { 405 + rid = iort_msi_xlate(&pdev->dev, rid, node); 404 406 } 405 407 406 408 return rid;
+9 -1
include/linux/acpi_iort.h
··· 27 27 struct fwnode_handle *fw_node); 28 28 void iort_deregister_domain_token(int trans_id); 29 29 struct fwnode_handle *iort_find_domain_token(int trans_id); 30 - int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); 31 30 32 31 #ifdef CONFIG_ACPI_IORT 33 32 u32 iort_msi_map_id(struct device *dev, u32 id); 33 + u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode_handle **node); 34 + int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base); 34 35 struct irq_domain *iort_get_device_domain(struct device *dev, u32 id, 35 36 enum irq_domain_bus_token bus_token); 37 + int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa); 36 38 void acpi_configure_pmsi_domain(struct device *dev); 37 39 void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, 38 40 struct list_head *head); ··· 48 46 #else 49 47 static inline u32 iort_msi_map_id(struct device *dev, u32 id) 50 48 { return id; } 49 + static inline u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode_handle **node) 50 + { return id; } 51 + static inline int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base) 52 + { return -ENODEV; } 51 53 static inline struct irq_domain *iort_get_device_domain( 52 54 struct device *dev, u32 id, enum irq_domain_bus_token bus_token) 53 55 { return NULL; } 56 + static inline int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa) 57 + { return -ENODEV; } 54 58 static inline void acpi_configure_pmsi_domain(struct device *dev) { } 55 59 static inline 56 60 void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_head *head) { }
+1
include/linux/irqchip/arm-gic-v5.h
··· 392 392 void gicv5_free_lpi(u32 lpi); 393 393 394 394 void __init gicv5_its_of_probe(struct device_node *parent); 395 + void __init gicv5_its_acpi_probe(void); 395 396 #endif