--- zzzz-none-000/linux-4.4.271/drivers/spi/spi.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/spi/spi.c 2023-04-19 10:22:29.000000000 +0000 @@ -37,6 +37,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -697,6 +698,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; @@ -704,12 +713,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); @@ -718,7 +729,7 @@ for (i = 0; i < sgs; i++) { - if (vmalloced_buf) { + if (vmalloced_buf || kmap_buf) { /* * Next scatterlist entry size is the minimum between * the desc_len and the remaining buffer length that @@ -727,7 +738,10 @@ min = min_t(size_t, desc_len, min_t(size_t, len, PAGE_SIZE - 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; @@ -740,7 +754,6 @@ sg_set_buf(&sgt->sgl[i], sg_buf, min); } - buf += min; len -= min; }