summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/arm64
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2016-11-21 05:01:48 -0500
committerWill Deacon <will.deacon@arm.com>2016-11-29 10:57:48 -0500
commit643b8e4d86f8b1a62cf5cd9ea221e9bc0d531d18 (patch)
tree6711969d45ce0d326661f023074db753657f472d /drivers/acpi/arm64
parent618f535a60623c9e7c596b208a57bf094766b9f6 (diff)
ACPI/IORT: Introduce iort_iommu_configure
DT based systems have a generic kernel API to configure IOMMUs for devices (ie of_iommu_configure()). On ARM based ACPI systems, the of_iommu_configure() equivalent can be implemented atop ACPI IORT kernel API, with the corresponding functions to map device identifiers to IOMMUs and retrieve the corresponding IOMMU operations necessary for DMA operations set-up. By relying on the iommu_fwspec generic kernel infrastructure, implement the IORT based IOMMU configuration for ARM ACPI systems and hook it up in the ACPI kernel layer that implements DMA configuration for a device. Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> [ACPI core] Reviewed-by: Tomasz Nowicki <tn@semihalf.com> Tested-by: Hanjun Guo <hanjun.guo@linaro.org> Tested-by: Tomasz Nowicki <tn@semihalf.com> Cc: Hanjun Guo <hanjun.guo@linaro.org> Cc: Tomasz Nowicki <tn@semihalf.com> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/acpi/arm64')
-rw-r--r--drivers/acpi/arm64/iort.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6aae49c35a95..47bace8eafb6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -28,6 +28,8 @@
28 28
29#define IORT_TYPE_MASK(type) (1 << (type)) 29#define IORT_TYPE_MASK(type) (1 << (type))
30#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP) 30#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
31#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
32 (1 << ACPI_IORT_NODE_SMMU_V3))
31 33
32struct iort_its_msi_chip { 34struct iort_its_msi_chip {
33 struct list_head list; 35 struct list_head list;
@@ -501,6 +503,102 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
501 return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); 503 return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
502} 504}
503 505
506static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
507{
508 u32 *rid = data;
509
510 *rid = alias;
511 return 0;
512}
513
514static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
515 struct fwnode_handle *fwnode,
516 const struct iommu_ops *ops)
517{
518 int ret = iommu_fwspec_init(dev, fwnode, ops);
519
520 if (!ret)
521 ret = iommu_fwspec_add_ids(dev, &streamid, 1);
522
523 return ret;
524}
525
526static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
527 struct acpi_iort_node *node,
528 u32 streamid)
529{
530 const struct iommu_ops *ops = NULL;
531 int ret = -ENODEV;
532 struct fwnode_handle *iort_fwnode;
533
534 if (node) {
535 iort_fwnode = iort_get_fwnode(node);
536 if (!iort_fwnode)
537 return NULL;
538
539 ops = iommu_get_instance(iort_fwnode);
540 if (!ops)
541 return NULL;
542
543 ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
544 }
545
546 return ret ? NULL : ops;
547}
548
549/**
550 * iort_iommu_configure - Set-up IOMMU configuration for a device.
551 *
552 * @dev: device to configure
553 *
554 * Returns: iommu_ops pointer on configuration success
555 * NULL on configuration failure
556 */
557const struct iommu_ops *iort_iommu_configure(struct device *dev)
558{
559 struct acpi_iort_node *node, *parent;
560 const struct iommu_ops *ops = NULL;
561 u32 streamid = 0;
562
563 if (dev_is_pci(dev)) {
564 struct pci_bus *bus = to_pci_dev(dev)->bus;
565 u32 rid;
566
567 pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
568 &rid);
569
570 node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
571 iort_match_node_callback, &bus->dev);
572 if (!node)
573 return NULL;
574
575 parent = iort_node_map_rid(node, rid, &streamid,
576 IORT_IOMMU_TYPE);
577
578 ops = iort_iommu_xlate(dev, parent, streamid);
579
580 } else {
581 int i = 0;
582
583 node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
584 iort_match_node_callback, dev);
585 if (!node)
586 return NULL;
587
588 parent = iort_node_get_id(node, &streamid,
589 IORT_IOMMU_TYPE, i++);
590
591 while (parent) {
592 ops = iort_iommu_xlate(dev, parent, streamid);
593
594 parent = iort_node_get_id(node, &streamid,
595 IORT_IOMMU_TYPE, i++);
596 }
597 }
598
599 return ops;
600}
601
504static void __init acpi_iort_register_irq(int hwirq, const char *name, 602static void __init acpi_iort_register_irq(int hwirq, const char *name,
505 int trigger, 603 int trigger,
506 struct resource *res) 604 struct resource *res)