Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 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> |
Dan Williams | 83762cb | 2021-11-15 13:20:57 -0800 | [diff] [blame] | 6 | #include "../nvdimm/pfn.h" |
| 7 | #include "../nvdimm/nd.h" |
| 8 | #include "bus.h" |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 9 | |
Dan Williams | 83762cb | 2021-11-15 13:20:57 -0800 | [diff] [blame] | 10 | static struct dev_dax *__dax_pmem_probe(struct device *dev) |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 11 | { |
Dan Williams | a4574f6 | 2020-10-13 16:50:29 -0700 | [diff] [blame] | 12 | struct range range; |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 13 | int rc, id, region_id; |
| 14 | resource_size_t offset; |
| 15 | struct nd_pfn_sb *pfn_sb; |
Dan Williams | 174ebec | 2020-10-13 16:49:38 -0700 | [diff] [blame] | 16 | struct dev_dax_data data; |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 17 | struct nd_namespace_io *nsio; |
| 18 | struct dax_region *dax_region; |
Christoph Hellwig | 1e240e8 | 2019-06-26 14:27:08 +0200 | [diff] [blame] | 19 | struct dev_pagemap pgmap = { }; |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 20 | struct nd_namespace_common *ndns; |
| 21 | struct nd_dax *nd_dax = to_nd_dax(dev); |
| 22 | struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; |
Dan Williams | 8fc5c73 | 2018-11-09 12:43:07 -0800 | [diff] [blame] | 23 | struct nd_region *nd_region = to_nd_region(dev->parent); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 24 | |
| 25 | ndns = nvdimm_namespace_common_probe(dev); |
| 26 | if (IS_ERR(ndns)) |
| 27 | return ERR_CAST(ndns); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 28 | |
| 29 | /* parse the 'pfn' info block via ->rw_bytes */ |
Aneesh Kumar K.V | 8f4b01f | 2019-10-31 16:27:41 +0530 | [diff] [blame] | 30 | rc = devm_namespace_enable(dev, ndns, nd_info_block_reserve()); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 31 | if (rc) |
| 32 | return ERR_PTR(rc); |
| 33 | rc = nvdimm_setup_pfn(nd_pfn, &pgmap); |
| 34 | if (rc) |
| 35 | return ERR_PTR(rc); |
Aneesh Kumar K.V | 8f4b01f | 2019-10-31 16:27:41 +0530 | [diff] [blame] | 36 | devm_namespace_disable(dev, ndns); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 37 | |
| 38 | /* reserve the metadata area, device-dax will reserve the data */ |
Vishal Verma | d521fba | 2019-03-18 16:53:37 -0600 | [diff] [blame] | 39 | pfn_sb = nd_pfn->pfn_sb; |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 40 | offset = le64_to_cpu(pfn_sb->dataoff); |
Aneesh Kumar K.V | 8f4b01f | 2019-10-31 16:27:41 +0530 | [diff] [blame] | 41 | nsio = to_nd_namespace_io(&ndns->dev); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 42 | if (!devm_request_mem_region(dev, nsio->res.start, offset, |
| 43 | dev_name(&ndns->dev))) { |
Vishal Verma | d521fba | 2019-03-18 16:53:37 -0600 | [diff] [blame] | 44 | dev_warn(dev, "could not reserve metadata\n"); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 45 | return ERR_PTR(-EBUSY); |
Vishal Verma | d521fba | 2019-03-18 16:53:37 -0600 | [diff] [blame] | 46 | } |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 47 | |
| 48 | rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); |
| 49 | if (rc != 2) |
| 50 | return ERR_PTR(-EINVAL); |
| 51 | |
Dan Williams | a4574f6 | 2020-10-13 16:50:29 -0700 | [diff] [blame] | 52 | /* adjust the dax_region range to the start of data */ |
| 53 | range = pgmap.range; |
Zheng Yongjun | 4e6a7b3 | 2020-12-14 21:45:06 +0800 | [diff] [blame] | 54 | range.start += offset; |
Dan Williams | a4574f6 | 2020-10-13 16:50:29 -0700 | [diff] [blame] | 55 | dax_region = alloc_dax_region(dev, region_id, &range, |
Dan Williams | c2f3011 | 2020-10-13 16:50:03 -0700 | [diff] [blame] | 56 | nd_region->target_node, le32_to_cpu(pfn_sb->align), |
| 57 | IORESOURCE_DAX_STATIC); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 58 | if (!dax_region) |
| 59 | return ERR_PTR(-ENOMEM); |
| 60 | |
Dan Williams | 174ebec | 2020-10-13 16:49:38 -0700 | [diff] [blame] | 61 | data = (struct dev_dax_data) { |
| 62 | .dax_region = dax_region, |
| 63 | .id = id, |
| 64 | .pgmap = &pgmap, |
Dan Williams | a4574f6 | 2020-10-13 16:50:29 -0700 | [diff] [blame] | 65 | .size = range_len(&range), |
Dan Williams | 174ebec | 2020-10-13 16:49:38 -0700 | [diff] [blame] | 66 | }; |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 67 | |
Dan Williams | 2532f41 | 2023-06-02 23:14:11 -0700 | [diff] [blame] | 68 | return devm_create_dev_dax(&data); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 69 | } |
Dan Williams | 83762cb | 2021-11-15 13:20:57 -0800 | [diff] [blame] | 70 | |
| 71 | static int dax_pmem_probe(struct device *dev) |
| 72 | { |
| 73 | return PTR_ERR_OR_ZERO(__dax_pmem_probe(dev)); |
| 74 | } |
| 75 | |
| 76 | static struct nd_device_driver dax_pmem_driver = { |
| 77 | .probe = dax_pmem_probe, |
| 78 | .drv = { |
| 79 | .name = "dax_pmem", |
| 80 | }, |
| 81 | .type = ND_DRIVER_DAX_PMEM, |
| 82 | }; |
| 83 | |
| 84 | static int __init dax_pmem_init(void) |
| 85 | { |
| 86 | return nd_driver_register(&dax_pmem_driver); |
| 87 | } |
| 88 | module_init(dax_pmem_init); |
| 89 | |
| 90 | static void __exit dax_pmem_exit(void) |
| 91 | { |
| 92 | driver_unregister(&dax_pmem_driver.drv); |
| 93 | } |
| 94 | module_exit(dax_pmem_exit); |
Dan Williams | 730926c | 2017-07-16 13:51:53 -0700 | [diff] [blame] | 95 | |
| 96 | MODULE_LICENSE("GPL v2"); |
| 97 | MODULE_AUTHOR("Intel Corporation"); |
Dan Williams | 83762cb | 2021-11-15 13:20:57 -0800 | [diff] [blame] | 98 | MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); |