From: Boaz Harrosh <boaz@xxxxxxxxxxxxx> This patch removes any global memory information. And lets each pmem-device manage it's own memory region. pmem_alloc() Now receives phys_addr and disk_size and will map that region, also pmem_free will do the unmaping. This is so we can support multiple discontinuous memory regions in the next patch Signed-off-by: Boaz Harrosh <boaz@xxxxxxxxxxxxx> --- drivers/block/pmem.c | 122 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 47 deletions(-) diff --git a/drivers/block/pmem.c b/drivers/block/pmem.c index 499536c..d5c5c52 100644 --- a/drivers/block/pmem.c +++ b/drivers/block/pmem.c @@ -27,19 +27,12 @@ #define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) #define PAGE_SECTORS (1 << PAGE_SECTORS_SHIFT) -/* - * driver-wide physical address and total_size - one single, contiguous memory - * region that we divide up in to same-sized devices - */ -phys_addr_t phys_addr; -void *virt_addr; -size_t total_size; - struct pmem_device { struct request_queue *pmem_queue; struct gendisk *pmem_disk; struct list_head pmem_list; + /* One contiguous memory region per device */ phys_addr_t phys_addr; void *virt_addr; size_t size; @@ -234,26 +227,70 @@ MODULE_PARM_DESC(pmem_count, "Number of pmem devices to evenly split allocated s static LIST_HEAD(pmem_devices); static int pmem_major; -/* FIXME: move phys_addr, virt_addr, size calls up to caller */ -static struct pmem_device *pmem_alloc(int i) +/* pmem->phys_addr and pmem->size need to be set. + * Will then set virt_addr if successful. + */ +int pmem_mapmem(struct pmem_device *pmem) +{ + struct resource *res_mem; + int err; + + res_mem = request_mem_region_exclusive(pmem->phys_addr, pmem->size, + "pmem"); + if (!res_mem) { + pr_warn("pmem: request_mem_region_exclusive phys=0x%llx size=0x%zx failed\n", + pmem->phys_addr, pmem->size); + return -EINVAL; + } + + pmem->virt_addr = ioremap_cache(pmem->phys_addr, pmem->size); + if (unlikely(!pmem->virt_addr)) { + err = -ENXIO; + goto out_release; + } + return 0; + +out_release: + release_mem_region(pmem->phys_addr, pmem->size); + return err; +} + +void pmem_unmapmem(struct pmem_device *pmem) +{ + if (unlikely(!pmem->virt_addr)) + return; + + iounmap(pmem->virt_addr); + release_mem_region(pmem->phys_addr, pmem->size); + pmem->virt_addr = NULL; +} + +static struct pmem_device *pmem_alloc(phys_addr_t phys_addr, size_t disk_size, + int i) { struct pmem_device *pmem; struct gendisk *disk; - size_t disk_size = total_size / pmem_count; - size_t disk_sectors = disk_size / 512; + int err; pmem = kzalloc(sizeof(*pmem), GFP_KERNEL); - if (!pmem) + if (unlikely(!pmem)) { + err = -ENOMEM; goto out; + } - pmem->phys_addr = phys_addr + i * disk_size; - pmem->virt_addr = virt_addr + i * disk_size; + pmem->phys_addr = phys_addr; pmem->size = disk_size; - pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL); - if (!pmem->pmem_queue) + err = pmem_mapmem(pmem); + if (unlikely(err)) goto out_free_dev; + pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL); + if (unlikely(!pmem->pmem_queue)) { + err = -ENOMEM; + goto out_unmap; + } + blk_queue_make_request(pmem->pmem_queue, pmem_make_request); blk_queue_max_hw_sectors(pmem->pmem_queue, 1024); blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY); @@ -264,9 +301,12 @@ static struct pmem_device *pmem_alloc(int i) blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE); pmem->pmem_queue->limits.io_min = 512; /* Don't use the accessor */ - disk = pmem->pmem_disk = alloc_disk(0); - if (!disk) + disk = alloc_disk(0); + if (unlikely(!disk)) { + err = -ENOMEM; goto out_free_queue; + } + disk->major = pmem_major; disk->first_minor = 0; disk->fops = &pmem_fops; @@ -274,22 +314,26 @@ static struct pmem_device *pmem_alloc(int i) disk->queue = pmem->pmem_queue; disk->flags = GENHD_FL_EXT_DEVT; sprintf(disk->disk_name, "pmem%d", i); - set_capacity(disk, disk_sectors); + set_capacity(disk, disk_size >> SECTOR_SHIFT); + pmem->pmem_disk = disk; return pmem; out_free_queue: blk_cleanup_queue(pmem->pmem_queue); +out_unmap: + pmem_unmapmem(pmem); out_free_dev: kfree(pmem); out: - return NULL; + return ERR_PTR(err); } static void pmem_free(struct pmem_device *pmem) { put_disk(pmem->pmem_disk); blk_cleanup_queue(pmem->pmem_queue); + pmem_unmapmem(pmem); kfree(pmem); } @@ -303,36 +347,28 @@ static void pmem_del_one(struct pmem_device *pmem) static int __init pmem_init(void) { int result, i; - struct resource *res_mem; struct pmem_device *pmem, *next; + phys_addr_t phys_addr; + size_t total_size, disk_size; phys_addr = (phys_addr_t) pmem_start_gb * 1024 * 1024 * 1024; total_size = (size_t) pmem_size_gb * 1024 * 1024 * 1024; - - res_mem = request_mem_region_exclusive(phys_addr, total_size, "pmem"); - if (!res_mem) - return -ENOMEM; - - virt_addr = ioremap_cache(phys_addr, total_size); - if (!virt_addr) { - result = -ENOMEM; - goto out_release; - } + disk_size = total_size / pmem_count; result = register_blkdev(0, "pmem"); - if (result < 0) { - result = -EIO; - goto out_unmap; - } else + if (result < 0) + return -EIO; + else pmem_major = result; for (i = 0; i < pmem_count; i++) { - pmem = pmem_alloc(i); - if (!pmem) { - result = -ENOMEM; + pmem = pmem_alloc(phys_addr, disk_size, i); + if (IS_ERR(pmem)) { + result = PTR_ERR(pmem); goto out_free; } list_add_tail(&pmem->pmem_list, &pmem_devices); + phys_addr += disk_size; } list_for_each_entry(pmem, &pmem_devices, pmem_list) @@ -348,11 +384,6 @@ out_free: } unregister_blkdev(pmem_major, "pmem"); -out_unmap: - iounmap(virt_addr); - -out_release: - release_mem_region(phys_addr, total_size); return result; } @@ -364,9 +395,6 @@ static void __exit pmem_exit(void) pmem_del_one(pmem); unregister_blkdev(pmem_major, "pmem"); - iounmap(virt_addr); - release_mem_region(phys_addr, total_size); - pr_info("pmem: module unloaded\n"); } -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html