diff options
| -rw-r--r-- | drivers/acpi/arm64/iort.c | 238 |
1 files changed, 120 insertions, 118 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 9058cb084b91..b5390b4c9ade 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c | |||
| @@ -753,31 +753,6 @@ static int __maybe_unused __get_pci_rid(struct pci_dev *pdev, u16 alias, | |||
| 753 | return 0; | 753 | return 0; |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | static int arm_smmu_iort_xlate(struct device *dev, u32 streamid, | ||
| 757 | struct fwnode_handle *fwnode, | ||
| 758 | const struct iommu_ops *ops) | ||
| 759 | { | ||
| 760 | int ret = iommu_fwspec_init(dev, fwnode, ops); | ||
| 761 | |||
| 762 | if (!ret) | ||
| 763 | ret = iommu_fwspec_add_ids(dev, &streamid, 1); | ||
| 764 | |||
| 765 | return ret; | ||
| 766 | } | ||
| 767 | |||
| 768 | static inline bool iort_iommu_driver_enabled(u8 type) | ||
| 769 | { | ||
| 770 | switch (type) { | ||
| 771 | case ACPI_IORT_NODE_SMMU_V3: | ||
| 772 | return IS_BUILTIN(CONFIG_ARM_SMMU_V3); | ||
| 773 | case ACPI_IORT_NODE_SMMU: | ||
| 774 | return IS_BUILTIN(CONFIG_ARM_SMMU); | ||
| 775 | default: | ||
| 776 | pr_warn("IORT node type %u does not describe an SMMU\n", type); | ||
| 777 | return false; | ||
| 778 | } | ||
| 779 | } | ||
| 780 | |||
| 781 | #ifdef CONFIG_IOMMU_API | 756 | #ifdef CONFIG_IOMMU_API |
| 782 | static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev) | 757 | static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev) |
| 783 | { | 758 | { |
| @@ -878,15 +853,39 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head) | |||
| 878 | 853 | ||
| 879 | return (resv == its->its_count) ? resv : -ENODEV; | 854 | return (resv == its->its_count) ? resv : -ENODEV; |
| 880 | } | 855 | } |
| 881 | #else | 856 | |
| 882 | static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev) | 857 | static inline bool iort_iommu_driver_enabled(u8 type) |
| 883 | { return NULL; } | 858 | { |
| 884 | static inline int iort_add_device_replay(const struct iommu_ops *ops, | 859 | switch (type) { |
| 885 | struct device *dev) | 860 | case ACPI_IORT_NODE_SMMU_V3: |
| 886 | { return 0; } | 861 | return IS_BUILTIN(CONFIG_ARM_SMMU_V3); |
| 887 | int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head) | 862 | case ACPI_IORT_NODE_SMMU: |
| 888 | { return 0; } | 863 | return IS_BUILTIN(CONFIG_ARM_SMMU); |
| 889 | #endif | 864 | default: |
| 865 | pr_warn("IORT node type %u does not describe an SMMU\n", type); | ||
| 866 | return false; | ||
| 867 | } | ||
| 868 | } | ||
| 869 | |||
| 870 | static int arm_smmu_iort_xlate(struct device *dev, u32 streamid, | ||
| 871 | struct fwnode_handle *fwnode, | ||
| 872 | const struct iommu_ops *ops) | ||
| 873 | { | ||
| 874 | int ret = iommu_fwspec_init(dev, fwnode, ops); | ||
| 875 | |||
| 876 | if (!ret) | ||
| 877 | ret = iommu_fwspec_add_ids(dev, &streamid, 1); | ||
| 878 | |||
| 879 | return ret; | ||
| 880 | } | ||
| 881 | |||
| 882 | static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node) | ||
| 883 | { | ||
| 884 | struct acpi_iort_root_complex *pci_rc; | ||
| 885 | |||
| 886 | pci_rc = (struct acpi_iort_root_complex *)node->node_data; | ||
| 887 | return pci_rc->ats_attribute & ACPI_IORT_ATS_SUPPORTED; | ||
| 888 | } | ||
| 890 | 889 | ||
| 891 | static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, | 890 | static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, |
| 892 | u32 streamid) | 891 | u32 streamid) |
| @@ -933,6 +932,93 @@ static int iort_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) | |||
| 933 | return iort_iommu_xlate(info->dev, parent, streamid); | 932 | return iort_iommu_xlate(info->dev, parent, streamid); |
| 934 | } | 933 | } |
| 935 | 934 | ||
| 935 | /** | ||
| 936 | * iort_iommu_configure - Set-up IOMMU configuration for a device. | ||
| 937 | * | ||
| 938 | * @dev: device to configure | ||
| 939 | * | ||
| 940 | * Returns: iommu_ops pointer on configuration success | ||
| 941 | * NULL on configuration failure | ||
| 942 | */ | ||
| 943 | const struct iommu_ops *iort_iommu_configure(struct device *dev) | ||
| 944 | { | ||
| 945 | struct acpi_iort_node *node, *parent; | ||
| 946 | const struct iommu_ops *ops; | ||
| 947 | u32 streamid = 0; | ||
| 948 | int err = -ENODEV; | ||
| 949 | |||
| 950 | /* | ||
| 951 | * If we already translated the fwspec there | ||
| 952 | * is nothing left to do, return the iommu_ops. | ||
| 953 | */ | ||
| 954 | ops = iort_fwspec_iommu_ops(dev); | ||
| 955 | if (ops) | ||
| 956 | return ops; | ||
| 957 | |||
| 958 | if (dev_is_pci(dev)) { | ||
| 959 | struct pci_bus *bus = to_pci_dev(dev)->bus; | ||
| 960 | struct iort_pci_alias_info info = { .dev = dev }; | ||
| 961 | |||
| 962 | node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, | ||
| 963 | iort_match_node_callback, &bus->dev); | ||
| 964 | if (!node) | ||
| 965 | return NULL; | ||
| 966 | |||
| 967 | info.node = node; | ||
| 968 | err = pci_for_each_dma_alias(to_pci_dev(dev), | ||
| 969 | iort_pci_iommu_init, &info); | ||
| 970 | |||
| 971 | if (!err && iort_pci_rc_supports_ats(node)) | ||
| 972 | dev->iommu_fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS; | ||
| 973 | } else { | ||
| 974 | int i = 0; | ||
| 975 | |||
| 976 | node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, | ||
| 977 | iort_match_node_callback, dev); | ||
| 978 | if (!node) | ||
| 979 | return NULL; | ||
| 980 | |||
| 981 | do { | ||
| 982 | parent = iort_node_map_platform_id(node, &streamid, | ||
| 983 | IORT_IOMMU_TYPE, | ||
| 984 | i++); | ||
| 985 | |||
| 986 | if (parent) | ||
| 987 | err = iort_iommu_xlate(dev, parent, streamid); | ||
| 988 | } while (parent && !err); | ||
| 989 | } | ||
| 990 | |||
| 991 | /* | ||
| 992 | * If we have reason to believe the IOMMU driver missed the initial | ||
| 993 | * add_device callback for dev, replay it to get things in order. | ||
| 994 | */ | ||
| 995 | if (!err) { | ||
| 996 | ops = iort_fwspec_iommu_ops(dev); | ||
| 997 | err = iort_add_device_replay(ops, dev); | ||
| 998 | } | ||
| 999 | |||
| 1000 | /* Ignore all other errors apart from EPROBE_DEFER */ | ||
| 1001 | if (err == -EPROBE_DEFER) { | ||
| 1002 | ops = ERR_PTR(err); | ||
| 1003 | } else if (err) { | ||
| 1004 | dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); | ||
| 1005 | ops = NULL; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | return ops; | ||
| 1009 | } | ||
| 1010 | #else | ||
| 1011 | static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev) | ||
| 1012 | { return NULL; } | ||
| 1013 | static inline int iort_add_device_replay(const struct iommu_ops *ops, | ||
| 1014 | struct device *dev) | ||
| 1015 | { return 0; } | ||
| 1016 | int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head) | ||
| 1017 | { return 0; } | ||
| 1018 | const struct iommu_ops *iort_iommu_configure(struct device *dev) | ||
| 1019 | { return NULL; } | ||
| 1020 | #endif | ||
| 1021 | |||
| 936 | static int nc_dma_get_range(struct device *dev, u64 *size) | 1022 | static int nc_dma_get_range(struct device *dev, u64 *size) |
| 937 | { | 1023 | { |
| 938 | struct acpi_iort_node *node; | 1024 | struct acpi_iort_node *node; |
| @@ -1031,90 +1117,6 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) | |||
| 1031 | dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset); | 1117 | dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset); |
| 1032 | } | 1118 | } |
| 1033 | 1119 | ||
| 1034 | static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node) | ||
| 1035 | { | ||
| 1036 | struct acpi_iort_root_complex *pci_rc; | ||
| 1037 | |||
| 1038 | pci_rc = (struct acpi_iort_root_complex *)node->node_data; | ||
| 1039 | return pci_rc->ats_attribute & ACPI_IORT_ATS_SUPPORTED; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /** | ||
| 1043 | * iort_iommu_configure - Set-up IOMMU configuration for a device. | ||
| 1044 | * | ||
| 1045 | * @dev: device to configure | ||
| 1046 | * | ||
| 1047 | * Returns: iommu_ops pointer on configuration success | ||
| 1048 | * NULL on configuration failure | ||
| 1049 | */ | ||
| 1050 | const struct iommu_ops *iort_iommu_configure(struct device *dev) | ||
| 1051 | { | ||
| 1052 | struct acpi_iort_node *node, *parent; | ||
| 1053 | const struct iommu_ops *ops; | ||
| 1054 | u32 streamid = 0; | ||
| 1055 | int err = -ENODEV; | ||
| 1056 | |||
| 1057 | /* | ||
| 1058 | * If we already translated the fwspec there | ||
| 1059 | * is nothing left to do, return the iommu_ops. | ||
| 1060 | */ | ||
| 1061 | ops = iort_fwspec_iommu_ops(dev); | ||
| 1062 | if (ops) | ||
| 1063 | return ops; | ||
| 1064 | |||
| 1065 | if (dev_is_pci(dev)) { | ||
| 1066 | struct pci_bus *bus = to_pci_dev(dev)->bus; | ||
| 1067 | struct iort_pci_alias_info info = { .dev = dev }; | ||
| 1068 | |||
| 1069 | node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, | ||
| 1070 | iort_match_node_callback, &bus->dev); | ||
| 1071 | if (!node) | ||
| 1072 | return NULL; | ||
| 1073 | |||
| 1074 | info.node = node; | ||
| 1075 | err = pci_for_each_dma_alias(to_pci_dev(dev), | ||
| 1076 | iort_pci_iommu_init, &info); | ||
| 1077 | |||
| 1078 | if (!err && iort_pci_rc_supports_ats(node)) | ||
| 1079 | dev->iommu_fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS; | ||
| 1080 | } else { | ||
| 1081 | int i = 0; | ||
| 1082 | |||
| 1083 | node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, | ||
| 1084 | iort_match_node_callback, dev); | ||
| 1085 | if (!node) | ||
| 1086 | return NULL; | ||
| 1087 | |||
| 1088 | do { | ||
| 1089 | parent = iort_node_map_platform_id(node, &streamid, | ||
| 1090 | IORT_IOMMU_TYPE, | ||
| 1091 | i++); | ||
| 1092 | |||
| 1093 | if (parent) | ||
| 1094 | err = iort_iommu_xlate(dev, parent, streamid); | ||
| 1095 | } while (parent && !err); | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | /* | ||
| 1099 | * If we have reason to believe the IOMMU driver missed the initial | ||
| 1100 | * add_device callback for dev, replay it to get things in order. | ||
| 1101 | */ | ||
| 1102 | if (!err) { | ||
| 1103 | ops = iort_fwspec_iommu_ops(dev); | ||
| 1104 | err = iort_add_device_replay(ops, dev); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | /* Ignore all other errors apart from EPROBE_DEFER */ | ||
| 1108 | if (err == -EPROBE_DEFER) { | ||
| 1109 | ops = ERR_PTR(err); | ||
| 1110 | } else if (err) { | ||
| 1111 | dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); | ||
| 1112 | ops = NULL; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | return ops; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | static void __init acpi_iort_register_irq(int hwirq, const char *name, | 1120 | static void __init acpi_iort_register_irq(int hwirq, const char *name, |
| 1119 | int trigger, | 1121 | int trigger, |
| 1120 | struct resource *res) | 1122 | struct resource *res) |
