static __inline void init_sg_elem(struct scatterlist *sgp, struct page *p, int offset, void *addr, size_t length) { sgp->length = length; if (p) { sg_assign_page(sgp, p); sgp->offset = offset; } else { sg_assign_page(sgp, virt_to_page(addr)); sgp->offset = offset_in_page(addr); } }
/* rd_build_device_space(): * * */ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table, u32 total_sg_needed, unsigned char init_payload) { u32 i = 0, j, page_offset = 0, sg_per_table; u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / sizeof(struct scatterlist)); struct page *pg; struct scatterlist *sg; unsigned char *p; while (total_sg_needed) { sg_per_table = (total_sg_needed > max_sg_per_table) ? max_sg_per_table : total_sg_needed; sg = kzalloc(sg_per_table * sizeof(struct scatterlist), GFP_KERNEL); if (!sg) { pr_err("Unable to allocate scatterlist array" " for struct rd_dev\n"); return -ENOMEM; } sg_init_table(sg, sg_per_table); sg_table[i].sg_table = sg; sg_table[i].rd_sg_count = sg_per_table; sg_table[i].page_start_offset = page_offset; sg_table[i++].page_end_offset = (page_offset + sg_per_table) - 1; for (j = 0; j < sg_per_table; j++) { pg = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); if (!pg) { pr_err("Unable to allocate scatterlist" " pages for struct rd_dev_sg_table\n"); return -ENOMEM; } sg_assign_page(&sg[j], pg); sg[j].length = PAGE_SIZE; p = kmap(pg); memset(p, init_payload, PAGE_SIZE); kunmap(pg); } page_offset += sg_per_table; total_sg_needed -= sg_per_table; } return 0; }
/* rd_build_device_space(): * * */ static int rd_build_device_space(struct rd_dev *rd_dev) { u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed; u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / sizeof(struct scatterlist)); struct rd_dev_sg_table *sg_table; struct page *pg; struct scatterlist *sg; if (rd_dev->rd_page_count <= 0) { pr_err("Illegal page count: %u for Ramdisk device\n", rd_dev->rd_page_count); return -EINVAL; } total_sg_needed = rd_dev->rd_page_count; sg_tables = (total_sg_needed / max_sg_per_table) + 1; sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL); if (!sg_table) { pr_err("Unable to allocate memory for Ramdisk" " scatterlist tables\n"); return -ENOMEM; } rd_dev->sg_table_array = sg_table; rd_dev->sg_table_count = sg_tables; while (total_sg_needed) { sg_per_table = (total_sg_needed > max_sg_per_table) ? max_sg_per_table : total_sg_needed; sg = kzalloc(sg_per_table * sizeof(struct scatterlist), GFP_KERNEL); if (!sg) { pr_err("Unable to allocate scatterlist array" " for struct rd_dev\n"); return -ENOMEM; } sg_init_table(sg, sg_per_table); sg_table[i].sg_table = sg; sg_table[i].rd_sg_count = sg_per_table; sg_table[i].page_start_offset = page_offset; sg_table[i++].page_end_offset = (page_offset + sg_per_table) - 1; for (j = 0; j < sg_per_table; j++) { pg = alloc_pages(GFP_KERNEL, 0); if (!pg) { pr_err("Unable to allocate scatterlist" " pages for struct rd_dev_sg_table\n"); return -ENOMEM; } sg_assign_page(&sg[j], pg); sg[j].length = PAGE_SIZE; } page_offset += sg_per_table; total_sg_needed -= sg_per_table; } pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u space of" " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, rd_dev->rd_page_count, rd_dev->sg_table_count); return 0; }
/* rd_build_device_space(): * * */ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table, u32 total_sg_needed, unsigned char init_payload) { u32 i = 0, j, page_offset = 0, sg_per_table; u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / sizeof(struct scatterlist)); struct page *pg; struct scatterlist *sg; unsigned char *p; while (total_sg_needed) { unsigned int chain_entry = 0; sg_per_table = (total_sg_needed > max_sg_per_table) ? max_sg_per_table : total_sg_needed; #ifdef CONFIG_ARCH_HAS_SG_CHAIN /* * Reserve extra element for chain entry */ if (sg_per_table < total_sg_needed) chain_entry = 1; #endif /* CONFIG_ARCH_HAS_SG_CHAIN */ sg = kcalloc(sg_per_table + chain_entry, sizeof(*sg), GFP_KERNEL); if (!sg) { pr_err("Unable to allocate scatterlist array" " for struct rd_dev\n"); return -ENOMEM; } sg_init_table(sg, sg_per_table + chain_entry); #ifdef CONFIG_ARCH_HAS_SG_CHAIN if (i > 0) { sg_chain(sg_table[i - 1].sg_table, max_sg_per_table + 1, sg); } #endif /* CONFIG_ARCH_HAS_SG_CHAIN */ sg_table[i].sg_table = sg; sg_table[i].rd_sg_count = sg_per_table; sg_table[i].page_start_offset = page_offset; sg_table[i++].page_end_offset = (page_offset + sg_per_table) - 1; for (j = 0; j < sg_per_table; j++) { pg = alloc_pages(GFP_KERNEL, 0); if (!pg) { pr_err("Unable to allocate scatterlist" " pages for struct rd_dev_sg_table\n"); return -ENOMEM; } sg_assign_page(&sg[j], pg); sg[j].length = PAGE_SIZE; p = kmap(pg); memset(p, init_payload, PAGE_SIZE); kunmap(pg); } page_offset += sg_per_table; total_sg_needed -= sg_per_table; } return 0; }