in fpga-mgr.c [296:352]
static int fpga_mgr_buf_load(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct page **pages;
struct sg_table sgt;
const void *p;
int nr_pages;
int index;
int rc;
/*
* This is just a fast path if the caller has already created a
* contiguous kernel buffer and the driver doesn't require SG, non-SG
* drivers will still work on the slow path.
*/
if (mgr->mops->write)
return fpga_mgr_buf_load_mapped(mgr, info, buf, count);
/*
* Convert the linear kernel pointer into a sg_table of pages for use
* by the driver.
*/
nr_pages = DIV_ROUND_UP((unsigned long)buf + count, PAGE_SIZE) -
(unsigned long)buf / PAGE_SIZE;
pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
p = buf - offset_in_page(buf);
for (index = 0; index < nr_pages; index++) {
if (is_vmalloc_addr(p))
pages[index] = vmalloc_to_page(p);
else
pages[index] = kmap_to_page((void *)p);
if (!pages[index]) {
kfree(pages);
return -EFAULT;
}
p += PAGE_SIZE;
}
/*
* The temporary pages list is used to code share the merging algorithm
* in sg_alloc_table_from_pages
*/
rc = sg_alloc_table_from_pages(&sgt, pages, index, offset_in_page(buf),
count, GFP_KERNEL);
kfree(pages);
if (rc)
return rc;
rc = fpga_mgr_buf_load_sg(mgr, info, &sgt);
sg_free_table(&sgt);
return rc;
}