2 * Copyright(c) 2016 Intel Corporation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 #include <linux/pagemap.h>
14 #include <linux/module.h>
15 #include <linux/device.h>
16 #include <linux/pfn_t.h>
17 #include <linux/slab.h>
18 #include <linux/dax.h>
23 static struct class *dax_class;
24 static DEFINE_IDA(dax_minor_ida);
27 * struct dax_region - mapping infrastructure for dax devices
28 * @id: kernel-wide unique region for a memory range
29 * @base: linear address corresponding to @res
30 * @kref: to pin while other agents have a need to do lookups
31 * @dev: parent device backing this region
32 * @align: allocation and mapping alignment for child dax devices
33 * @res: physical address range of the region
34 * @pfn_flags: identify whether the pfns are paged back or not
44 unsigned long pfn_flags;
48 * struct dax_dev - subdivision of a dax region
49 * @region - parent region
50 * @dev - device backing the character device
51 * @kref - enable this data to be tracked in filp->private_data
52 * @id - child id in the region
53 * @num_resources - number of physical address extents in this device
54 * @res - array of physical address ranges
57 struct dax_region *region;
62 struct resource res[0];
65 static void dax_region_free(struct kref *kref)
67 struct dax_region *dax_region;
69 dax_region = container_of(kref, struct dax_region, kref);
73 void dax_region_put(struct dax_region *dax_region)
75 kref_put(&dax_region->kref, dax_region_free);
77 EXPORT_SYMBOL_GPL(dax_region_put);
79 static void dax_dev_free(struct kref *kref)
81 struct dax_dev *dax_dev;
83 dax_dev = container_of(kref, struct dax_dev, kref);
84 dax_region_put(dax_dev->region);
88 static void dax_dev_put(struct dax_dev *dax_dev)
90 kref_put(&dax_dev->kref, dax_dev_free);
93 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
94 struct resource *res, unsigned int align, void *addr,
95 unsigned long pfn_flags)
97 struct dax_region *dax_region;
99 dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL);
104 memcpy(&dax_region->res, res, sizeof(*res));
105 dax_region->pfn_flags = pfn_flags;
106 kref_init(&dax_region->kref);
107 dax_region->id = region_id;
108 ida_init(&dax_region->ida);
109 dax_region->align = align;
110 dax_region->dev = parent;
111 dax_region->base = addr;
115 EXPORT_SYMBOL_GPL(alloc_dax_region);
117 static ssize_t size_show(struct device *dev,
118 struct device_attribute *attr, char *buf)
120 struct dax_dev *dax_dev = dev_get_drvdata(dev);
121 unsigned long long size = 0;
124 for (i = 0; i < dax_dev->num_resources; i++)
125 size += resource_size(&dax_dev->res[i]);
127 return sprintf(buf, "%llu\n", size);
129 static DEVICE_ATTR_RO(size);
131 static struct attribute *dax_device_attributes[] = {
136 static const struct attribute_group dax_device_attribute_group = {
137 .attrs = dax_device_attributes,
140 static const struct attribute_group *dax_attribute_groups[] = {
141 &dax_device_attribute_group,
145 static void unregister_dax_dev(void *_dev)
147 struct device *dev = _dev;
148 struct dax_dev *dax_dev = dev_get_drvdata(dev);
149 struct dax_region *dax_region = dax_dev->region;
151 dev_dbg(dev, "%s\n", __func__);
154 device_unregister(dev);
155 ida_simple_remove(&dax_region->ida, dax_dev->id);
156 ida_simple_remove(&dax_minor_ida, MINOR(dev->devt));
158 dax_dev_put(dax_dev);
161 int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,
164 struct device *parent = dax_region->dev;
165 struct dax_dev *dax_dev;
170 dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL);
173 memcpy(dax_dev->res, res, sizeof(*res) * count);
174 dax_dev->num_resources = count;
175 kref_init(&dax_dev->kref);
176 dax_dev->region = dax_region;
177 kref_get(&dax_region->kref);
179 dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
180 if (dax_dev->id < 0) {
185 minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL);
191 dev_t = MKDEV(dax_major, minor);
192 dev = device_create_with_groups(dax_class, parent, dev_t, dax_dev,
193 dax_attribute_groups, "dax%d.%d", dax_region->id,
201 rc = devm_add_action(dax_region->dev, unregister_dax_dev, dev);
203 unregister_dax_dev(dev);
210 ida_simple_remove(&dax_minor_ida, minor);
212 ida_simple_remove(&dax_region->ida, dax_dev->id);
214 dax_dev_put(dax_dev);
218 EXPORT_SYMBOL_GPL(devm_create_dax_dev);
220 static const struct file_operations dax_fops = {
221 .llseek = noop_llseek,
222 .owner = THIS_MODULE,
225 static int __init dax_init(void)
229 rc = register_chrdev(0, "dax", &dax_fops);
234 dax_class = class_create(THIS_MODULE, "dax");
235 if (IS_ERR(dax_class)) {
236 unregister_chrdev(dax_major, "dax");
237 return PTR_ERR(dax_class);
243 static void __exit dax_exit(void)
245 class_destroy(dax_class);
246 unregister_chrdev(dax_major, "dax");
247 ida_destroy(&dax_minor_ida);
250 MODULE_AUTHOR("Intel Corporation");
251 MODULE_LICENSE("GPL v2");
252 subsys_initcall(dax_init);
253 module_exit(dax_exit);