--- zzzz-none-000/linux-4.4.60/drivers/spi/spi.c 2017-04-08 07:53:53.000000000 +0000 +++ wasp-540e-714/linux-4.4.60/drivers/spi/spi.c 2019-07-03 09:21:34.000000000 +0000 @@ -37,6 +37,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -685,6 +686,14 @@ enum dma_data_direction dir) { const bool vmalloced_buf = is_vmalloc_addr(buf); + unsigned int max_seg_size = dma_get_max_seg_size(dev); +#ifdef CONFIG_HIGHMEM + const bool kmap_buf = ((unsigned long)buf >= PKMAP_BASE && + (unsigned long)buf < (PKMAP_BASE + + (LAST_PKMAP * PAGE_SIZE))); +#else + const bool kmap_buf = false; +#endif int desc_len; int sgs; struct page *vm_page; @@ -692,12 +701,14 @@ size_t min; int i, ret; - if (vmalloced_buf) { - desc_len = PAGE_SIZE; + if (vmalloced_buf || kmap_buf) { + desc_len = min_t(int, max_seg_size, PAGE_SIZE); sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); - } else { - desc_len = master->max_dma_len; + } else if (virt_addr_valid(buf)) { + desc_len = min_t(int, max_seg_size, master->max_dma_len); sgs = DIV_ROUND_UP(len, desc_len); + } else { + return -EINVAL; } ret = sg_alloc_table(sgt, sgs, GFP_KERNEL); @@ -706,10 +717,13 @@ for (i = 0; i < sgs; i++) { - if (vmalloced_buf) { + if (vmalloced_buf || kmap_buf) { min = min_t(size_t, len, desc_len - offset_in_page(buf)); - vm_page = vmalloc_to_page(buf); + if (vmalloced_buf) + vm_page = vmalloc_to_page(buf); + else + vm_page = kmap_to_page(buf); if (!vm_page) { sg_free_table(sgt); return -ENOMEM; @@ -722,7 +736,6 @@ sg_set_buf(&sgt->sgl[i], sg_buf, min); } - buf += min; len -= min; }