diff options
author | Vignesh R <vigneshr@ti.com> | 2016-08-17 05:52:36 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-08-17 07:24:01 -0400 |
commit | b1b8153cf0aeeb7ae6d4f012b8beb2dcfc92c68a (patch) | |
tree | b9fb07d7e31ff24bc7fb47138129548750d9612f | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (diff) |
spi: Add support to handle kmap'd buffers in spi_map_buf()
JFFS2 FS might sometime provide kmap'd buffers as destination
buffers to read data from flash. Update spi_map_buf() function to
generate sg_list for such buffers, so that SPI controllers drivers can
use DMA to read data into such buffers.
Signed-off-by: Vignesh R <vigneshr@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 51ad42fad567..2a5dd22efa34 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
38 | #include <linux/ioport.h> | 38 | #include <linux/ioport.h> |
39 | #include <linux/acpi.h> | 39 | #include <linux/acpi.h> |
40 | #include <linux/highmem.h> | ||
40 | 41 | ||
41 | #define CREATE_TRACE_POINTS | 42 | #define CREATE_TRACE_POINTS |
42 | #include <trace/events/spi.h> | 43 | #include <trace/events/spi.h> |
@@ -709,6 +710,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, | |||
709 | { | 710 | { |
710 | const bool vmalloced_buf = is_vmalloc_addr(buf); | 711 | const bool vmalloced_buf = is_vmalloc_addr(buf); |
711 | unsigned int max_seg_size = dma_get_max_seg_size(dev); | 712 | unsigned int max_seg_size = dma_get_max_seg_size(dev); |
713 | #ifdef CONFIG_HIGHMEM | ||
714 | const bool kmap_buf = ((unsigned long)buf >= PKMAP_BASE && | ||
715 | (unsigned long)buf < (PKMAP_BASE + | ||
716 | (LAST_PKMAP * PAGE_SIZE))); | ||
717 | #else | ||
718 | const bool kmap_buf = false; | ||
719 | #endif | ||
712 | int desc_len; | 720 | int desc_len; |
713 | int sgs; | 721 | int sgs; |
714 | struct page *vm_page; | 722 | struct page *vm_page; |
@@ -716,7 +724,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, | |||
716 | size_t min; | 724 | size_t min; |
717 | int i, ret; | 725 | int i, ret; |
718 | 726 | ||
719 | if (vmalloced_buf) { | 727 | if (vmalloced_buf || kmap_buf) { |
720 | desc_len = min_t(int, max_seg_size, PAGE_SIZE); | 728 | desc_len = min_t(int, max_seg_size, PAGE_SIZE); |
721 | sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); | 729 | sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); |
722 | } else if (virt_addr_valid(buf)) { | 730 | } else if (virt_addr_valid(buf)) { |
@@ -732,10 +740,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, | |||
732 | 740 | ||
733 | for (i = 0; i < sgs; i++) { | 741 | for (i = 0; i < sgs; i++) { |
734 | 742 | ||
735 | if (vmalloced_buf) { | 743 | if (vmalloced_buf || kmap_buf) { |
736 | min = min_t(size_t, | 744 | min = min_t(size_t, |
737 | len, desc_len - offset_in_page(buf)); | 745 | len, desc_len - offset_in_page(buf)); |
738 | vm_page = vmalloc_to_page(buf); | 746 | if (vmalloced_buf) |
747 | vm_page = vmalloc_to_page(buf); | ||
748 | else | ||
749 | vm_page = kmap_to_page(buf); | ||
739 | if (!vm_page) { | 750 | if (!vm_page) { |
740 | sg_free_table(sgt); | 751 | sg_free_table(sgt); |
741 | return -ENOMEM; | 752 | return -ENOMEM; |