diff options
author | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2016-11-21 05:01:48 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-11-29 10:57:48 -0500 |
commit | 643b8e4d86f8b1a62cf5cd9ea221e9bc0d531d18 (patch) | |
tree | 6711969d45ce0d326661f023074db753657f472d /drivers/acpi/arm64 | |
parent | 618f535a60623c9e7c596b208a57bf094766b9f6 (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.c | 98 |
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 | ||
32 | struct iort_its_msi_chip { | 34 | struct 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 | ||
506 | static 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 | |||
514 | static 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 | |||
526 | static 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 | */ | ||
557 | const 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 | |||
504 | static void __init acpi_iort_register_irq(int hwirq, const char *name, | 602 | static 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) |