pmem.c (2689B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ 3#include <linux/memremap.h> 4#include <linux/module.h> 5#include <linux/pfn_t.h> 6#include "../nvdimm/pfn.h" 7#include "../nvdimm/nd.h" 8#include "bus.h" 9 10static struct dev_dax *__dax_pmem_probe(struct device *dev) 11{ 12 struct range range; 13 int rc, id, region_id; 14 resource_size_t offset; 15 struct nd_pfn_sb *pfn_sb; 16 struct dev_dax *dev_dax; 17 struct dev_dax_data data; 18 struct nd_namespace_io *nsio; 19 struct dax_region *dax_region; 20 struct dev_pagemap pgmap = { }; 21 struct nd_namespace_common *ndns; 22 struct nd_dax *nd_dax = to_nd_dax(dev); 23 struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; 24 struct nd_region *nd_region = to_nd_region(dev->parent); 25 26 ndns = nvdimm_namespace_common_probe(dev); 27 if (IS_ERR(ndns)) 28 return ERR_CAST(ndns); 29 30 /* parse the 'pfn' info block via ->rw_bytes */ 31 rc = devm_namespace_enable(dev, ndns, nd_info_block_reserve()); 32 if (rc) 33 return ERR_PTR(rc); 34 rc = nvdimm_setup_pfn(nd_pfn, &pgmap); 35 if (rc) 36 return ERR_PTR(rc); 37 devm_namespace_disable(dev, ndns); 38 39 /* reserve the metadata area, device-dax will reserve the data */ 40 pfn_sb = nd_pfn->pfn_sb; 41 offset = le64_to_cpu(pfn_sb->dataoff); 42 nsio = to_nd_namespace_io(&ndns->dev); 43 if (!devm_request_mem_region(dev, nsio->res.start, offset, 44 dev_name(&ndns->dev))) { 45 dev_warn(dev, "could not reserve metadata\n"); 46 return ERR_PTR(-EBUSY); 47 } 48 49 rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); 50 if (rc != 2) 51 return ERR_PTR(-EINVAL); 52 53 /* adjust the dax_region range to the start of data */ 54 range = pgmap.range; 55 range.start += offset; 56 dax_region = alloc_dax_region(dev, region_id, &range, 57 nd_region->target_node, le32_to_cpu(pfn_sb->align), 58 IORESOURCE_DAX_STATIC); 59 if (!dax_region) 60 return ERR_PTR(-ENOMEM); 61 62 data = (struct dev_dax_data) { 63 .dax_region = dax_region, 64 .id = id, 65 .pgmap = &pgmap, 66 .size = range_len(&range), 67 }; 68 dev_dax = devm_create_dev_dax(&data); 69 70 /* child dev_dax instances now own the lifetime of the dax_region */ 71 dax_region_put(dax_region); 72 73 return dev_dax; 74} 75 76static int dax_pmem_probe(struct device *dev) 77{ 78 return PTR_ERR_OR_ZERO(__dax_pmem_probe(dev)); 79} 80 81static struct nd_device_driver dax_pmem_driver = { 82 .probe = dax_pmem_probe, 83 .drv = { 84 .name = "dax_pmem", 85 }, 86 .type = ND_DRIVER_DAX_PMEM, 87}; 88 89static int __init dax_pmem_init(void) 90{ 91 return nd_driver_register(&dax_pmem_driver); 92} 93module_init(dax_pmem_init); 94 95static void __exit dax_pmem_exit(void) 96{ 97 driver_unregister(&dax_pmem_driver.drv); 98} 99module_exit(dax_pmem_exit); 100 101MODULE_LICENSE("GPL v2"); 102MODULE_AUTHOR("Intel Corporation"); 103MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM);