Skip to contentSkip to conversation

spi: Fix mapping from vmalloc-ed buffer to scatter list

PATCH Applied Charles Keepax 2 participants 8 messages Nov 14, 2014 6 messages not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 spi: Fix mapping from vmalloc-ed buffer to scatter list

We can only use page_address on memory that has been mapped using kmap, when the buffer passed to the SPI has been allocated by vmalloc the page has not necessarily been mapped through kmap. This means sometimes page_address will return NULL causing the pointer we pass to sg_set_buf to be invalid.

As we only call page_address such that we can pass a virtual address to sg_set_buf which will then immediately call virt_to_page on it, fix this by calling sg_set_page directly rather then relying on the sg_set_buf helper.

---
 drivers/spi/spi.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/spi/spi.c +3 -3
index ebcb33d..50f20f2 100644
@@ -615,13 +615,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
 				sg_free_table(sgt);
 				return -ENOMEM;
 			}
-			sg_buf = page_address(vm_page) +
-				((size_t)buf & ~PAGE_MASK);
+			sg_set_page(&sgt->sgl[i], vm_page,
+				    min, offset_in_page(buf));
 		} else {
 			sg_buf = buf;
+			sg_set_buf(&sgt->sgl[i], sg_buf, min);
 		}
 
-		sg_set_buf(&sgt->sgl[i], sg_buf, min);
 
 		buf += min;
 		len -= min;
Signature · 6 lines
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 1415979645-26264-1-git-send-email-ckeepax-yzvPICuk2AATkU/[email protected]

#2 lore raw

PATCH 2/2 ASoC: wm_adsp: Use vmalloc to allocate firmware download buffer

Use vmalloc to allocate the buffer for firmware/coefficient download and rely on the SPI core to split this up into DMA-able chunks. This should give better performance and means we no longer need to manually split the download into page size chunks to avoid allocating overly large continuous memory regions.

---
 sound/soc/codecs/wm_adsp.c |   58 +++++++++++++++++--------------------------
 1 files changed, 23 insertions(+), 35 deletions(-)
sound/soc/codecs/wm_adsp.c +22 -34
index f412a99..0a08ef5e 100644
@@ -21,6 +21,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -169,11 +170,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
 	if (buf == NULL)
 		return NULL;
 
-	buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
+	buf->buf = vmalloc(len);
 	if (!buf->buf) {
-		kfree(buf);
+		vfree(buf);
 		return NULL;
 	}
+	memcpy(buf->buf, src, len);
 
 	if (list)
 		list_add_tail(&buf->list, list);
@@ -188,7 +190,7 @@ static void wm_adsp_buf_free(struct list_head *list)
 							   struct wm_adsp_buf,
 							   list);
 		list_del(&buf->list);
-		kfree(buf->buf);
+		vfree(buf->buf);
 		kfree(buf);
 	}
 }
