Skip to contentSkip to conversation

dma-coherent: add support for multi coherent rmems per dev

PATCH Superseded Howard Yen 4 participants 12 messages Feb 8, 2024 – Mar 4, 2024

Subsystems (2)

v3 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Howard Yen

author
#0 lore raw

PATCH v3 1/1 dma-coherent: add support for multi coherent rmems per dev

Add support for multiple coherent rmems per device. This patch replaces original dma_mem with dma_mems list in device structure to store multiple rmems.

These multiple rmems can be assigned to the device one by one by of_reserved_mem_device_init_by_idx() with the memory-region declaration in device tree as below and store the rmem to the dma_mems list.

	device1@0 {
		...
		memory-region = <&reserved_mem0>, <&reserved_mem1>;
		...
	};

When driver tries to allocate memory from the rmems, looks for the first available rmem and allocates the memory from this rmem.

Then if driver removed, of_reserved_mem_device_release() needs to be invoked to release all the rmems assigned to the device.

---
Changelog since v2:
(suggested by Andy Shevchenko <[email protected]>)
- Re-org the members of struct dma_coherent_mem to avoid additional pointer arithmetics and the holes inside the structure.
- Use consistent naming of return value.
- Re-write the dev checking statement to be more clear.

 drivers/base/core.c    |  3 ++
 include/linux/device.h |  5 +--
 kernel/dma/coherent.c  | 92 +++++++++++++++++++++++++++---------------
 3 files changed, 64 insertions(+), 36 deletions(-)
drivers/base/core.c +3 -0
index 14d46af40f9a..d9af38d7b870 100644
@@ -3108,6 +3108,9 @@ void device_initialize(struct device *dev)
     defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \
     defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
 	dev->dma_coherent = dma_default_coherent;
+#endif
+#ifdef CONFIG_DMA_DECLARE_COHERENT
+	INIT_LIST_HEAD(&dev->dma_mems);
 #endif
 	swiotlb_dev_init(dev);
 }
