of_iommu: add support for "iommu-ranges"
Subsystems (12)
v7 cover of_iommu: add support for "iommu-ranges"
The series adds support for recently introduced property "iommu-ranges". It adds the required checks to error out for cases which are not following the schema definition.
Iommu-ranges was defined in schema with this PR
https://github.com/devicetree-org/dt-schema/pull/207
The patch series is being posted as revision v6, since the patches were initially part of the media series [1]. The patches are moved out to get review comments from iommu reviewers, which was otherwise looking as a media series. Happy to move this back to media series if anyone have any concerns.
[1]
https://lore.kernel.org/linux-media/20260926-vpu_iommu_iova_handling-v5-0-0322ca5dc10c@oss.qualcomm.com/
---
Changes in v7:
- Move the "iommu-addresses" behaviour change ("reg" required, non-direct
mappings rejected) into its own patch before the iommu-ranges patch (Bryan)
- Make OF_IOMMU depend on OF_ADDRESS and drop the #if guards (Rob)
- Use resource_size_t for the size in vfio_find_dma() (Sashiko)
- End the derived trailing reserved region at PHYS_ADDR_MAX - 1 to avoid
overflow (Sashiko)
- Add a dma-iommu fix to protect the IOVA rbtree anchor on 32-bit with
64-bit dma_addr_t (Sashiko)
- Use the "iommu/of:" prefix and fix the subject case
- Link to v6: https://lore.kernel.org/r/[email protected]
Changes in v6:
- Addressed sashiko comments.
- Addressed comment from Bryan.
- Link to v5: https://lore.kernel.org/all/20260926-vpu_iommu_iova_handling-v5-4-0322ca5dc10c@oss.qualcomm.com/
---
Vikash Garodia (5):
iommu/dma: Keep reserved regions below the IOVA rbtree anchor
iommu: Use resource_size_t for reserved region length iommu/of: Make OF_IOMMU depend on OF_ADDRESS iommu/of: Require reg for iommu-addresses iommu/of: Add support for "iommu-ranges" on a device node
drivers/iommu/Kconfig | 2 +- drivers/iommu/amd/iommu.c | 2 +- drivers/iommu/dma-iommu.c | 32 +++++---- drivers/iommu/intel/iommu.c | 2 +- drivers/iommu/iommu.c | 2 +- drivers/iommu/of_iommu.c | 147 ++++++++++++++++++++++++++++++++++------ drivers/iommu/virtio-iommu.c | 2 +- drivers/of/address.c | 2 +- drivers/vfio/vfio_iommu_type1.c | 2 +- include/linux/iommu.h | 4 +- include/linux/of_address.h | 2 +- 11 files changed, 155 insertions(+), 44 deletions(-)
---
base-commit: 2637bdec0535a2044cd830eba9a79363651d9043
change-id: 20261103-add_iommu_ranges-549cf3fb0867
Best regards,
Signature · 1 line
Vikash Garodia <[email protected]>
PATCH v7 1/5 iommu/dma: Keep reserved regions below the IOVA rbtree anchor
The IOVA allocator tracks address ranges by page frame number (PFN). The highest node in its rbtree is a fixed anchor at PFN ~0UL, which is embedded in the DMA cookie. dma-iommu converts reserved regions to PFNs with iova_pfn(), which returns unsigned long. On x86-32 with PAE, addresses are 64-bit but unsigned long is 32-bit, so the upper bits of the PFN are lost.
A reserved region that ends at the top of the address space then gets the anchor's PFN. reserve_iova() merges it into the anchor and lowers the anchor's pfn_lo. At teardown, free_iova_mem() no longer recognises the anchor and frees it to iova_cache, which corrupts the slab. PCI host bridge windows above 16TiB and the reservation after the last PCI DMA window hit the same problem.
Compute the PFNs in u64. Skip ranges that start above the PFN space and clamp the end one PFN below the anchor. The allocator never hands out those IOVAs, so nothing is lost. On 64-bit, PFNs never reach ~0UL, so nothing changes there.
--- drivers/iommu/dma-iommu.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
drivers/iommu/dma-iommu.c +20 -12
@@ -505,21 +505,34 @@ static int iommu_dma_ranges_sort(void *priv, const struct list_head *a,return res_a->res->start > res_b->res->start; } +/* +* IOVA PFNs are unsigned long, and ~0UL is the rbtree anchor. On 32-bit +* with a 64-bit dma_addr_t, iova_pfn() would truncate the range. Compute +* the PFNs in u64 instead, skip a range that starts beyond the PFN space +* and clamp its end below the anchor. Such IOVAs cannot be allocated. +*/ +static void iova_reserve_range (struct iova_domain *iovad,u64 start,u64 end) +{ +u64 lo = start >>iova_shift (iovad); +u64 hi = end >>iova_shift (iovad); + +if (lo <ULONG_MAX ) +reserve_iova (iovad, lo,min (hi,ULONG_MAX -1 )); +} +static int iova_reserve_pci_windows (struct pci_dev *dev,struct iova_domain *iovad) {struct pci_host_bridge *bridge =pci_find_host_bridge (dev->bus);struct resource_entry *window; -unsigned long lo, hi;phys_addr_t start =0 , end;resource_list_for_each_entry (window, &bridge->windows) {if (resource_type (window->res) !=IORESOURCE_MEM )continue ; - lo =iova_pfn (iovad, window->res->start - window->offset); - hi =iova_pfn (iovad, window->res->end - window->offset); -reserve_iova (iovad, lo, hi); +iova_reserve_range (iovad, window->res->start - window->offset, + window->res->end - window->offset); }/* Get reserved DMA windows from host bridge */
@@ -528,9 +541,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev, end = window->res->start - window->offset; resv_iova:if (end > start) { - lo =iova_pfn (iovad, start); - hi =iova_pfn (iovad, end); -reserve_iova (iovad, lo, hi); +iova_reserve_range (iovad, start, end); }else if (end < start) {/* DMA ranges should be non-overlapping */ dev_err(&dev->dev,
@@ -568,15 +579,12 @@ static int iova_reserve_iommu_regions(struct device *dev,iommu_get_resv_regions (dev, &resv_regions);list_for_each_entry (region, &resv_regions, list) { -unsigned long lo, hi; -/* We ARE the software that manages these! */ if (region->type ==IOMMU_RESV_SW_MSI )continue ; - lo =iova_pfn (iovad, region->start); - hi =iova_pfn (iovad, region->start + region->length -1 ); -reserve_iova (iovad, lo, hi); +iova_reserve_range (iovad, region->start, + region->start + region->length -1 );if (region->type ==IOMMU_RESV_MSI ) ret = cookie_init_hw_msi_region(cookie, region->start,
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v7 1/5] iommu/dma: Keep reserved regions below the IOVA rbtree anchor
Sashiko has reviewed this patch and found no issues.
Quoted 17 lines
The IOVA allocator tracks address ranges by page frame number (PFN). The highest node in its rbtree is a fixed anchor at PFN ~0UL, which is embedded in the DMA cookie. dma-iommu converts reserved regions to PFNs with
iova_pfn(), which returns unsigned long. On x86-32 with PAE, addresses are 64-bit but unsigned long is 32-bit, so the upper bits of the PFN are lost.
A reserved region that ends at the top of the address space then gets the anchor's PFN.reserve_iova()merges it into the anchor and lowers the anchor'spfn_lo. At teardown,free_iova_mem()no longer recognises the anchor and frees it toiova_cache, which corrupts the slab. PCI host bridge windows above 16TiB and the reservation after the last PCI DMA window hit the same problem.
Compute the PFNs in u64. Skip ranges that start above the PFN space and clamp the end one PFN below the anchor. The allocator never hands out those IOVAs, so nothing is lost. On 64-bit, PFNs never reach ~0UL, so nothing changes there.
Quoted 9 lines
Fixes fade1ec055dc ("iommu/dma: Avoid PCI host bridge windows")Fixes 7c1b058c8b5a ("iommu/dma: Handle IOMMU API reserved regions")Fixes aadad097cd46 ("iommu/dma: Reserve IOVA for PCIe inaccessible DMA address")Reported-by Sashiko <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
PATCH v7 2/5 iommu: Use resource_size_t for reserved region length
In reply to Vikash GarodiaOn 32-bit systems with LPAE, physical addresses are 64-bit. A reserved region can be larger than 4GiB, but its length is stored as size_t, which is only 32-bit there. The length gets truncated.
Use resource_size_t for the length so it matches the width of phys_addr_t and holds the full size of the region.
--- drivers/iommu/amd/iommu.c | 2 +- drivers/iommu/intel/iommu.c | 2 +- drivers/iommu/iommu.c | 2 +- drivers/iommu/of_iommu.c | 4 ++-- drivers/iommu/virtio-iommu.c | 2 +- drivers/of/address.c | 2 +- drivers/vfio/vfio_iommu_type1.c | 2 +- include/linux/iommu.h | 4 ++-- include/linux/of_address.h | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-)
drivers/iommu/amd/iommu.c +1 -1
@@ -3327,7 +3327,7 @@ static void amd_iommu_get_resv_regions(struct device *dev,list_for_each_entry (entry, &pci_seg->unity_map, list) {int type, prot =0 ; -size_t length; +resource_size_t length;if (devid < entry->devid_start || devid > entry->devid_end)continue ;
drivers/iommu/intel/iommu.c +1 -1
@@ -3535,7 +3535,7 @@ static void intel_iommu_get_resv_regions(struct device *device, i, i_dev) {struct iommu_resv_region *resv;enum iommu_resv_type type; -size_t length; +resource_size_t length;if (i_dev != device && !is_downstream_to_pci_bridge (device, i_dev))
drivers/iommu/iommu.c +1 -1
@@ -3010,7 +3010,7 @@ void iommu_put_resv_regions(struct device *dev, struct list_head *list)EXPORT_SYMBOL (iommu_put_resv_regions);struct iommu_resv_region *iommu_alloc_resv_region (phys_addr_t start, -size_t length,int prot, +resource_size_t length,int prot,enum iommu_resv_type type,gfp_t gfp) {
drivers/iommu/of_iommu.c +2 -2
@@ -170,7 +170,7 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,static enum iommu_resv_type __maybe_unused iommu_resv_region_get_type (struct device *dev,struct resource *phys, -phys_addr_t start,size_t length) +phys_addr_t start,resource_size_t length) {phys_addr_t end = start + length -1 ;
@@ -246,7 +246,7 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)struct iommu_resv_region *region;enum iommu_resv_type type;phys_addr_t iova; -size_t length; +resource_size_t length;if (of_dma_is_coherent (dev->of_node)) prot |=IOMMU_CACHE ;
drivers/iommu/virtio-iommu.c +1 -1
@@ -483,7 +483,7 @@ static int viommu_add_resv_mem(struct viommu_endpoint *vdev, struct virtio_iommu_probe_resv_mem *mem, size_t len) { - size_t size; +resource_size_t size;u64 start64, end64;phys_addr_t start, end;struct iommu_resv_region *region =NULL , *next;
drivers/of/address.c +1 -1
@@ -655,7 +655,7 @@ EXPORT_SYMBOL(of_translate_dma_address);* Returns a pointer to the cell immediately following the translated DMA region. */ const __be32 *of_translate_dma_region (struct device_node *dev,const __be32 *prop, -phys_addr_t *start,size_t *length) +phys_addr_t *start,resource_size_t *length) { struct device_node *parent __free(device_node) = __of_get_dma_parent(dev);u64 address, size;
drivers/vfio/vfio_iommu_type1.c +1 -1
@@ -164,7 +164,7 @@ vfio_iommu_find_iommu_group(struct vfio_iommu *iommu,*/ static struct vfio_dma *vfio_find_dma (struct vfio_iommu *iommu, -dma_addr_t start,size_t size) +dma_addr_t start,resource_size_t size) {struct rb_node *node = iommu->dma_list.rb_node;
include/linux/iommu.h +2 -2
@@ -306,7 +306,7 @@ enum iommu_resv_type {struct iommu_resv_region {struct list_head list;phys_addr_t start; -size_t length; +resource_size_t length;int prot;enum iommu_resv_type type;void (*free)(struct device *dev,struct iommu_resv_region *region);
@@ -968,7 +968,7 @@ extern void iommu_set_default_passthrough(bool cmd_line);extern void iommu_set_default_translated (bool cmd_line);extern bool iommu_default_passthrough (void );extern struct iommu_resv_region * -iommu_alloc_resv_region (phys_addr_t start,size_t length,int prot, +iommu_alloc_resv_region (phys_addr_t start,resource_size_t length,int prot,enum iommu_resv_type type,gfp_t gfp);extern int iommu_get_group_resv_regions (struct iommu_group *group,struct list_head *head);
include/linux/of_address.h +1 -1
@@ -56,7 +56,7 @@ static inline int of_range_count(const struct of_range_parser *parser)extern u64 of_translate_dma_address (struct device_node *dev,const __be32 *in_addr);extern const __be32 *of_translate_dma_region (struct device_node *dev,const __be32 *addr, -phys_addr_t *start,size_t *length); +phys_addr_t *start,resource_size_t *length);#ifdef CONFIG_OF_ADDRESS extern u64 of_translate_address (struct device_node *np,const __be32 *addr);
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v7 2/5] iommu: Use resource_size_t for reserved region length
Sashiko has reviewed this patch and found no issues.
Quoted 6 lines
On 32-bit systems with LPAE, physical addresses are 64-bit. A reserved region can be larger than 4GiB, but its length is stored as
size_t, which is only 32-bit there. The length gets truncated.
Useresource_size_tfor the length so it matches the width ofphys_addr_tand holds the full size of the region.
Quoted 7 lines
Fixes 2b20cbba3390 ("iommu: iommu_alloc_resv_region")Reported-by Sashiko <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v7 2/5] iommu: Use resource_size_t for reserved region length
In reply to Vikash GarodiaQuoted 13 lines · Vikash Garodia
On 32-bit systems with LPAE, physical addresses are 64-bit. A reserved region can be larger than 4GiB, but its length is stored as
size_t, which is only 32-bit there. The length gets truncated.
Useresource_size_tfor the length so it matches the width ofphys_addr_tand holds the full size of the region.Fixes 2b20cbba3390 ("iommu: iommu_alloc_resv_region")Reported-by Sashiko <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Quoted 12 lines
--- drivers/iommu/amd/iommu.c | 2 +- drivers/iommu/intel/iommu.c | 2 +- drivers/iommu/iommu.c | 2 +- drivers/iommu/of_iommu.c | 4 ++-- drivers/iommu/virtio-iommu.c | 2 +- drivers/of/address.c | 2 +- drivers/vfio/vfio_iommu_type1.c | 2 +- include/linux/iommu.h | 4 ++-- include/linux/of_address.h | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-)
PATCH v7 3/5 iommu/of: Make OF_IOMMU depend on OF_ADDRESS
In reply to Vikash GarodiaThe OF_IOMMU code relies on OF address parsing helpers, but the dependency on OF_ADDRESS is not expressed in Kconfig. As a result, of_iommu.c contains CONFIG_OF_ADDRESS guards and a __maybe_unused annotation to handle configurations where OF_ADDRESS is disabled.
Make OF_IOMMU depend on OF_ADDRESS and remove the now unnecessary preprocessor guards and __maybe_unused annotation.
The only architecture supporting OF without OF_ADDRESS is SPARC, which does not use OF_IOMMU, so no functional change is intended.
--- drivers/iommu/Kconfig | 2 +- drivers/iommu/of_iommu.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-)
drivers/iommu/Kconfig +1 -1
@@ -147,7 +147,7 @@ endchoice config OF_IOMMU def_bool y - depends on OF && IOMMU_API + depends on OF_ADDRESS && IOMMU_API # IOMMU-agnostic DMA-mapping layer config IOMMU_DMA
drivers/iommu/of_iommu.c +1 -3
@@ -167,7 +167,7 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,return err; } -static enum iommu_resv_type __maybe_unused +static enum iommu_resv_type iommu_resv_region_get_type (struct device *dev,struct resource *phys,phys_addr_t start,resource_size_t length)
@@ -203,7 +203,6 @@ iommu_resv_region_get_type(struct device *dev,*/ void of_iommu_get_resv_regions (struct device *dev,struct list_head *list) { -#if IS_ENABLED (CONFIG_OF_ADDRESS )struct of_phandle_iterator it;int err;
@@ -265,6 +264,5 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) } } } -#endif }EXPORT_SYMBOL (of_iommu_get_resv_regions);
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v7 3/5] iommu/of: Make OF_IOMMU depend on OF_ADDRESS
Sashiko has reviewed this patch and found no issues.
Quoted 8 lines
The
OF_IOMMUcode relies on OF address parsing helpers, but the dependency onOF_ADDRESSis not expressed inKconfig. As a result,of_iommu.ccontainsCONFIG_OF_ADDRESSguards and a__maybe_unusedannotation to handle configurations whereOF_ADDRESSis disabled.Make
OF_IOMMUdepend onOF_ADDRESSand remove the now unnecessary preprocessor guards and__maybe_unusedannotation.
Quoted 7 lines
The only architecture supporting OF without
OF_ADDRESSis SPARC, which does not useOF_IOMMU, so no functional change is intended.Suggested-by Rob Herring <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
PATCH v7 4/5 iommu/of: Require reg for iommu-addresses
In reply to Vikash GarodiaThe "iommu-addresses" property describes an identity 1:1 mapping between an IOVA range and the physical memory specified by "reg" in the same reserved-memory node. Without "reg", there is no physical memory to map.
The DT schema now requires "reg" whenever "iommu-addresses" is present. Align the kernel implementation with this requirement.
https://github.com/devicetree-org/dt-schema/pull/207
An identity mapping requires matching IOVA and "reg" ranges. Reject mismatched ranges and report an error.
--- drivers/iommu/of_iommu.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)
drivers/iommu/of_iommu.c +15 -17
@@ -174,19 +174,12 @@ iommu_resv_region_get_type(struct device *dev, {phys_addr_t end = start + length -1 ; -/* -* IOMMU regions without an associated physical region cannot be -* mapped and are simply reservations. -*/ -if (phys->start >= phys->end) -return IOMMU_RESV_RESERVED ; -/* may be IOMMU_RESV_DIRECT_RELAXABLE for certain cases */ if (start == phys->start && end == phys->end)return IOMMU_RESV_DIRECT ; -dev_warn (dev,"treating non-direct mapping [%pr] -> [%pap-%pap] as reservation\n" , phys, - &start, &end); +dev_err (dev,"non-direct mapping [%pr] -> [%pap-%pap] is not supported\n" , phys, + &start, &end);return IOMMU_RESV_RESERVED ; }
@@ -211,12 +204,14 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)struct resource phys;int size; -memset (&phys,0 ,sizeof (phys)); + maps =of_get_property (it.node,"iommu-addresses" , &size); +if (!maps) +continue ;/* -* The "reg" property is optional and can be omitted by reserved-memory regions -* that represent reservations in the IOVA space, which are regions that should -* not be mapped. +* "iommu-addresses" must be used in combination with a "reg" that provides +* the physical address and size of this memory region, for an identity 1:1 +* IOVA mapping to that physical memory. */ if (of_property_present (it.node,"reg" )) { err =of_address_to_resource (it.node,0 , &phys);
@@ -225,11 +220,11 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) it.node, err);continue ; } - } - - maps =of_get_property (it.node,"iommu-addresses" , &size); -if (!maps) + }else { +dev_err (dev,"%pOF: iommu-addresses requires a reg property\n" , + it.node);continue ; + } end = maps + size /sizeof (__be32);
@@ -257,6 +252,9 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) } type =iommu_resv_region_get_type (dev, &phys, iova, length); +if (type !=IOMMU_RESV_DIRECT ) +continue ; + region =iommu_alloc_resv_region (iova, length, prot, type,GFP_KERNEL );if (region)
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v7 4/5] iommu/of: Require reg for iommu-addresses
Sashiko has reviewed this patch and found no issues.
Quoted 8 lines
The "iommu-addresses" property describes an identity 1:1 mapping between an IOVA range and the physical memory specified by "reg" in the same reserved-memory node. Without "reg", there is no physical memory to map.
The DT schema now requires "reg" whenever "iommu-addresses" is present. Align the kernel implementation with this requirement.
https://github.com/devicetree-org/dt-schema/pull/207
Quoted 7 lines
An identity mapping requires matching IOVA and "reg" ranges. Reject mismatched ranges and report an error.
Suggested-by Rob Herring <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Re: [PATCH v7 4/5] iommu/of: Require reg for iommu-addresses
In reply to Vikash Garodiadrivers/iommu/of_iommu.c void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) · line 257
Quoted 7 lines · Vikash Garodia
drivers/iommu/of_iommu.c +3
-0@@ -257,6 +252,9 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) } type =iommu_resv_region_get_type (dev, &phys, iova, length); +if (type !=IOMMU_RESV_DIRECT ) +continue ; +
This change is not about requiring a reg though, which is why it should be a standalone patch with its own justifications.
Basically the patch should state why a mismatch is dropped instead of being reserved.
---
bod
PATCH v7 5/5 iommu/of: Add support for "iommu-ranges" on a device node
In reply to Vikash GarodiaReserving an IOVA address using "iommu-addresses" requires it to be placed in the reserved-memory node. But when "iommu-addresses" is the only property being described and there is no backing "reg" (i.e. no actual reserved system memory), it does not really belong under /reserved-memory. A device IOVA range is specific to its own address space, and does not describe the system physical memory to make it qualify under reserved-memory. Given this, place "iommu-addresses" inside reserved-memory only when it is paired with a "reg", otherwise, define it within the device own node. It was discussed here:
https://lore.kernel.org/all/[email protected]
Existing "iommu-addresses" property expects a phandle, which does not make sense when the property is defined within the device node. "iommu-ranges" was introduced to specify the device specific IOVA ranges when there is no backing "reg".
--- drivers/iommu/of_iommu.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+)
drivers/iommu/of_iommu.c +107 -0
@@ -183,6 +183,111 @@ iommu_resv_region_get_type(struct device *dev,return IOMMU_RESV_RESERVED ; } +/** +* of_iommu_derive_resv_regions - derive reserved regions which +* are outside of iommu-ranges +* @dev: device for which to get reserved regions +* @list: reserved region list +* +* A device can describe its own usable IOVA ranges directly on its node +* via "iommu-ranges". Everything not under those ranges is derived +* as a reserved region so the IOMMU allocator won't use it. Entries may +* appear in any order in the property. +*/ +static void of_iommu_derive_resv_regions (struct device *dev,struct list_head *list) +{ +struct of_iommu_range { +struct list_head node; +phys_addr_t start; +phys_addr_t end; + } *pos, *new, *next_range; +int size, prot =IOMMU_READ |IOMMU_WRITE ; +struct iommu_resv_region *region; +const __be32 *maps, *end; +struct list_head *prev; +phys_addr_t next =0 ; +LIST_HEAD (ranges); + + maps =of_get_property (dev->of_node,"iommu-ranges" , &size); +if (!maps) +return ; + + end = maps + size /sizeof (__be32); + +while (maps < end) { +phys_addr_t iova, iova_end; +resource_size_t length; + + maps =of_translate_dma_region (dev->of_node, maps, &iova, &length); +if (!maps) { +dev_err (dev,"%pOF: failed to parse iommu-ranges\n" , + dev->of_node); + goto exit; + } + +if (!length) +continue ; + + iova_end = iova + length -1 ; + +if (iova_end < iova) { +dev_err (dev,"%pOF: iommu-ranges overflows address space\n" , + dev->of_node); + goto exit; + } + + prev = &ranges; +list_for_each_entry (pos, &ranges, node) { +if (pos->start > iova) +break ; + prev = &pos->node; + } + + new =kmalloc_obj (*new); +if (!new) + goto exit; + + new->start = iova; + new->end = iova_end; +list_add (&new->node, prev); + } + +if (list_empty (&ranges)) +return ; + +if (of_dma_is_coherent (dev->of_node)) + prot |=IOMMU_CACHE ; + +list_for_each_entry_safe (pos, next_range, &ranges, node) { +if (pos->start > next) { + region =iommu_alloc_resv_region (next, pos->start - next, prot, +IOMMU_RESV_RESERVED ,GFP_KERNEL ); +if (region) +list_add_tail (®ion->list, list); + } + +if (pos->end >=PHYS_ADDR_MAX -1 ) + goto exit; + +if (pos->end >= next) + next = pos->end +1 ; + +list_del (&pos->node); +kfree (pos); + } + + region =iommu_alloc_resv_region (next,PHYS_ADDR_MAX - next, + prot,IOMMU_RESV_RESERVED ,GFP_KERNEL ); +if (region) +list_add_tail (®ion->list, list); + +exit: +list_for_each_entry_safe (pos, next_range, &ranges, node) { +list_del (&pos->node); +kfree (pos); + } +} +/** * of_iommu_get_resv_regions - reserved region driver helper for device tree * @dev: device for which to get reserved regions
@@ -262,5 +367,7 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) } } } + +of_iommu_derive_resv_regions (dev, list); }EXPORT_SYMBOL (of_iommu_get_resv_regions);
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v7 5/5] iommu/of: Add support for "iommu-ranges" on a device node
Sashiko has reviewed this patch and found no issues.
Quoted 16 lines
Reserving an IOVA address using "iommu-addresses" requires it to be placed in the reserved-memory node. But when "iommu-addresses" is the only property being described and there is no backing "reg" (i.e. no actual reserved system memory), it does not really belong under /reserved-memory. A device IOVA range is specific to its own address space, and does not describe the system physical memory to make it qualify under reserved-memory. Given this, place "iommu-addresses" inside reserved-memory only when it is paired with a "reg", otherwise, define it within the device own node. It was discussed here:
https://lore.kernel.org/all/[email protected]Existing "iommu-addresses" property expects a phandle, which does not make sense when the property is defined within the device node. "iommu-ranges" was introduced to specify the device specific IOVA ranges when there is no backing "reg".
Quoted 5 lines
Suggested-by Rob Herring <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Co-developed-by Vishnu Reddy <[email protected]>Signed-off-by Vishnu Reddy <[email protected]>Signed-off-by Vikash Garodia <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Quoted 54 lines · Vikash Garodia
The series adds support for recently introduced property "iommu-ranges". It adds the required checks to error out for cases which are not following the schema definition.
Iommu-ranges was defined in schema with this PR
https://github.com/devicetree-org/dt-schema/pull/207The patch series is being posted as revision v6, since the patches were initially part of the media series [1]. The patches are moved out to get review comments from iommu reviewers, which was otherwise looking as a media series. Happy to move this back to media series if anyone have any concerns.
[1]
https://lore.kernel.org/linux-media/20260926-vpu_iommu_iova_handling-v5-0-0322ca5dc10c@oss.qualcomm.com/Signed-off-by Vikash Garodia <[email protected]>---
Changes in v7:
- Move the "iommu-addresses" behaviour change ("reg" required, non-direct
mappings rejected) into its own patch before the iommu-ranges patch (Bryan)
- MakeOF_IOMMUdepend onOF_ADDRESSand drop the #if guards (Rob)
- Useresource_size_tfor the size invfio_find_dma()(Sashiko)
- End the derived trailing reserved region atPHYS_ADDR_MAX- 1 to avoid
overflow (Sashiko)
- Add a dma-iommu fix to protect the IOVA rbtree anchor on 32-bit with
64-bitdma_addr_t(Sashiko)
- Use the "iommu/of:" prefix and fix the subject case
- Link to v6: https://lore.kernel.org/r/[email protected]Changes in v6:
- Addressed sashiko comments.
- Addressed comment from Bryan.
- Link to v5: https://lore.kernel.org/all/20260926-vpu_iommu_iova_handling-v5-4-0322ca5dc10c@oss.qualcomm.com/---
Vikash Garodia (5):
iommu/dma: Keep reserved regions below the IOVA rbtree anchor
iommu: Useresource_size_tfor reserved region length iommu/of: MakeOF_IOMMUdepend onOF_ADDRESSiommu/of: Require reg for iommu-addresses iommu/of: Add support for "iommu-ranges" on a device nodedrivers/iommu/Kconfig | 2 +- drivers/iommu/amd/iommu.c | 2 +- drivers/iommu/dma-iommu.c | 32 +++++---- drivers/iommu/intel/iommu.c | 2 +- drivers/iommu/iommu.c | 2 +- drivers/iommu/of_iommu.c | 147 ++++++++++++++++++++++++++++++++++------ drivers/iommu/virtio-iommu.c | 2 +- drivers/of/address.c | 2 +- drivers/vfio/vfio_iommu_type1.c | 2 +- include/linux/iommu.h | 4 +- include/linux/of_address.h | 2 +- 11 files changed, 155 insertions(+), 44 deletions(-)
Quoted 8 lines
---
base-commit:2637bdec0535a2044cd830eba9a79363651d9043
change-id: 20261103-add_iommu_ranges-549cf3fb0867Best regards,
Signature · 1 line
Vikash Garodia <[email protected]>
FYI, we need this series too, for the extended mapping support [1] in
the fastrpc driver. I'll be posting a new version of that series soon.
[1] https://lore.kernel.org/all/[email protected]/