aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dax/dax.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dax/dax.c')
-rw-r--r--drivers/dax/dax.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 26ec39ddf21f..ed758b74ddf0 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -75,6 +75,73 @@ struct dax_dev {
75 struct resource res[0]; 75 struct resource res[0];
76}; 76};
77 77
78static ssize_t id_show(struct device *dev,
79 struct device_attribute *attr, char *buf)
80{
81 struct dax_region *dax_region;
82 ssize_t rc = -ENXIO;
83
84 device_lock(dev);
85 dax_region = dev_get_drvdata(dev);
86 if (dax_region)
87 rc = sprintf(buf, "%d\n", dax_region->id);
88 device_unlock(dev);
89
90 return rc;
91}
92static DEVICE_ATTR_RO(id);
93
94static ssize_t region_size_show(struct device *dev,
95 struct device_attribute *attr, char *buf)
96{
97 struct dax_region *dax_region;
98 ssize_t rc = -ENXIO;
99
100 device_lock(dev);
101 dax_region = dev_get_drvdata(dev);
102 if (dax_region)
103 rc = sprintf(buf, "%llu\n", (unsigned long long)
104 resource_size(&dax_region->res));
105 device_unlock(dev);
106
107 return rc;
108}
109static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
110 region_size_show, NULL);
111
112static ssize_t align_show(struct device *dev,
113 struct device_attribute *attr, char *buf)
114{
115 struct dax_region *dax_region;
116 ssize_t rc = -ENXIO;
117
118 device_lock(dev);
119 dax_region = dev_get_drvdata(dev);
120 if (dax_region)
121 rc = sprintf(buf, "%u\n", dax_region->align);
122 device_unlock(dev);
123
124 return rc;
125}
126static DEVICE_ATTR_RO(align);
127
128static struct attribute *dax_region_attributes[] = {
129 &dev_attr_region_size.attr,
130 &dev_attr_align.attr,
131 &dev_attr_id.attr,
132 NULL,
133};
134
135static const struct attribute_group dax_region_attribute_group = {
136 .name = "dax_region",
137 .attrs = dax_region_attributes,
138};
139
140static const struct attribute_group *dax_region_attribute_groups[] = {
141 &dax_region_attribute_group,
142 NULL,
143};
144
78static struct inode *dax_alloc_inode(struct super_block *sb) 145static struct inode *dax_alloc_inode(struct super_block *sb)
79{ 146{
80 return kmem_cache_alloc(dax_cache, GFP_KERNEL); 147 return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
200} 267}
201EXPORT_SYMBOL_GPL(dax_region_put); 268EXPORT_SYMBOL_GPL(dax_region_put);
202 269
270static void dax_region_unregister(void *region)
271{
272 struct dax_region *dax_region = region;
273
274 sysfs_remove_groups(&dax_region->dev->kobj,
275 dax_region_attribute_groups);
276 dax_region_put(dax_region);
277}
278
203struct dax_region *alloc_dax_region(struct device *parent, int region_id, 279struct dax_region *alloc_dax_region(struct device *parent, int region_id,
204 struct resource *res, unsigned int align, void *addr, 280 struct resource *res, unsigned int align, void *addr,
205 unsigned long pfn_flags) 281 unsigned long pfn_flags)
206{ 282{
207 struct dax_region *dax_region; 283 struct dax_region *dax_region;
208 284
285 /*
286 * The DAX core assumes that it can store its private data in
287 * parent->driver_data. This WARN is a reminder / safeguard for
288 * developers of device-dax drivers.
289 */
290 if (dev_get_drvdata(parent)) {
291 dev_WARN(parent, "dax core failed to setup private data\n");
292 return NULL;
293 }
294
209 if (!IS_ALIGNED(res->start, align) 295 if (!IS_ALIGNED(res->start, align)
210 || !IS_ALIGNED(resource_size(res), align)) 296 || !IS_ALIGNED(resource_size(res), align))
211 return NULL; 297 return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
214 if (!dax_region) 300 if (!dax_region)
215 return NULL; 301 return NULL;
216 302
303 dev_set_drvdata(parent, dax_region);
217 memcpy(&dax_region->res, res, sizeof(*res)); 304 memcpy(&dax_region->res, res, sizeof(*res));
218 dax_region->pfn_flags = pfn_flags; 305 dax_region->pfn_flags = pfn_flags;
219 kref_init(&dax_region->kref); 306 kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
222 dax_region->align = align; 309 dax_region->align = align;
223 dax_region->dev = parent; 310 dax_region->dev = parent;
224 dax_region->base = addr; 311 dax_region->base = addr;
312 if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
313 kfree(dax_region);
314 return NULL;;
315 }
225 316
317 kref_get(&dax_region->kref);
318 if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
319 return NULL;
226 return dax_region; 320 return dax_region;
227} 321}
228EXPORT_SYMBOL_GPL(alloc_dax_region); 322EXPORT_SYMBOL_GPL(alloc_dax_region);