@@ -684,38 +686,24 @@ static int wm_adsp_load(struct wm_adsp *dsp)
 		}
 
 		if (reg) {
-			size_t to_write = PAGE_SIZE;
-			size_t remain = le32_to_cpu(region->len);
-			const u8 *data = region->data;
-
-			while (remain > 0) {
-				if (remain < PAGE_SIZE)
-					to_write = remain;
-
-				buf = wm_adsp_buf_alloc(data,
-							to_write,
-							&buf_list);
-				if (!buf) {
-					adsp_err(dsp, "Out of memory\n");
-					ret = -ENOMEM;
-					goto out_fw;
-				}
-
-				ret = regmap_raw_write_async(regmap, reg,
-							     buf->buf,
-							     to_write);
-				if (ret != 0) {
-					adsp_err(dsp,
-						"%s.%d: Failed to write %zd bytes at %d in %s: %d\n",
-						file, regions,
-						to_write, offset,
-						region_name, ret);
-					goto out_fw;
-				}
+			buf = wm_adsp_buf_alloc(region->data,
+						le32_to_cpu(region->len),
+						&buf_list);
+			if (!buf) {
+				adsp_err(dsp, "Out of memory\n");
+				ret = -ENOMEM;
+				goto out_fw;
+			}
 
-				data += to_write;
-				reg += to_write / 2;
-				remain -= to_write;
+			ret = regmap_raw_write_async(regmap, reg, buf->buf,
+						     le32_to_cpu(region->len));
+			if (ret != 0) {
+				adsp_err(dsp,
+					"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
+					file, regions,
+					le32_to_cpu(region->len), offset,
+					region_name, ret);
+				goto out_fw;
 			}
 		}
 
Signature · 6 lines
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 1415979645-26264-2-git-send-email-ckeepax-yzvPICuk2AATkU/[email protected]

Applied
#4 lore raw

Re: [PATCH 2/2] ASoC: wm_adsp: Use vmalloc to allocate firmware download buffer

Quoted 5 lines · Charles Keepax

Use vmalloc to allocate the buffer for firmware/coefficient download and rely on the SPI core to split this up into DMA-able chunks. This should give better performance and means we no longer need to manually split the download into page size chunks to avoid allocating overly large continuous memory regions.

Applied, thanks.

#5 lore raw
In reply to a message not in the archive
Quoted 5 lines · Charles Keepax

We can only use page_address on memory that has been mapped using kmap, when the buffer passed to the SPI has been allocated by vmalloc the page has not necessarily been mapped through kmap. This means sometimes page_address will return NULL causing the pointer we pass to sg_set_buf to be invalid.

Hrm, this is a bug in the mxs driver (which is where we copied the core code from) - care to fix that too?

Quoted 1 line

As we only call page_address such that we can pass a virtual address to

s/such/so/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw
Quoted 9 lines · Mark Brown
Quoted 5 lines · Charles Keepax

We can only use page_address on memory that has been mapped using kmap, when the buffer passed to the SPI has been allocated by vmalloc the page has not necessarily been mapped through kmap. This means sometimes page_address will return NULL causing the pointer we pass to sg_set_buf to be invalid.

Hrm, this is a bug in the mxs driver (which is where we copied the core code from) - care to fix that too?

Yeah no problem, won't be able to test it, but should be a fairly trivial change and hopefully someone else can test.

Quoted 4 lines
Quoted 2 lines

As we only call page_address such that we can pass a virtual address to

s/such/so/

Will ping a respin and include the mxs fixup too.

Thanks,
Charles

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20141114160607.GB12443-yzvPICuk2AATkU/[email protected]

#9 lore raw
Quoted 8 lines · Charles Keepax
Quoted 7 lines · Mark Brown
Quoted 5 lines · Charles Keepax

We can only use page_address on memory that has been mapped using kmap, when the buffer passed to the SPI has been allocated by vmalloc the page has not necessarily been mapped through kmap. This means sometimes page_address will return NULL causing the pointer we pass to sg_set_buf to be invalid.

Quoted 5 lines
Quoted 2 lines

Hrm, this is a bug in the mxs driver (which is where we copied the core code from) - care to fix that too?

Yeah no problem, won't be able to test it, but should be a fairly trivial change and hopefully someone else can test.

Ah... ok I think I see the difference here. The MXS architecture has CONFIG_HIGHMEM=n whereas Arndale has CONFIG_HIGHMEM=y. So that means on MXS all the pages will always be in low mem so I think will always be mapped into the kernel logical address space hence no problems. Not sure if it would be worth updating the driver or not, what do you think?

Thanks,
Charles
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20141114171133.GC12443-yzvPICuk2AATkU/[email protected]

#11 lore raw
Quoted 6 lines · Charles Keepax

Ah... ok I think I see the difference here. The MXS architecture has CONFIG_HIGHMEM=n whereas Arndale has CONFIG_HIGHMEM=y. So that means on MXS all the pages will always be in low mem so I think will always be mapped into the kernel logical address space hence no problems. Not sure if it would be worth updating the driver or not, what do you think?

This is a user configurable option, it's not something that depends on the architecture (and in any case it's better not to leave people wondering why things are different when they consider consolidation).

A message that is not in the archive (sent off-list or not yet received): [email protected]

#13 lore raw
Quoted 9 lines · Mark Brown
Quoted 6 lines · Charles Keepax

Ah... ok I think I see the difference here. The MXS architecture has CONFIG_HIGHMEM=n whereas Arndale has CONFIG_HIGHMEM=y. So that means on MXS all the pages will always be in low mem so I think will always be mapped into the kernel logical address space hence no problems. Not sure if it would be worth updating the driver or not, what do you think?

Quoted 3 lines

This is a user configurable option, it's not something that depends on the architecture (and in any case it's better not to leave people wondering why things are different when they consider consolidation).

Cool, I will do the respin then.

Thanks,
Charles
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html