diff options
| -rw-r--r-- | drivers/iommu/iommu.c | 200 | ||||
| -rw-r--r-- | include/linux/iommu.h | 140 |
2 files changed, 340 insertions, 0 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 109de67d5d72..f8fe112e507a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
| @@ -2039,3 +2039,203 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids) | |||
| 2039 | return 0; | 2039 | return 0; |
| 2040 | } | 2040 | } |
| 2041 | EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids); | 2041 | EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids); |
| 2042 | |||
| 2043 | /* | ||
| 2044 | * Per device IOMMU features. | ||
| 2045 | */ | ||
| 2046 | bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 2047 | { | ||
| 2048 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2049 | |||
| 2050 | if (ops && ops->dev_has_feat) | ||
| 2051 | return ops->dev_has_feat(dev, feat); | ||
| 2052 | |||
| 2053 | return false; | ||
| 2054 | } | ||
| 2055 | EXPORT_SYMBOL_GPL(iommu_dev_has_feature); | ||
| 2056 | |||
| 2057 | int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 2058 | { | ||
| 2059 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2060 | |||
| 2061 | if (ops && ops->dev_enable_feat) | ||
| 2062 | return ops->dev_enable_feat(dev, feat); | ||
| 2063 | |||
| 2064 | return -ENODEV; | ||
| 2065 | } | ||
| 2066 | EXPORT_SYMBOL_GPL(iommu_dev_enable_feature); | ||
| 2067 | |||
| 2068 | /* | ||
| 2069 | * The device drivers should do the necessary cleanups before calling this. | ||
| 2070 | * For example, before disabling the aux-domain feature, the device driver | ||
| 2071 | * should detach all aux-domains. Otherwise, this will return -EBUSY. | ||
| 2072 | */ | ||
| 2073 | int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 2074 | { | ||
| 2075 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2076 | |||
| 2077 | if (ops && ops->dev_disable_feat) | ||
| 2078 | return ops->dev_disable_feat(dev, feat); | ||
| 2079 | |||
| 2080 | return -EBUSY; | ||
| 2081 | } | ||
| 2082 | EXPORT_SYMBOL_GPL(iommu_dev_disable_feature); | ||
| 2083 | |||
| 2084 | bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat) | ||
| 2085 | { | ||
| 2086 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2087 | |||
| 2088 | if (ops && ops->dev_feat_enabled) | ||
| 2089 | return ops->dev_feat_enabled(dev, feat); | ||
| 2090 | |||
| 2091 | return false; | ||
| 2092 | } | ||
| 2093 | EXPORT_SYMBOL_GPL(iommu_dev_feature_enabled); | ||
| 2094 | |||
| 2095 | /* | ||
| 2096 | * Aux-domain specific attach/detach. | ||
| 2097 | * | ||
| 2098 | * Only works if iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX) returns | ||
| 2099 | * true. Also, as long as domains are attached to a device through this | ||
| 2100 | * interface, any tries to call iommu_attach_device() should fail | ||
| 2101 | * (iommu_detach_device() can't fail, so we fail when trying to re-attach). | ||
| 2102 | * This should make us safe against a device being attached to a guest as a | ||
| 2103 | * whole while there are still pasid users on it (aux and sva). | ||
| 2104 | */ | ||
| 2105 | int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev) | ||
| 2106 | { | ||
| 2107 | int ret = -ENODEV; | ||
| 2108 | |||
| 2109 | if (domain->ops->aux_attach_dev) | ||
| 2110 | ret = domain->ops->aux_attach_dev(domain, dev); | ||
| 2111 | |||
| 2112 | if (!ret) | ||
| 2113 | trace_attach_device_to_domain(dev); | ||
| 2114 | |||
| 2115 | return ret; | ||
| 2116 | } | ||
| 2117 | EXPORT_SYMBOL_GPL(iommu_aux_attach_device); | ||
| 2118 | |||
| 2119 | void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev) | ||
| 2120 | { | ||
| 2121 | if (domain->ops->aux_detach_dev) { | ||
| 2122 | domain->ops->aux_detach_dev(domain, dev); | ||
| 2123 | trace_detach_device_from_domain(dev); | ||
| 2124 | } | ||
| 2125 | } | ||
| 2126 | EXPORT_SYMBOL_GPL(iommu_aux_detach_device); | ||
| 2127 | |||
| 2128 | int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) | ||
| 2129 | { | ||
| 2130 | int ret = -ENODEV; | ||
| 2131 | |||
| 2132 | if (domain->ops->aux_get_pasid) | ||
| 2133 | ret = domain->ops->aux_get_pasid(domain, dev); | ||
| 2134 | |||
| 2135 | return ret; | ||
| 2136 | } | ||
| 2137 | EXPORT_SYMBOL_GPL(iommu_aux_get_pasid); | ||
| 2138 | |||
| 2139 | /** | ||
| 2140 | * iommu_sva_bind_device() - Bind a process address space to a device | ||
| 2141 | * @dev: the device | ||
| 2142 | * @mm: the mm to bind, caller must hold a reference to it | ||
| 2143 | * | ||
| 2144 | * Create a bond between device and address space, allowing the device to access | ||
| 2145 | * the mm using the returned PASID. If a bond already exists between @device and | ||
| 2146 | * @mm, it is returned and an additional reference is taken. Caller must call | ||
| 2147 | * iommu_sva_unbind_device() to release each reference. | ||
| 2148 | * | ||
| 2149 | * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to | ||
| 2150 | * initialize the required SVA features. | ||
| 2151 | * | ||
| 2152 | * On error, returns an ERR_PTR value. | ||
| 2153 | */ | ||
| 2154 | struct iommu_sva * | ||
| 2155 | iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata) | ||
| 2156 | { | ||
| 2157 | struct iommu_group *group; | ||
| 2158 | struct iommu_sva *handle = ERR_PTR(-EINVAL); | ||
| 2159 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2160 | |||
| 2161 | if (!ops || !ops->sva_bind) | ||
| 2162 | return ERR_PTR(-ENODEV); | ||
| 2163 | |||
| 2164 | group = iommu_group_get(dev); | ||
| 2165 | if (!group) | ||
| 2166 | return ERR_PTR(-ENODEV); | ||
| 2167 | |||
| 2168 | /* Ensure device count and domain don't change while we're binding */ | ||
| 2169 | mutex_lock(&group->mutex); | ||
| 2170 | |||
| 2171 | /* | ||
| 2172 | * To keep things simple, SVA currently doesn't support IOMMU groups | ||
| 2173 | * with more than one device. Existing SVA-capable systems are not | ||
| 2174 | * affected by the problems that required IOMMU groups (lack of ACS | ||
| 2175 | * isolation, device ID aliasing and other hardware issues). | ||
| 2176 | */ | ||
| 2177 | if (iommu_group_device_count(group) != 1) | ||
| 2178 | goto out_unlock; | ||
| 2179 | |||
| 2180 | handle = ops->sva_bind(dev, mm, drvdata); | ||
| 2181 | |||
| 2182 | out_unlock: | ||
| 2183 | mutex_unlock(&group->mutex); | ||
| 2184 | iommu_group_put(group); | ||
| 2185 | |||
| 2186 | return handle; | ||
| 2187 | } | ||
| 2188 | EXPORT_SYMBOL_GPL(iommu_sva_bind_device); | ||
| 2189 | |||
| 2190 | /** | ||
| 2191 | * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device | ||
| 2192 | * @handle: the handle returned by iommu_sva_bind_device() | ||
| 2193 | * | ||
| 2194 | * Put reference to a bond between device and address space. The device should | ||
| 2195 | * not be issuing any more transaction for this PASID. All outstanding page | ||
| 2196 | * requests for this PASID must have been flushed to the IOMMU. | ||
| 2197 | * | ||
| 2198 | * Returns 0 on success, or an error value | ||
| 2199 | */ | ||
| 2200 | void iommu_sva_unbind_device(struct iommu_sva *handle) | ||
| 2201 | { | ||
| 2202 | struct iommu_group *group; | ||
| 2203 | struct device *dev = handle->dev; | ||
| 2204 | const struct iommu_ops *ops = dev->bus->iommu_ops; | ||
| 2205 | |||
| 2206 | if (!ops || !ops->sva_unbind) | ||
| 2207 | return; | ||
| 2208 | |||
| 2209 | group = iommu_group_get(dev); | ||
| 2210 | if (!group) | ||
| 2211 | return; | ||
| 2212 | |||
| 2213 | mutex_lock(&group->mutex); | ||
| 2214 | ops->sva_unbind(handle); | ||
| 2215 | mutex_unlock(&group->mutex); | ||
| 2216 | |||
| 2217 | iommu_group_put(group); | ||
| 2218 | } | ||
| 2219 | EXPORT_SYMBOL_GPL(iommu_sva_unbind_device); | ||
| 2220 | |||
| 2221 | int iommu_sva_set_ops(struct iommu_sva *handle, | ||
| 2222 | const struct iommu_sva_ops *sva_ops) | ||
| 2223 | { | ||
| 2224 | if (handle->ops && handle->ops != sva_ops) | ||
| 2225 | return -EEXIST; | ||
| 2226 | |||
| 2227 | handle->ops = sva_ops; | ||
| 2228 | return 0; | ||
| 2229 | } | ||
| 2230 | EXPORT_SYMBOL_GPL(iommu_sva_set_ops); | ||
| 2231 | |||
| 2232 | int iommu_sva_get_pasid(struct iommu_sva *handle) | ||
| 2233 | { | ||
| 2234 | const struct iommu_ops *ops = handle->dev->bus->iommu_ops; | ||
| 2235 | |||
| 2236 | if (!ops || !ops->sva_get_pasid) | ||
| 2237 | return IOMMU_PASID_INVALID; | ||
| 2238 | |||
| 2239 | return ops->sva_get_pasid(handle); | ||
| 2240 | } | ||
| 2241 | EXPORT_SYMBOL_GPL(iommu_sva_get_pasid); | ||
diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 6c1b4c900191..a815cf6f6f47 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h | |||
| @@ -48,6 +48,7 @@ struct bus_type; | |||
| 48 | struct device; | 48 | struct device; |
| 49 | struct iommu_domain; | 49 | struct iommu_domain; |
| 50 | struct notifier_block; | 50 | struct notifier_block; |
| 51 | struct iommu_sva; | ||
| 51 | 52 | ||
| 52 | /* iommu fault flags */ | 53 | /* iommu fault flags */ |
| 53 | #define IOMMU_FAULT_READ 0x0 | 54 | #define IOMMU_FAULT_READ 0x0 |
| @@ -55,6 +56,8 @@ struct notifier_block; | |||
| 55 | 56 | ||
| 56 | typedef int (*iommu_fault_handler_t)(struct iommu_domain *, | 57 | typedef int (*iommu_fault_handler_t)(struct iommu_domain *, |
| 57 | struct device *, unsigned long, int, void *); | 58 | struct device *, unsigned long, int, void *); |
| 59 | typedef int (*iommu_mm_exit_handler_t)(struct device *dev, struct iommu_sva *, | ||
| 60 | void *); | ||
| 58 | 61 | ||
| 59 | struct iommu_domain_geometry { | 62 | struct iommu_domain_geometry { |
| 60 | dma_addr_t aperture_start; /* First address that can be mapped */ | 63 | dma_addr_t aperture_start; /* First address that can be mapped */ |
| @@ -156,6 +159,33 @@ struct iommu_resv_region { | |||
| 156 | enum iommu_resv_type type; | 159 | enum iommu_resv_type type; |
| 157 | }; | 160 | }; |
| 158 | 161 | ||
| 162 | /* Per device IOMMU features */ | ||
| 163 | enum iommu_dev_features { | ||
| 164 | IOMMU_DEV_FEAT_AUX, /* Aux-domain feature */ | ||
| 165 | IOMMU_DEV_FEAT_SVA, /* Shared Virtual Addresses */ | ||
| 166 | }; | ||
| 167 | |||
| 168 | #define IOMMU_PASID_INVALID (-1U) | ||
| 169 | |||
| 170 | /** | ||
| 171 | * struct iommu_sva_ops - device driver callbacks for an SVA context | ||
| 172 | * | ||
| 173 | * @mm_exit: called when the mm is about to be torn down by exit_mmap. After | ||
| 174 | * @mm_exit returns, the device must not issue any more transaction | ||
| 175 | * with the PASID given as argument. | ||
| 176 | * | ||
| 177 | * The @mm_exit handler is allowed to sleep. Be careful about the | ||
| 178 | * locks taken in @mm_exit, because they might lead to deadlocks if | ||
| 179 | * they are also held when dropping references to the mm. Consider the | ||
| 180 | * following call chain: | ||
| 181 | * mutex_lock(A); mmput(mm) -> exit_mm() -> @mm_exit() -> mutex_lock(A) | ||
| 182 | * Using mmput_async() prevents this scenario. | ||
| 183 | * | ||
| 184 | */ | ||
| 185 | struct iommu_sva_ops { | ||
| 186 | iommu_mm_exit_handler_t mm_exit; | ||
| 187 | }; | ||
| 188 | |||
| 159 | #ifdef CONFIG_IOMMU_API | 189 | #ifdef CONFIG_IOMMU_API |
| 160 | 190 | ||
| 161 | /** | 191 | /** |
| @@ -186,6 +216,14 @@ struct iommu_resv_region { | |||
| 186 | * @of_xlate: add OF master IDs to iommu grouping | 216 | * @of_xlate: add OF master IDs to iommu grouping |
| 187 | * @is_attach_deferred: Check if domain attach should be deferred from iommu | 217 | * @is_attach_deferred: Check if domain attach should be deferred from iommu |
| 188 | * driver init to device driver init (default no) | 218 | * driver init to device driver init (default no) |
| 219 | * @dev_has/enable/disable_feat: per device entries to check/enable/disable | ||
| 220 | * iommu specific features. | ||
| 221 | * @dev_feat_enabled: check enabled feature | ||
| 222 | * @aux_attach/detach_dev: aux-domain specific attach/detach entries. | ||
| 223 | * @aux_get_pasid: get the pasid given an aux-domain | ||
| 224 | * @sva_bind: Bind process address space to device | ||
| 225 | * @sva_unbind: Unbind process address space from device | ||
| 226 | * @sva_get_pasid: Get PASID associated to a SVA handle | ||
| 189 | * @pgsize_bitmap: bitmap of all possible supported page sizes | 227 | * @pgsize_bitmap: bitmap of all possible supported page sizes |
| 190 | */ | 228 | */ |
| 191 | struct iommu_ops { | 229 | struct iommu_ops { |
| @@ -230,6 +268,22 @@ struct iommu_ops { | |||
| 230 | int (*of_xlate)(struct device *dev, struct of_phandle_args *args); | 268 | int (*of_xlate)(struct device *dev, struct of_phandle_args *args); |
| 231 | bool (*is_attach_deferred)(struct iommu_domain *domain, struct device *dev); | 269 | bool (*is_attach_deferred)(struct iommu_domain *domain, struct device *dev); |
| 232 | 270 | ||
| 271 | /* Per device IOMMU features */ | ||
| 272 | bool (*dev_has_feat)(struct device *dev, enum iommu_dev_features f); | ||
| 273 | bool (*dev_feat_enabled)(struct device *dev, enum iommu_dev_features f); | ||
| 274 | int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f); | ||
| 275 | int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f); | ||
| 276 | |||
| 277 | /* Aux-domain specific attach/detach entries */ | ||
| 278 | int (*aux_attach_dev)(struct iommu_domain *domain, struct device *dev); | ||
| 279 | void (*aux_detach_dev)(struct iommu_domain *domain, struct device *dev); | ||
| 280 | int (*aux_get_pasid)(struct iommu_domain *domain, struct device *dev); | ||
| 281 | |||
| 282 | struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm, | ||
| 283 | void *drvdata); | ||
| 284 | void (*sva_unbind)(struct iommu_sva *handle); | ||
| 285 | int (*sva_get_pasid)(struct iommu_sva *handle); | ||
| 286 | |||
| 233 | unsigned long pgsize_bitmap; | 287 | unsigned long pgsize_bitmap; |
| 234 | }; | 288 | }; |
| 235 | 289 | ||
| @@ -400,6 +454,14 @@ struct iommu_fwspec { | |||
| 400 | /* ATS is supported */ | 454 | /* ATS is supported */ |
| 401 | #define IOMMU_FWSPEC_PCI_RC_ATS (1 << 0) | 455 | #define IOMMU_FWSPEC_PCI_RC_ATS (1 << 0) |
| 402 | 456 | ||
| 457 | /** | ||
| 458 | * struct iommu_sva - handle to a device-mm bond | ||
| 459 | */ | ||
| 460 | struct iommu_sva { | ||
| 461 | struct device *dev; | ||
| 462 | const struct iommu_sva_ops *ops; | ||
| 463 | }; | ||
| 464 | |||
| 403 | int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode, | 465 | int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode, |
| 404 | const struct iommu_ops *ops); | 466 | const struct iommu_ops *ops); |
| 405 | void iommu_fwspec_free(struct device *dev); | 467 | void iommu_fwspec_free(struct device *dev); |
| @@ -420,6 +482,22 @@ static inline void dev_iommu_fwspec_set(struct device *dev, | |||
| 420 | int iommu_probe_device(struct device *dev); | 482 | int iommu_probe_device(struct device *dev); |
| 421 | void iommu_release_device(struct device *dev); | 483 | void iommu_release_device(struct device *dev); |
| 422 | 484 | ||
| 485 | bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features f); | ||
| 486 | int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f); | ||
| 487 | int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f); | ||
| 488 | bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f); | ||
| 489 | int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev); | ||
| 490 | void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev); | ||
| 491 | int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev); | ||
| 492 | |||
| 493 | struct iommu_sva *iommu_sva_bind_device(struct device *dev, | ||
| 494 | struct mm_struct *mm, | ||
| 495 | void *drvdata); | ||
| 496 | void iommu_sva_unbind_device(struct iommu_sva *handle); | ||
| 497 | int iommu_sva_set_ops(struct iommu_sva *handle, | ||
| 498 | const struct iommu_sva_ops *ops); | ||
| 499 | int iommu_sva_get_pasid(struct iommu_sva *handle); | ||
| 500 | |||
| 423 | #else /* CONFIG_IOMMU_API */ | 501 | #else /* CONFIG_IOMMU_API */ |
| 424 | 502 | ||
| 425 | struct iommu_ops {}; | 503 | struct iommu_ops {}; |
| @@ -704,6 +782,68 @@ const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode) | |||
| 704 | return NULL; | 782 | return NULL; |
| 705 | } | 783 | } |
| 706 | 784 | ||
| 785 | static inline bool | ||
| 786 | iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 787 | { | ||
| 788 | return false; | ||
| 789 | } | ||
| 790 | |||
| 791 | static inline bool | ||
| 792 | iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat) | ||
| 793 | { | ||
| 794 | return false; | ||
| 795 | } | ||
| 796 | |||
| 797 | static inline int | ||
| 798 | iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 799 | { | ||
| 800 | return -ENODEV; | ||
| 801 | } | ||
| 802 | |||
| 803 | static inline int | ||
| 804 | iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat) | ||
| 805 | { | ||
| 806 | return -ENODEV; | ||
| 807 | } | ||
| 808 | |||
| 809 | static inline int | ||
| 810 | iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev) | ||
| 811 | { | ||
| 812 | return -ENODEV; | ||
| 813 | } | ||
| 814 | |||
| 815 | static inline void | ||
| 816 | iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev) | ||
| 817 | { | ||
| 818 | } | ||
| 819 | |||
| 820 | static inline int | ||
| 821 | iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) | ||
| 822 | { | ||
| 823 | return -ENODEV; | ||
| 824 | } | ||
| 825 | |||
| 826 | static inline struct iommu_sva * | ||
| 827 | iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata) | ||
| 828 | { | ||
| 829 | return NULL; | ||
| 830 | } | ||
| 831 | |||
| 832 | static inline void iommu_sva_unbind_device(struct iommu_sva *handle) | ||
| 833 | { | ||
| 834 | } | ||
| 835 | |||
| 836 | static inline int iommu_sva_set_ops(struct iommu_sva *handle, | ||
| 837 | const struct iommu_sva_ops *ops) | ||
| 838 | { | ||
| 839 | return -EINVAL; | ||
| 840 | } | ||
| 841 | |||
| 842 | static inline int iommu_sva_get_pasid(struct iommu_sva *handle) | ||
| 843 | { | ||
| 844 | return IOMMU_PASID_INVALID; | ||
| 845 | } | ||
| 846 | |||
| 707 | #endif /* CONFIG_IOMMU_API */ | 847 | #endif /* CONFIG_IOMMU_API */ |
| 708 | 848 | ||
| 709 | #ifdef CONFIG_IOMMU_DEBUGFS | 849 | #ifdef CONFIG_IOMMU_DEBUGFS |