include/linux/device.h +2 -3
index 97c4b046c09d..5fa15e5adbdc 100644
@@ -648,7 +648,7 @@ struct device_physical_location {
  * @dma_parms:	A low level driver may set these to teach IOMMU code about
  * 		segment limitations.
  * @dma_pools:	Dma pools (if dma'ble device).
- * @dma_mem:	Internal for coherent mem override.
+ * @dma_mems:	Internal for coherent mems.
  * @cma_area:	Contiguous memory area for dma allocations
  * @dma_io_tlb_mem: Software IO TLB allocator.  Not for driver use.
  * @dma_io_tlb_pools:	List of transient swiotlb memory pools.
@@ -749,8 +749,7 @@ struct device {
 	struct list_head	dma_pools;	/* dma pools (if dma'ble) */
 
 #ifdef CONFIG_DMA_DECLARE_COHERENT
-	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
-					     override */
+	struct list_head	dma_mems; /* Internal for coherent mems */
 #endif
 #ifdef CONFIG_DMA_CMA
 	struct cma *cma_area;		/* contiguous memory area for dma
kernel/dma/coherent.c +59 -33

158 lines not on this page · raw message

Signature · 1 line
2.43.0.594.gd9cf4e227d-goog
#1 lore raw
Quoted 20 lines · Howard Yen

Add support for multiple coherent rmems per device. This patch replaces original dma_mem with dma_mems list in device structure to store multiple rmems.

These multiple rmems can be assigned to the device one by one by of_reserved_mem_device_init_by_idx() with the memory-region declaration in device tree as below and store the rmem to the dma_mems list.

	device1@0 {
		...
		memory-region = <&reserved_mem0>, <&reserved_mem1>;
		...
	};

When driver tries to allocate memory from the rmems, looks for the first available rmem and allocates the memory from this rmem.

Then if driver removed, of_reserved_mem_device_release() needs to be invoked to release all the rmems assigned to the device.

...

Quoted 5 lines
kernel/dma/coherent.c +1 -1
 	struct dma_coherent_mem *mem;
-	int ret;
+	int retval;
 
 	mem = dma_init_coherent_memory(phys_addr, device_addr, size, false);

kernel/dma/coherent.c int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, · line 123

Quoted 10 lines
kernel/dma/coherent.c +3 -3
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
-	ret = dma_assign_coherent_memory(dev, mem);
-	if (ret)
+	retval = dma_assign_coherent_memory(dev, mem);
+	if (retval)
 		_dma_release_coherent_memory(mem);
-	return ret;
+	return retval;

This is unrelated change.

But why? Do you have retval in the _existing_ code elsewhere?

...

Quoted 5 lines

int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,

kernel/dma/coherent.c +1 -1
 		dma_addr_t *dma_handle, void **ret)
 {
-	struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+	struct dma_coherent_mem *mem_tmp;

kernel/dma/coherent.c static void *__dma_alloc_from_coherent(struct device *dev, · line 196

Quoted 10 lines
kernel/dma/coherent.c +5 -2
 
-	if (!mem)
+	if (list_empty(&dev->dma_mems))
 		return 0;
 
-	*ret = __dma_alloc_from_coherent(dev, mem, size, dma_handle);
+	list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+		*ret = __dma_alloc_from_coherent(dev, mem_tmp, size, dma_handle);
+		if (*ret)
+			break;

This bails out on the first success. Moreover, if one calls this function again, it will rewrite the existing allocation. Is this all expected?

OTOH, if you add multiple entries and bailing out on error condition it should be clear if the previous allocations have to be released.

Quoted 5 lines
kernel/dma/coherent.c +1 -0
+	}
 
 	return 1;
 
 }

...

kernel/dma/coherent.c static int __dma_release_from_coherent(struct dma_coherent_mem *mem, · line 238

Quoted 10 lines

int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr) {

kernel/dma/coherent.c +7 -1
-	struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+	struct dma_coherent_mem *mem_tmp;
+	int retval = 0;
+
+	list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+		retval = __dma_release_from_coherent(mem_tmp, order, vaddr);
+		if (retval == 1)
+			break;

Same Q here.

Quoted 5 lines
kernel/dma/coherent.c +2 -1
+	}
 
-	return __dma_release_from_coherent(mem, order, vaddr);
+	return retval;
 }

...

kernel/dma/coherent.c static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem, · line 290

Quoted 12 lines

int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,

kernel/dma/coherent.c +6 -2
 			   void *vaddr, size_t size, int *ret)
 {
-	struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+	struct dma_coherent_mem *mem_tmp;
+	int retval = 0;
 
-	return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret);
+	list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+		retval = __dma_mmap_from_coherent(mem_tmp, vma, vaddr, size, ret);
+		if (retval == 1)
+			break;

And here.

kernel/dma/coherent.c static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem, · line 294

Quoted 4 lines
kernel/dma/coherent.c +3 -0
+	}
+
+	return retval;
 }

...

With the above Q in mind, here is another one: Why can't we allocate all at once?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author
#2 lore raw
Quoted 41 lines · Andy Shevchenko
Quoted 20 lines · Howard Yen

Add support for multiple coherent rmems per device. This patch replaces original dma_mem with dma_mems list in device structure to store multiple rmems.

These multiple rmems can be assigned to the device one by one by of_reserved_mem_device_init_by_idx() with the memory-region declaration in device tree as below and store the rmem to the dma_mems list.

      device1@0 {
              ...
              memory-region = <&reserved_mem0>, <&reserved_mem1>;
              ...
      };

When driver tries to allocate memory from the rmems, looks for the first available rmem and allocates the memory from this rmem.

Then if driver removed, of_reserved_mem_device_release() needs to be invoked to release all the rmems assigned to the device.

...

Quoted 5 lines
      struct dma_coherent_mem *mem;
kernel/dma/coherent.c +1 -1
-     int ret;
+     int retval;
 
      mem = dma_init_coherent_memory(phys_addr, device_addr, size, false);

kernel/dma/coherent.c int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, · line 123

Quoted 10 lines
kernel/dma/coherent.c +3 -3
      if (IS_ERR(mem))
              return PTR_ERR(mem);
 
-     ret = dma_assign_coherent_memory(dev, mem);
-     if (ret)
+     retval = dma_assign_coherent_memory(dev, mem);
+     if (retval)
              _dma_release_coherent_memory(mem);
-     return ret;
+     return retval;
Quoted 3 lines

This is unrelated change.

But why? Do you have retval in the _existing_ code elsewhere?

Rename the 'ret' variable to 'retval' because, in the dma_mmap_from_dev_coherent(),
there is an argument named 'ret', and also I add 'retval' for the return value. So I try to rename it here to be consistent.

Quoted 20 lines

...

Quoted 5 lines

int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
dma_addr_t *dma_handle, void **ret)
{

kernel/dma/coherent.c +1 -1
-     struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+     struct dma_coherent_mem *mem_tmp;

kernel/dma/coherent.c static void *__dma_alloc_from_coherent(struct device *dev, · line 196

Quoted 10 lines
kernel/dma/coherent.c +5 -2
 
-     if (!mem)
+     if (list_empty(&dev->dma_mems))
              return 0;
 
-     *ret = __dma_alloc_from_coherent(dev, mem, size, dma_handle);
+     list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+             *ret = __dma_alloc_from_coherent(dev, mem_tmp, size, dma_handle);
+             if (*ret)
+                     break;
Quoted 5 lines

This bails out on the first success. Moreover, if one calls this function again, it will rewrite the existing allocation. Is this all expected?

OTOH, if you add multiple entries and bailing out on error condition it should be clear if the previous allocations have to be released.

If it's not able to allocate required memory from the first entry, then tries to allocate
from the following entry, and so on.

Quoted 45 lines
Quoted 6 lines

+ }

      return 1;

}

...

kernel/dma/coherent.c static int __dma_release_from_coherent(struct dma_coherent_mem *mem, · line 238

Quoted 10 lines

int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr) {

kernel/dma/coherent.c +7 -1
-     struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+     struct dma_coherent_mem *mem_tmp;
+     int retval = 0;
+
+     list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+             retval = __dma_release_from_coherent(mem_tmp, order, vaddr);
+             if (retval == 1)
+                     break;

Same Q here.

Quoted 5 lines
kernel/dma/coherent.c +2 -1
+     }
 
-     return __dma_release_from_coherent(mem, order, vaddr);
+     return retval;
 }

...

kernel/dma/coherent.c static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem, · line 290

Quoted 12 lines

int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
void *vaddr, size_t size, int *ret)
{

kernel/dma/coherent.c +6 -2
-     struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+     struct dma_coherent_mem *mem_tmp;
+     int retval = 0;
 
-     return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret);
+     list_for_each_entry(mem_tmp, &dev->dma_mems, node) {
+             retval = __dma_mmap_from_coherent(mem_tmp, vma, vaddr, size, ret);
+             if (retval == 1)
+                     break;

And here.

Quoted 8 lines

kernel/dma/coherent.c static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem, · line 294

Quoted 4 lines
kernel/dma/coherent.c +3 -0
+     }
+
+     return retval;
 }

...

With the above Q in mind, here is another one: Why can't we allocate all at once?

Not sure if I misunderstand your meaning, It tries to allocate the memory from the first
entry that satisfies the allocation requirement, but not separately.

Quoted 6 lines

--
With Best Regards,
Andy Shevchenko

Signature · 3 lines
Regards,

Howard
author
#4 lore raw
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Howard Yen

Add support for multiple coherent rmems per device.

Why?

I tried to upload the patch to support multiple coherent rmems per device because in some system, the primary memory space for the device might be limited, so that add multiple coherent rmems support per device to satisfy the scenario.

Signature · 3 lines
Regards,

Howard
#5 lore raw
Quoted 4 lines · Howard Yen

I tried to upload the patch to support multiple coherent rmems per device because in some system, the primary memory space for the device might be limited, so that add multiple coherent rmems support per device to satisfy the scenario.

I'm not sure what the means.

If you have non-trivial patches you really need to explain why you're doing in detail as you need to convince maintainers that it is useful.

author
#6 lore raw
Quoted 11 lines · Christoph Hellwig
Quoted 4 lines · Howard Yen

I tried to upload the patch to support multiple coherent rmems per device because in some system, the primary memory space for the device might be limited, so that add multiple coherent rmems support per device to satisfy the scenario.

I'm not sure what the means.

If you have non-trivial patches you really need to explain why you're doing in detail as you need to convince maintainers that it is useful.

Thanks for the response, let me explain more.

The reason why I tried to propose this patch is that in the system I'm working on, where the driver utilizes the coherent reserved memory in the subsystem for DMA, which has limited memory space as its primary usage. During the execution of the driver, there is a possibility of encountering memory depletion scenarios with the primary one.

To address this issue, I tried to create a patch that enables the coherent reserved memory driver to support multiple coherent reserved memory regions per device. This modification aims to provide the driver with the ability to search for memory from a secondary region if the primary memory is exhausted, and so on.

--
Regards,

Howard

#7 lore raw
Quoted 11 lines · Howard Yen

The reason why I tried to propose this patch is that in the system I'm working on, where the driver utilizes the coherent reserved memory in the subsystem for DMA, which has limited memory space as its primary usage. During the execution of the driver, there is a possibility of encountering memory depletion scenarios with the primary one.

To address this issue, I tried to create a patch that enables the coherent reserved memory driver to support multiple coherent reserved memory regions per device. This modification aims to provide the driver with the ability to search for memory from a secondary region if the primary memory is exhausted, and so on.

This all seems pretty vague. Can you point to your driver submission and explain why it can't just use a larger region instead of multiple smaller ones?

author
#8 lore raw
Quoted 14 lines · Christoph Hellwig
Quoted 11 lines · Howard Yen

The reason why I tried to propose this patch is that in the system I'm working on, where the driver utilizes the coherent reserved memory in the subsystem for DMA, which has limited memory space as its primary usage. During the execution of the driver, there is a possibility of encountering memory depletion scenarios with the primary one.

To address this issue, I tried to create a patch that enables the coherent reserved memory driver to support multiple coherent reserved memory regions per device. This modification aims to provide the driver with the ability to search for memory from a secondary region if the primary memory is exhausted, and so on.

Quoted 4 lines

This all seems pretty vague. Can you point to your driver submission and explain why it can't just use a larger region instead of multiple smaller ones?

The reason why it needs multiple regions is that in my system there is an always-on subsystem which includes a small size memory, and several functions need to run and occupy the memory from the small memory if they need to run on the always-on subsystem. These functions must allocate the memory from the small memory region, so that they can get benefit from the always-on subsystem. So the small memory is split for multiple functions which are satisfied with their generic use cases. But in specific use cases, they required more memory than their pre-allocated memory region, so I tried to propose this patch to give it the ability to get the memory from another larger memory to solve the issue.

I'll upload the next version to show the modification in the driver.

---
Best Regards,

Howard

reviewer
#9 lore raw
Quoted 20 lines · Howard Yen
Quoted 14 lines · Christoph Hellwig
Quoted 11 lines · Howard Yen

The reason why I tried to propose this patch is that in the system I'm working on, where the driver utilizes the coherent reserved memory in the subsystem for DMA, which has limited memory space as its primary usage. During the execution of the driver, there is a possibility of encountering memory depletion scenarios with the primary one.

To address this issue, I tried to create a patch that enables the coherent reserved memory driver to support multiple coherent reserved memory regions per device. This modification aims to provide the driver with the ability to search for memory from a secondary region if the primary memory is exhausted, and so on.

Quoted 4 lines

This all seems pretty vague. Can you point to your driver submission and explain why it can't just use a larger region instead of multiple smaller ones?

Quoted 7 lines

The reason why it needs multiple regions is that in my system there is an always-on subsystem which includes a small size memory, and several functions need to run and occupy the memory from the small memory if they need to run on the always-on subsystem. These functions must allocate the memory from the small memory region, so that they can get benefit from the always-on subsystem. So the small memory is split for multiple functions which are satisfied with their generic use cases.

I don't really see how that aligns with what you've implemented, though. The coherent allocator doesn't have any notion of the caller's use-case, it's just going to allocate from wherever it happens to find space first. Thus even the calls which would somehow benefit from allocating from the "primary" region will have no way to guarantee that they will actually allocate from there if it's already been consumed by callers who didn't need that benefit but just happened to get there first.

Really that sounds like a case for having specific named memory-regions and managing them directly from the relevant driver, rather than trying to convince the generic dma-coherent abstraction to do things that don't really fit it. Otherwise I'd be slightly concerned that you're expecting to bake secret undocumented ABI into DMA API implementations where some particular order of allocations must guarantee a particular deterministic behaviour, which is really not something we want.

Thanks,
Robin.

Quoted 11 lines

But in specific use cases, they required more memory than their pre-allocated memory region, so I tried to propose this patch to give it the ability to get the memory from another larger memory to solve the issue.

I'll upload the next version to show the modification in the driver.

---
Best Regards,

Howard

author
#10 lore raw
Quoted 38 lines · Robin Murphy
Quoted 20 lines · Howard Yen
Quoted 14 lines · Christoph Hellwig
Quoted 11 lines · Howard Yen

The reason why I tried to propose this patch is that in the system I'm working on, where the driver utilizes the coherent reserved memory in the subsystem for DMA, which has limited memory space as its primary usage. During the execution of the driver, there is a possibility of encountering memory depletion scenarios with the primary one.

To address this issue, I tried to create a patch that enables the coherent reserved memory driver to support multiple coherent reserved memory regions per device. This modification aims to provide the driver with the ability to search for memory from a secondary region if the primary memory is exhausted, and so on.

Quoted 4 lines

This all seems pretty vague. Can you point to your driver submission and explain why it can't just use a larger region instead of multiple smaller ones?

Quoted 7 lines

The reason why it needs multiple regions is that in my system there is an always-on subsystem which includes a small size memory, and several functions need to run and occupy the memory from the small memory if they need to run on the always-on subsystem. These functions must allocate the memory from the small memory region, so that they can get benefit from the always-on subsystem. So the small memory is split for multiple functions which are satisfied with their generic use cases.

I don't really see how that aligns with what you've implemented, though. The coherent allocator doesn't have any notion of the caller's use-case, it's just going to allocate from wherever it happens to find space first. Thus even the calls which would somehow benefit from allocating from the "primary" region will have no way to guarantee that they will actually allocate from there if it's already been consumed by callers who didn't need that benefit but just happened to get there first.

Quoted 7 lines

Really that sounds like a case for having specific named memory-regions and managing them directly from the relevant driver, rather than trying to convince the generic dma-coherent abstraction to do things that don't really fit it. Otherwise I'd be slightly concerned that you're expecting to bake secret undocumented ABI into DMA API implementations where some particular order of allocations must guarantee a particular deterministic behaviour, which is really not something we want.

Thanks for the response.

The original problem I tried to resolve is the use-case explained in the previous reply, and I was thinking of implementing it in a generic way. Then I tried to submit this patch. As you mentioned here, it provides the benefit that if somehow the "primary" region has no way to guarantee for the callers. And my use-case is one of its uses.

---
Best Regards,

Howard

Quoted 15 lines

Thanks,
Robin.

Quoted 11 lines

But in specific use cases, they required more memory than their pre-allocated memory region, so I tried to propose this patch to give it the ability to get the memory from another larger memory to solve the issue.

I'll upload the next version to show the modification in the driver.

---
Best Regards,

Howard

Signature · 3 lines
Best Regards,

Howard
author
#11 lore raw
In reply to Christoph Hellwig
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Howard Yen

Add support for multiple coherent rmems per device.

Why?

Resend the message because the previous one contained some HTML.

I tried to upload the patch to support multiple coherent rmems per device because in some system, the primary memory space for the device might be limited, so that add multiple coherent rmems support per device to satisfy the scenario.

Signature · 3 lines
Regards,

Howard