151cf784cSDan Williams // SPDX-License-Identifier: GPL-2.0
251cf784cSDan Williams /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */
389ec9f2cSDan Williams #include <linux/memremap.h>
451cf784cSDan Williams #include <linux/device.h>
5d200781eSDan Williams #include <linux/mutex.h>
6d200781eSDan Williams #include <linux/list.h>
751cf784cSDan Williams #include <linux/slab.h>
851cf784cSDan Williams #include <linux/dax.h>
9fcffb6a1SDan Williams #include <linux/io.h>
1051cf784cSDan Williams #include "dax-private.h"
1151cf784cSDan Williams #include "bus.h"
1251cf784cSDan Williams
13d200781eSDan Williams static DEFINE_MUTEX(dax_bus_lock);
14d200781eSDan Williams
15d200781eSDan Williams #define DAX_NAME_LEN 30
16d200781eSDan Williams struct dax_id {
17d200781eSDan Williams struct list_head list;
18d200781eSDan Williams char dev_name[DAX_NAME_LEN];
19d200781eSDan Williams };
20d200781eSDan Williams
dax_bus_uevent(const struct device * dev,struct kobj_uevent_env * env)212a81ada3SGreg Kroah-Hartman static int dax_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
229567da0bSDan Williams {
239567da0bSDan Williams /*
249567da0bSDan Williams * We only ever expect to handle device-dax instances, i.e. the
259567da0bSDan Williams * @type argument to MODULE_ALIAS_DAX_DEVICE() is always zero
269567da0bSDan Williams */
279567da0bSDan Williams return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0);
289567da0bSDan Williams }
299567da0bSDan Williams
to_dax_drv(struct device_driver * drv)30d200781eSDan Williams static struct dax_device_driver *to_dax_drv(struct device_driver *drv)
31d200781eSDan Williams {
32d200781eSDan Williams return container_of(drv, struct dax_device_driver, drv);
33d200781eSDan Williams }
34d200781eSDan Williams
__dax_match_id(struct dax_device_driver * dax_drv,const char * dev_name)35d200781eSDan Williams static struct dax_id *__dax_match_id(struct dax_device_driver *dax_drv,
36d200781eSDan Williams const char *dev_name)
37d200781eSDan Williams {
38d200781eSDan Williams struct dax_id *dax_id;
39d200781eSDan Williams
40d200781eSDan Williams lockdep_assert_held(&dax_bus_lock);
41d200781eSDan Williams
42d200781eSDan Williams list_for_each_entry(dax_id, &dax_drv->ids, list)
43d200781eSDan Williams if (sysfs_streq(dax_id->dev_name, dev_name))
44d200781eSDan Williams return dax_id;
45d200781eSDan Williams return NULL;
46d200781eSDan Williams }
47d200781eSDan Williams
dax_match_id(struct dax_device_driver * dax_drv,struct device * dev)48d200781eSDan Williams static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev)
49d200781eSDan Williams {
50d200781eSDan Williams int match;
51d200781eSDan Williams
52d200781eSDan Williams mutex_lock(&dax_bus_lock);
53d200781eSDan Williams match = !!__dax_match_id(dax_drv, dev_name(dev));
54d200781eSDan Williams mutex_unlock(&dax_bus_lock);
55d200781eSDan Williams
56d200781eSDan Williams return match;
57d200781eSDan Williams }
58d200781eSDan Williams
dax_match_type(struct dax_device_driver * dax_drv,struct device * dev)59e9ee9fe3SDan Williams static int dax_match_type(struct dax_device_driver *dax_drv, struct device *dev)
60e9ee9fe3SDan Williams {
61e9ee9fe3SDan Williams enum dax_driver_type type = DAXDRV_DEVICE_TYPE;
62e9ee9fe3SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
63e9ee9fe3SDan Williams
64e9ee9fe3SDan Williams if (dev_dax->region->res.flags & IORESOURCE_DAX_KMEM)
65e9ee9fe3SDan Williams type = DAXDRV_KMEM_TYPE;
66e9ee9fe3SDan Williams
67e9ee9fe3SDan Williams if (dax_drv->type == type)
68e9ee9fe3SDan Williams return 1;
69e9ee9fe3SDan Williams
70e9ee9fe3SDan Williams /* default to device mode if dax_kmem is disabled */
71e9ee9fe3SDan Williams if (dax_drv->type == DAXDRV_DEVICE_TYPE &&
72e9ee9fe3SDan Williams !IS_ENABLED(CONFIG_DEV_DAX_KMEM))
73e9ee9fe3SDan Williams return 1;
74e9ee9fe3SDan Williams
75e9ee9fe3SDan Williams return 0;
76e9ee9fe3SDan Williams }
77e9ee9fe3SDan Williams
78664525b2SDan Williams enum id_action {
79664525b2SDan Williams ID_REMOVE,
80664525b2SDan Williams ID_ADD,
81664525b2SDan Williams };
82664525b2SDan Williams
do_id_store(struct device_driver * drv,const char * buf,size_t count,enum id_action action)83d200781eSDan Williams static ssize_t do_id_store(struct device_driver *drv, const char *buf,
84664525b2SDan Williams size_t count, enum id_action action)
85d200781eSDan Williams {
86d200781eSDan Williams struct dax_device_driver *dax_drv = to_dax_drv(drv);
87d200781eSDan Williams unsigned int region_id, id;
88d200781eSDan Williams char devname[DAX_NAME_LEN];
89d200781eSDan Williams struct dax_id *dax_id;
90d200781eSDan Williams ssize_t rc = count;
91d200781eSDan Williams int fields;
92d200781eSDan Williams
93d200781eSDan Williams fields = sscanf(buf, "dax%d.%d", ®ion_id, &id);
94d200781eSDan Williams if (fields != 2)
95d200781eSDan Williams return -EINVAL;
96d200781eSDan Williams sprintf(devname, "dax%d.%d", region_id, id);
97d200781eSDan Williams if (!sysfs_streq(buf, devname))
98d200781eSDan Williams return -EINVAL;
99d200781eSDan Williams
100d200781eSDan Williams mutex_lock(&dax_bus_lock);
101d200781eSDan Williams dax_id = __dax_match_id(dax_drv, buf);
102d200781eSDan Williams if (!dax_id) {
103664525b2SDan Williams if (action == ID_ADD) {
104d200781eSDan Williams dax_id = kzalloc(sizeof(*dax_id), GFP_KERNEL);
105d200781eSDan Williams if (dax_id) {
106d200781eSDan Williams strncpy(dax_id->dev_name, buf, DAX_NAME_LEN);
107d200781eSDan Williams list_add(&dax_id->list, &dax_drv->ids);
108d200781eSDan Williams } else
109d200781eSDan Williams rc = -ENOMEM;
1109de82caaSArnd Bergmann }
111664525b2SDan Williams } else if (action == ID_REMOVE) {
112d200781eSDan Williams list_del(&dax_id->list);
113d200781eSDan Williams kfree(dax_id);
1149de82caaSArnd Bergmann }
115d200781eSDan Williams mutex_unlock(&dax_bus_lock);
116664525b2SDan Williams
117664525b2SDan Williams if (rc < 0)
118d200781eSDan Williams return rc;
119664525b2SDan Williams if (action == ID_ADD)
120664525b2SDan Williams rc = driver_attach(drv);
121664525b2SDan Williams if (rc)
122664525b2SDan Williams return rc;
123664525b2SDan Williams return count;
124d200781eSDan Williams }
125d200781eSDan Williams
new_id_store(struct device_driver * drv,const char * buf,size_t count)126d200781eSDan Williams static ssize_t new_id_store(struct device_driver *drv, const char *buf,
127d200781eSDan Williams size_t count)
128d200781eSDan Williams {
129664525b2SDan Williams return do_id_store(drv, buf, count, ID_ADD);
130d200781eSDan Williams }
131d200781eSDan Williams static DRIVER_ATTR_WO(new_id);
132d200781eSDan Williams
remove_id_store(struct device_driver * drv,const char * buf,size_t count)133d200781eSDan Williams static ssize_t remove_id_store(struct device_driver *drv, const char *buf,
134d200781eSDan Williams size_t count)
135d200781eSDan Williams {
136664525b2SDan Williams return do_id_store(drv, buf, count, ID_REMOVE);
137d200781eSDan Williams }
138d200781eSDan Williams static DRIVER_ATTR_WO(remove_id);
139d200781eSDan Williams
140d200781eSDan Williams static struct attribute *dax_drv_attrs[] = {
141d200781eSDan Williams &driver_attr_new_id.attr,
142d200781eSDan Williams &driver_attr_remove_id.attr,
143d200781eSDan Williams NULL,
144d200781eSDan Williams };
145d200781eSDan Williams ATTRIBUTE_GROUPS(dax_drv);
146d200781eSDan Williams
1479567da0bSDan Williams static int dax_bus_match(struct device *dev, struct device_driver *drv);
1489567da0bSDan Williams
149fc65c4ebSJoao Martins /*
150fc65c4ebSJoao Martins * Static dax regions are regions created by an external subsystem
151fc65c4ebSJoao Martins * nvdimm where a single range is assigned. Its boundaries are by the external
152fc65c4ebSJoao Martins * subsystem and are usually limited to one physical memory range. For example,
153fc65c4ebSJoao Martins * for PMEM it is usually defined by NVDIMM Namespace boundaries (i.e. a
154fc65c4ebSJoao Martins * single contiguous range)
155fc65c4ebSJoao Martins *
156fc65c4ebSJoao Martins * On dynamic dax regions, the assigned region can be partitioned by dax core
157fc65c4ebSJoao Martins * into multiple subdivisions. A subdivision is represented into one
158fc65c4ebSJoao Martins * /dev/daxN.M device composed by one or more potentially discontiguous ranges.
159fc65c4ebSJoao Martins *
160fc65c4ebSJoao Martins * When allocating a dax region, drivers must set whether it's static
161fc65c4ebSJoao Martins * (IORESOURCE_DAX_STATIC). On static dax devices, the @pgmap is pre-assigned
162fc65c4ebSJoao Martins * to dax core when calling devm_create_dev_dax(), whereas in dynamic dax
163fc65c4ebSJoao Martins * devices it is NULL but afterwards allocated by dax core on device ->probe().
164fc65c4ebSJoao Martins * Care is needed to make sure that dynamic dax devices are torn down with a
165fc65c4ebSJoao Martins * cleared @pgmap field (see kill_dev_dax()).
166fc65c4ebSJoao Martins */
is_static(struct dax_region * dax_region)167c2f3011eSDan Williams static bool is_static(struct dax_region *dax_region)
168c2f3011eSDan Williams {
169c2f3011eSDan Williams return (dax_region->res.flags & IORESOURCE_DAX_STATIC) != 0;
170c2f3011eSDan Williams }
171c2f3011eSDan Williams
static_dev_dax(struct dev_dax * dev_dax)172fc65c4ebSJoao Martins bool static_dev_dax(struct dev_dax *dev_dax)
173fc65c4ebSJoao Martins {
174fc65c4ebSJoao Martins return is_static(dev_dax->region);
175fc65c4ebSJoao Martins }
176fc65c4ebSJoao Martins EXPORT_SYMBOL_GPL(static_dev_dax);
177fc65c4ebSJoao Martins
dev_dax_size(struct dev_dax * dev_dax)17860e93dc0SDan Williams static u64 dev_dax_size(struct dev_dax *dev_dax)
17960e93dc0SDan Williams {
18060e93dc0SDan Williams u64 size = 0;
18160e93dc0SDan Williams int i;
18260e93dc0SDan Williams
18360e93dc0SDan Williams device_lock_assert(&dev_dax->dev);
18460e93dc0SDan Williams
18560e93dc0SDan Williams for (i = 0; i < dev_dax->nr_range; i++)
18660e93dc0SDan Williams size += range_len(&dev_dax->ranges[i].range);
18760e93dc0SDan Williams
18860e93dc0SDan Williams return size;
18960e93dc0SDan Williams }
19060e93dc0SDan Williams
dax_bus_probe(struct device * dev)191f11cf813SDan Williams static int dax_bus_probe(struct device *dev)
192f11cf813SDan Williams {
193f11cf813SDan Williams struct dax_device_driver *dax_drv = to_dax_drv(dev->driver);
194f11cf813SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
1950f3da14aSDan Williams struct dax_region *dax_region = dev_dax->region;
1960f3da14aSDan Williams int rc;
197f11cf813SDan Williams
19860e93dc0SDan Williams if (dev_dax_size(dev_dax) == 0 || dev_dax->id < 0)
1990f3da14aSDan Williams return -ENXIO;
2000f3da14aSDan Williams
2010f3da14aSDan Williams rc = dax_drv->probe(dev_dax);
2020f3da14aSDan Williams
2030f3da14aSDan Williams if (rc || is_static(dax_region))
2040f3da14aSDan Williams return rc;
2050f3da14aSDan Williams
2060f3da14aSDan Williams /*
2070f3da14aSDan Williams * Track new seed creation only after successful probe of the
2080f3da14aSDan Williams * previous seed.
2090f3da14aSDan Williams */
2100f3da14aSDan Williams if (dax_region->seed == dev)
2110f3da14aSDan Williams dax_region->seed = NULL;
2120f3da14aSDan Williams
2130f3da14aSDan Williams return 0;
214f11cf813SDan Williams }
215f11cf813SDan Williams
dax_bus_remove(struct device * dev)216fc7a6209SUwe Kleine-König static void dax_bus_remove(struct device *dev)
217f11cf813SDan Williams {
218f11cf813SDan Williams struct dax_device_driver *dax_drv = to_dax_drv(dev->driver);
219f11cf813SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
220f11cf813SDan Williams
2218029968eSUwe Kleine-König if (dax_drv->remove)
2220d519e0dSUwe Kleine-König dax_drv->remove(dev_dax);
223f11cf813SDan Williams }
224f11cf813SDan Williams
2259567da0bSDan Williams static struct bus_type dax_bus_type = {
2269567da0bSDan Williams .name = "dax",
2279567da0bSDan Williams .uevent = dax_bus_uevent,
2289567da0bSDan Williams .match = dax_bus_match,
229f11cf813SDan Williams .probe = dax_bus_probe,
230f11cf813SDan Williams .remove = dax_bus_remove,
231d200781eSDan Williams .drv_groups = dax_drv_groups,
2329567da0bSDan Williams };
2339567da0bSDan Williams
dax_bus_match(struct device * dev,struct device_driver * drv)2349567da0bSDan Williams static int dax_bus_match(struct device *dev, struct device_driver *drv)
2359567da0bSDan Williams {
236d200781eSDan Williams struct dax_device_driver *dax_drv = to_dax_drv(drv);
237d200781eSDan Williams
238e9ee9fe3SDan Williams if (dax_match_id(dax_drv, dev))
2399567da0bSDan Williams return 1;
240e9ee9fe3SDan Williams return dax_match_type(dax_drv, dev);
2419567da0bSDan Williams }
2429567da0bSDan Williams
24351cf784cSDan Williams /*
24451cf784cSDan Williams * Rely on the fact that drvdata is set before the attributes are
24551cf784cSDan Williams * registered, and that the attributes are unregistered before drvdata
24651cf784cSDan Williams * is cleared to assume that drvdata is always valid.
24751cf784cSDan Williams */
id_show(struct device * dev,struct device_attribute * attr,char * buf)24851cf784cSDan Williams static ssize_t id_show(struct device *dev,
24951cf784cSDan Williams struct device_attribute *attr, char *buf)
25051cf784cSDan Williams {
25151cf784cSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
25251cf784cSDan Williams
25351cf784cSDan Williams return sprintf(buf, "%d\n", dax_region->id);
25451cf784cSDan Williams }
25551cf784cSDan Williams static DEVICE_ATTR_RO(id);
25651cf784cSDan Williams
region_size_show(struct device * dev,struct device_attribute * attr,char * buf)25751cf784cSDan Williams static ssize_t region_size_show(struct device *dev,
25851cf784cSDan Williams struct device_attribute *attr, char *buf)
25951cf784cSDan Williams {
26051cf784cSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
26151cf784cSDan Williams
26251cf784cSDan Williams return sprintf(buf, "%llu\n", (unsigned long long)
26351cf784cSDan Williams resource_size(&dax_region->res));
26451cf784cSDan Williams }
26551cf784cSDan Williams static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
26651cf784cSDan Williams region_size_show, NULL);
26751cf784cSDan Williams
region_align_show(struct device * dev,struct device_attribute * attr,char * buf)2686d82120fSDan Williams static ssize_t region_align_show(struct device *dev,
26951cf784cSDan Williams struct device_attribute *attr, char *buf)
27051cf784cSDan Williams {
27151cf784cSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
27251cf784cSDan Williams
27351cf784cSDan Williams return sprintf(buf, "%u\n", dax_region->align);
27451cf784cSDan Williams }
2756d82120fSDan Williams static struct device_attribute dev_attr_region_align =
2766d82120fSDan Williams __ATTR(align, 0400, region_align_show, NULL);
27751cf784cSDan Williams
278c2f3011eSDan Williams #define for_each_dax_region_resource(dax_region, res) \
279c2f3011eSDan Williams for (res = (dax_region)->res.child; res; res = res->sibling)
280c2f3011eSDan Williams
dax_region_avail_size(struct dax_region * dax_region)281c2f3011eSDan Williams static unsigned long long dax_region_avail_size(struct dax_region *dax_region)
282c2f3011eSDan Williams {
283c2f3011eSDan Williams resource_size_t size = resource_size(&dax_region->res);
284c2f3011eSDan Williams struct resource *res;
285c2f3011eSDan Williams
286c2f3011eSDan Williams device_lock_assert(dax_region->dev);
287c2f3011eSDan Williams
288c2f3011eSDan Williams for_each_dax_region_resource(dax_region, res)
289c2f3011eSDan Williams size -= resource_size(res);
290c2f3011eSDan Williams return size;
291c2f3011eSDan Williams }
292c2f3011eSDan Williams
available_size_show(struct device * dev,struct device_attribute * attr,char * buf)293c2f3011eSDan Williams static ssize_t available_size_show(struct device *dev,
294c2f3011eSDan Williams struct device_attribute *attr, char *buf)
295c2f3011eSDan Williams {
296c2f3011eSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
297c2f3011eSDan Williams unsigned long long size;
298c2f3011eSDan Williams
299c2f3011eSDan Williams device_lock(dev);
300c2f3011eSDan Williams size = dax_region_avail_size(dax_region);
301c2f3011eSDan Williams device_unlock(dev);
302c2f3011eSDan Williams
303c2f3011eSDan Williams return sprintf(buf, "%llu\n", size);
304c2f3011eSDan Williams }
305c2f3011eSDan Williams static DEVICE_ATTR_RO(available_size);
306c2f3011eSDan Williams
seed_show(struct device * dev,struct device_attribute * attr,char * buf)3070f3da14aSDan Williams static ssize_t seed_show(struct device *dev,
3080f3da14aSDan Williams struct device_attribute *attr, char *buf)
3090f3da14aSDan Williams {
3100f3da14aSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
3110f3da14aSDan Williams struct device *seed;
3120f3da14aSDan Williams ssize_t rc;
3130f3da14aSDan Williams
3140f3da14aSDan Williams if (is_static(dax_region))
3150f3da14aSDan Williams return -EINVAL;
3160f3da14aSDan Williams
3170f3da14aSDan Williams device_lock(dev);
3180f3da14aSDan Williams seed = dax_region->seed;
3190f3da14aSDan Williams rc = sprintf(buf, "%s\n", seed ? dev_name(seed) : "");
3200f3da14aSDan Williams device_unlock(dev);
3210f3da14aSDan Williams
3220f3da14aSDan Williams return rc;
3230f3da14aSDan Williams }
3240f3da14aSDan Williams static DEVICE_ATTR_RO(seed);
3250f3da14aSDan Williams
create_show(struct device * dev,struct device_attribute * attr,char * buf)3260f3da14aSDan Williams static ssize_t create_show(struct device *dev,
3270f3da14aSDan Williams struct device_attribute *attr, char *buf)
3280f3da14aSDan Williams {
3290f3da14aSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
3300f3da14aSDan Williams struct device *youngest;
3310f3da14aSDan Williams ssize_t rc;
3320f3da14aSDan Williams
3330f3da14aSDan Williams if (is_static(dax_region))
3340f3da14aSDan Williams return -EINVAL;
3350f3da14aSDan Williams
3360f3da14aSDan Williams device_lock(dev);
3370f3da14aSDan Williams youngest = dax_region->youngest;
3380f3da14aSDan Williams rc = sprintf(buf, "%s\n", youngest ? dev_name(youngest) : "");
3390f3da14aSDan Williams device_unlock(dev);
3400f3da14aSDan Williams
3410f3da14aSDan Williams return rc;
3420f3da14aSDan Williams }
3430f3da14aSDan Williams
create_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)3440f3da14aSDan Williams static ssize_t create_store(struct device *dev, struct device_attribute *attr,
3450f3da14aSDan Williams const char *buf, size_t len)
3460f3da14aSDan Williams {
3470f3da14aSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
3480f3da14aSDan Williams unsigned long long avail;
3490f3da14aSDan Williams ssize_t rc;
3500f3da14aSDan Williams int val;
3510f3da14aSDan Williams
3520f3da14aSDan Williams if (is_static(dax_region))
3530f3da14aSDan Williams return -EINVAL;
3540f3da14aSDan Williams
3550f3da14aSDan Williams rc = kstrtoint(buf, 0, &val);
3560f3da14aSDan Williams if (rc)
3570f3da14aSDan Williams return rc;
3580f3da14aSDan Williams if (val != 1)
3590f3da14aSDan Williams return -EINVAL;
3600f3da14aSDan Williams
3610f3da14aSDan Williams device_lock(dev);
3620f3da14aSDan Williams avail = dax_region_avail_size(dax_region);
3630f3da14aSDan Williams if (avail == 0)
3640f3da14aSDan Williams rc = -ENOSPC;
3650f3da14aSDan Williams else {
3660f3da14aSDan Williams struct dev_dax_data data = {
3670f3da14aSDan Williams .dax_region = dax_region,
3680f3da14aSDan Williams .size = 0,
3690f3da14aSDan Williams .id = -1,
3700f3da14aSDan Williams };
3710f3da14aSDan Williams struct dev_dax *dev_dax = devm_create_dev_dax(&data);
3720f3da14aSDan Williams
3730f3da14aSDan Williams if (IS_ERR(dev_dax))
3740f3da14aSDan Williams rc = PTR_ERR(dev_dax);
3750f3da14aSDan Williams else {
3760f3da14aSDan Williams /*
3770f3da14aSDan Williams * In support of crafting multiple new devices
3780f3da14aSDan Williams * simultaneously multiple seeds can be created,
3790f3da14aSDan Williams * but only the first one that has not been
3800f3da14aSDan Williams * successfully bound is tracked as the region
3810f3da14aSDan Williams * seed.
3820f3da14aSDan Williams */
3830f3da14aSDan Williams if (!dax_region->seed)
3840f3da14aSDan Williams dax_region->seed = &dev_dax->dev;
3850f3da14aSDan Williams dax_region->youngest = &dev_dax->dev;
3860f3da14aSDan Williams rc = len;
3870f3da14aSDan Williams }
3880f3da14aSDan Williams }
3890f3da14aSDan Williams device_unlock(dev);
3900f3da14aSDan Williams
3910f3da14aSDan Williams return rc;
3920f3da14aSDan Williams }
3930f3da14aSDan Williams static DEVICE_ATTR_RW(create);
3940f3da14aSDan Williams
kill_dev_dax(struct dev_dax * dev_dax)3950f3da14aSDan Williams void kill_dev_dax(struct dev_dax *dev_dax)
3960f3da14aSDan Williams {
3970f3da14aSDan Williams struct dax_device *dax_dev = dev_dax->dax_dev;
3980f3da14aSDan Williams struct inode *inode = dax_inode(dax_dev);
3990f3da14aSDan Williams
4000f3da14aSDan Williams kill_dax(dax_dev);
4010f3da14aSDan Williams unmap_mapping_range(inode->i_mapping, 0, 0, 1);
402fc65c4ebSJoao Martins
403fc65c4ebSJoao Martins /*
404fc65c4ebSJoao Martins * Dynamic dax region have the pgmap allocated via dev_kzalloc()
405fc65c4ebSJoao Martins * and thus freed by devm. Clear the pgmap to not have stale pgmap
406fc65c4ebSJoao Martins * ranges on probe() from previous reconfigurations of region devices.
407fc65c4ebSJoao Martins */
408fc65c4ebSJoao Martins if (!static_dev_dax(dev_dax))
409fc65c4ebSJoao Martins dev_dax->pgmap = NULL;
4100f3da14aSDan Williams }
4110f3da14aSDan Williams EXPORT_SYMBOL_GPL(kill_dev_dax);
4120f3da14aSDan Williams
trim_dev_dax_range(struct dev_dax * dev_dax)4136268d7daSDan Williams static void trim_dev_dax_range(struct dev_dax *dev_dax)
4140f3da14aSDan Williams {
4156268d7daSDan Williams int i = dev_dax->nr_range - 1;
4166268d7daSDan Williams struct range *range = &dev_dax->ranges[i].range;
4170f3da14aSDan Williams struct dax_region *dax_region = dev_dax->region;
4180f3da14aSDan Williams
4190f3da14aSDan Williams device_lock_assert(dax_region->dev);
4206268d7daSDan Williams dev_dbg(&dev_dax->dev, "delete range[%d]: %#llx:%#llx\n", i,
4216268d7daSDan Williams (unsigned long long)range->start,
4226268d7daSDan Williams (unsigned long long)range->end);
42360e93dc0SDan Williams
4246268d7daSDan Williams __release_region(&dax_region->res, range->start, range_len(range));
4256268d7daSDan Williams if (--dev_dax->nr_range == 0) {
4266268d7daSDan Williams kfree(dev_dax->ranges);
4276268d7daSDan Williams dev_dax->ranges = NULL;
4280f3da14aSDan Williams }
4296268d7daSDan Williams }
4306268d7daSDan Williams
free_dev_dax_ranges(struct dev_dax * dev_dax)4316268d7daSDan Williams static void free_dev_dax_ranges(struct dev_dax *dev_dax)
4326268d7daSDan Williams {
4336268d7daSDan Williams while (dev_dax->nr_range)
4346268d7daSDan Williams trim_dev_dax_range(dev_dax);
43560e93dc0SDan Williams }
4360f3da14aSDan Williams
unregister_dev_dax(void * dev)4370f3da14aSDan Williams static void unregister_dev_dax(void *dev)
4380f3da14aSDan Williams {
4390f3da14aSDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
4400f3da14aSDan Williams
4410f3da14aSDan Williams dev_dbg(dev, "%s\n", __func__);
4420f3da14aSDan Williams
4430f3da14aSDan Williams kill_dev_dax(dev_dax);
4440f3da14aSDan Williams device_del(dev);
445e686c325SDan Williams free_dev_dax_ranges(dev_dax);
4460f3da14aSDan Williams put_device(dev);
4470f3da14aSDan Williams }
4480f3da14aSDan Williams
dax_region_free(struct kref * kref)44970aab281SDan Williams static void dax_region_free(struct kref *kref)
45070aab281SDan Williams {
45170aab281SDan Williams struct dax_region *dax_region;
45270aab281SDan Williams
45370aab281SDan Williams dax_region = container_of(kref, struct dax_region, kref);
45470aab281SDan Williams kfree(dax_region);
45570aab281SDan Williams }
45670aab281SDan Williams
dax_region_put(struct dax_region * dax_region)457*2532f416SDan Williams static void dax_region_put(struct dax_region *dax_region)
45870aab281SDan Williams {
45970aab281SDan Williams kref_put(&dax_region->kref, dax_region_free);
46070aab281SDan Williams }
46170aab281SDan Williams
4620f3da14aSDan Williams /* a return value >= 0 indicates this invocation invalidated the id */
__free_dev_dax_id(struct dev_dax * dev_dax)4630f3da14aSDan Williams static int __free_dev_dax_id(struct dev_dax *dev_dax)
4640f3da14aSDan Williams {
4650f3da14aSDan Williams struct device *dev = &dev_dax->dev;
46670aab281SDan Williams struct dax_region *dax_region;
4670f3da14aSDan Williams int rc = dev_dax->id;
4680f3da14aSDan Williams
4690f3da14aSDan Williams device_lock_assert(dev);
4700f3da14aSDan Williams
47170aab281SDan Williams if (!dev_dax->dyn_id || dev_dax->id < 0)
4720f3da14aSDan Williams return -1;
47370aab281SDan Williams dax_region = dev_dax->region;
4740f3da14aSDan Williams ida_free(&dax_region->ida, dev_dax->id);
47570aab281SDan Williams dax_region_put(dax_region);
4760f3da14aSDan Williams dev_dax->id = -1;
4770f3da14aSDan Williams return rc;
4780f3da14aSDan Williams }
4790f3da14aSDan Williams
free_dev_dax_id(struct dev_dax * dev_dax)4800f3da14aSDan Williams static int free_dev_dax_id(struct dev_dax *dev_dax)
4810f3da14aSDan Williams {
4820f3da14aSDan Williams struct device *dev = &dev_dax->dev;
4830f3da14aSDan Williams int rc;
4840f3da14aSDan Williams
4850f3da14aSDan Williams device_lock(dev);
4860f3da14aSDan Williams rc = __free_dev_dax_id(dev_dax);
4870f3da14aSDan Williams device_unlock(dev);
4880f3da14aSDan Williams return rc;
4890f3da14aSDan Williams }
4900f3da14aSDan Williams
alloc_dev_dax_id(struct dev_dax * dev_dax)49170aab281SDan Williams static int alloc_dev_dax_id(struct dev_dax *dev_dax)
49270aab281SDan Williams {
49370aab281SDan Williams struct dax_region *dax_region = dev_dax->region;
49470aab281SDan Williams int id;
49570aab281SDan Williams
49670aab281SDan Williams id = ida_alloc(&dax_region->ida, GFP_KERNEL);
49770aab281SDan Williams if (id < 0)
49870aab281SDan Williams return id;
49970aab281SDan Williams kref_get(&dax_region->kref);
50070aab281SDan Williams dev_dax->dyn_id = true;
50170aab281SDan Williams dev_dax->id = id;
50270aab281SDan Williams return id;
50370aab281SDan Williams }
50470aab281SDan Williams
delete_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)5050f3da14aSDan Williams static ssize_t delete_store(struct device *dev, struct device_attribute *attr,
5060f3da14aSDan Williams const char *buf, size_t len)
5070f3da14aSDan Williams {
5080f3da14aSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
5090f3da14aSDan Williams struct dev_dax *dev_dax;
5100f3da14aSDan Williams struct device *victim;
5110f3da14aSDan Williams bool do_del = false;
5120f3da14aSDan Williams int rc;
5130f3da14aSDan Williams
5140f3da14aSDan Williams if (is_static(dax_region))
5150f3da14aSDan Williams return -EINVAL;
5160f3da14aSDan Williams
5170f3da14aSDan Williams victim = device_find_child_by_name(dax_region->dev, buf);
5180f3da14aSDan Williams if (!victim)
5190f3da14aSDan Williams return -ENXIO;
5200f3da14aSDan Williams
5210f3da14aSDan Williams device_lock(dev);
5220f3da14aSDan Williams device_lock(victim);
5230f3da14aSDan Williams dev_dax = to_dev_dax(victim);
52460e93dc0SDan Williams if (victim->driver || dev_dax_size(dev_dax))
5250f3da14aSDan Williams rc = -EBUSY;
5260f3da14aSDan Williams else {
5270f3da14aSDan Williams /*
5280f3da14aSDan Williams * Invalidate the device so it does not become active
5290f3da14aSDan Williams * again, but always preserve device-id-0 so that
5300f3da14aSDan Williams * /sys/bus/dax/ is guaranteed to be populated while any
5310f3da14aSDan Williams * dax_region is registered.
5320f3da14aSDan Williams */
5330f3da14aSDan Williams if (dev_dax->id > 0) {
5340f3da14aSDan Williams do_del = __free_dev_dax_id(dev_dax) >= 0;
5350f3da14aSDan Williams rc = len;
5360f3da14aSDan Williams if (dax_region->seed == victim)
5370f3da14aSDan Williams dax_region->seed = NULL;
5380f3da14aSDan Williams if (dax_region->youngest == victim)
5390f3da14aSDan Williams dax_region->youngest = NULL;
5400f3da14aSDan Williams } else
5410f3da14aSDan Williams rc = -EBUSY;
5420f3da14aSDan Williams }
5430f3da14aSDan Williams device_unlock(victim);
5440f3da14aSDan Williams
5450f3da14aSDan Williams /* won the race to invalidate the device, clean it up */
5460f3da14aSDan Williams if (do_del)
5470f3da14aSDan Williams devm_release_action(dev, unregister_dev_dax, victim);
5480f3da14aSDan Williams device_unlock(dev);
5490f3da14aSDan Williams put_device(victim);
5500f3da14aSDan Williams
5510f3da14aSDan Williams return rc;
5520f3da14aSDan Williams }
5530f3da14aSDan Williams static DEVICE_ATTR_WO(delete);
5540f3da14aSDan Williams
dax_region_visible(struct kobject * kobj,struct attribute * a,int n)555c2f3011eSDan Williams static umode_t dax_region_visible(struct kobject *kobj, struct attribute *a,
556c2f3011eSDan Williams int n)
557c2f3011eSDan Williams {
558c2f3011eSDan Williams struct device *dev = container_of(kobj, struct device, kobj);
559c2f3011eSDan Williams struct dax_region *dax_region = dev_get_drvdata(dev);
560c2f3011eSDan Williams
5610f3da14aSDan Williams if (is_static(dax_region))
5620f3da14aSDan Williams if (a == &dev_attr_available_size.attr
5630f3da14aSDan Williams || a == &dev_attr_create.attr
5640f3da14aSDan Williams || a == &dev_attr_seed.attr
5650f3da14aSDan Williams || a == &dev_attr_delete.attr)
566c2f3011eSDan Williams return 0;
567c2f3011eSDan Williams return a->mode;
568c2f3011eSDan Williams }
569c2f3011eSDan Williams
57051cf784cSDan Williams static struct attribute *dax_region_attributes[] = {
571c2f3011eSDan Williams &dev_attr_available_size.attr,
57251cf784cSDan Williams &dev_attr_region_size.attr,
5736d82120fSDan Williams &dev_attr_region_align.attr,
5740f3da14aSDan Williams &dev_attr_create.attr,
5750f3da14aSDan Williams &dev_attr_seed.attr,
5760f3da14aSDan Williams &dev_attr_delete.attr,
57751cf784cSDan Williams &dev_attr_id.attr,
57851cf784cSDan Williams NULL,
57951cf784cSDan Williams };
58051cf784cSDan Williams
58151cf784cSDan Williams static const struct attribute_group dax_region_attribute_group = {
58251cf784cSDan Williams .name = "dax_region",
58351cf784cSDan Williams .attrs = dax_region_attributes,
584c2f3011eSDan Williams .is_visible = dax_region_visible,
58551cf784cSDan Williams };
58651cf784cSDan Williams
58751cf784cSDan Williams static const struct attribute_group *dax_region_attribute_groups[] = {
58851cf784cSDan Williams &dax_region_attribute_group,
58951cf784cSDan Williams NULL,
59051cf784cSDan Williams };
59151cf784cSDan Williams
dax_region_unregister(void * region)59251cf784cSDan Williams static void dax_region_unregister(void *region)
59351cf784cSDan Williams {
59451cf784cSDan Williams struct dax_region *dax_region = region;
59551cf784cSDan Williams
59651cf784cSDan Williams sysfs_remove_groups(&dax_region->dev->kobj,
59751cf784cSDan Williams dax_region_attribute_groups);
59851cf784cSDan Williams dax_region_put(dax_region);
59951cf784cSDan Williams }
60051cf784cSDan Williams
alloc_dax_region(struct device * parent,int region_id,struct range * range,int target_node,unsigned int align,unsigned long flags)60151cf784cSDan Williams struct dax_region *alloc_dax_region(struct device *parent, int region_id,
602a4574f63SDan Williams struct range *range, int target_node, unsigned int align,
603c2f3011eSDan Williams unsigned long flags)
60451cf784cSDan Williams {
60551cf784cSDan Williams struct dax_region *dax_region;
60651cf784cSDan Williams
60751cf784cSDan Williams /*
60851cf784cSDan Williams * The DAX core assumes that it can store its private data in
60951cf784cSDan Williams * parent->driver_data. This WARN is a reminder / safeguard for
61051cf784cSDan Williams * developers of device-dax drivers.
61151cf784cSDan Williams */
61251cf784cSDan Williams if (dev_get_drvdata(parent)) {
61351cf784cSDan Williams dev_WARN(parent, "dax core failed to setup private data\n");
61451cf784cSDan Williams return NULL;
61551cf784cSDan Williams }
61651cf784cSDan Williams
617a4574f63SDan Williams if (!IS_ALIGNED(range->start, align)
618a4574f63SDan Williams || !IS_ALIGNED(range_len(range), align))
61951cf784cSDan Williams return NULL;
62051cf784cSDan Williams
62151cf784cSDan Williams dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL);
62251cf784cSDan Williams if (!dax_region)
62351cf784cSDan Williams return NULL;
62451cf784cSDan Williams
62551cf784cSDan Williams dev_set_drvdata(parent, dax_region);
62651cf784cSDan Williams kref_init(&dax_region->kref);
62751cf784cSDan Williams dax_region->id = region_id;
62851cf784cSDan Williams dax_region->align = align;
62951cf784cSDan Williams dax_region->dev = parent;
6308fc5c735SDan Williams dax_region->target_node = target_node;
6310f3da14aSDan Williams ida_init(&dax_region->ida);
632c2f3011eSDan Williams dax_region->res = (struct resource) {
633a4574f63SDan Williams .start = range->start,
634a4574f63SDan Williams .end = range->end,
635c2f3011eSDan Williams .flags = IORESOURCE_MEM | flags,
636c2f3011eSDan Williams };
637c2f3011eSDan Williams
63851cf784cSDan Williams if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
63951cf784cSDan Williams kfree(dax_region);
64051cf784cSDan Williams return NULL;
64151cf784cSDan Williams }
64251cf784cSDan Williams
64351cf784cSDan Williams if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
64451cf784cSDan Williams return NULL;
64551cf784cSDan Williams return dax_region;
64651cf784cSDan Williams }
64751cf784cSDan Williams EXPORT_SYMBOL_GPL(alloc_dax_region);
64851cf784cSDan Williams
dax_mapping_release(struct device * dev)6490b07ce87SDan Williams static void dax_mapping_release(struct device *dev)
6500b07ce87SDan Williams {
6510b07ce87SDan Williams struct dax_mapping *mapping = to_dax_mapping(dev);
6526d24b170SDan Williams struct device *parent = dev->parent;
6536d24b170SDan Williams struct dev_dax *dev_dax = to_dev_dax(parent);
6540b07ce87SDan Williams
6550b07ce87SDan Williams ida_free(&dev_dax->ida, mapping->id);
6560b07ce87SDan Williams kfree(mapping);
6576d24b170SDan Williams put_device(parent);
6580b07ce87SDan Williams }
6590b07ce87SDan Williams
unregister_dax_mapping(void * data)6600b07ce87SDan Williams static void unregister_dax_mapping(void *data)
6610b07ce87SDan Williams {
6620b07ce87SDan Williams struct device *dev = data;
6630b07ce87SDan Williams struct dax_mapping *mapping = to_dax_mapping(dev);
6640b07ce87SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev->parent);
6650b07ce87SDan Williams struct dax_region *dax_region = dev_dax->region;
6660b07ce87SDan Williams
6670b07ce87SDan Williams dev_dbg(dev, "%s\n", __func__);
6680b07ce87SDan Williams
6690b07ce87SDan Williams device_lock_assert(dax_region->dev);
6700b07ce87SDan Williams
6710b07ce87SDan Williams dev_dax->ranges[mapping->range_id].mapping = NULL;
6720b07ce87SDan Williams mapping->range_id = -1;
6730b07ce87SDan Williams
67482b4ceecSDan Williams device_unregister(dev);
6750b07ce87SDan Williams }
6760b07ce87SDan Williams
get_dax_range(struct device * dev)6770b07ce87SDan Williams static struct dev_dax_range *get_dax_range(struct device *dev)
6780b07ce87SDan Williams {
6790b07ce87SDan Williams struct dax_mapping *mapping = to_dax_mapping(dev);
6800b07ce87SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev->parent);
6810b07ce87SDan Williams struct dax_region *dax_region = dev_dax->region;
6820b07ce87SDan Williams
6830b07ce87SDan Williams device_lock(dax_region->dev);
6840b07ce87SDan Williams if (mapping->range_id < 0) {
6850b07ce87SDan Williams device_unlock(dax_region->dev);
6860b07ce87SDan Williams return NULL;
6870b07ce87SDan Williams }
6880b07ce87SDan Williams
6890b07ce87SDan Williams return &dev_dax->ranges[mapping->range_id];
6900b07ce87SDan Williams }
6910b07ce87SDan Williams
put_dax_range(struct dev_dax_range * dax_range)6920b07ce87SDan Williams static void put_dax_range(struct dev_dax_range *dax_range)
6930b07ce87SDan Williams {
6940b07ce87SDan Williams struct dax_mapping *mapping = dax_range->mapping;
6950b07ce87SDan Williams struct dev_dax *dev_dax = to_dev_dax(mapping->dev.parent);
6960b07ce87SDan Williams struct dax_region *dax_region = dev_dax->region;
6970b07ce87SDan Williams
6980b07ce87SDan Williams device_unlock(dax_region->dev);
6990b07ce87SDan Williams }
7000b07ce87SDan Williams
start_show(struct device * dev,struct device_attribute * attr,char * buf)7010b07ce87SDan Williams static ssize_t start_show(struct device *dev,
7020b07ce87SDan Williams struct device_attribute *attr, char *buf)
7030b07ce87SDan Williams {
7040b07ce87SDan Williams struct dev_dax_range *dax_range;
7050b07ce87SDan Williams ssize_t rc;
7060b07ce87SDan Williams
7070b07ce87SDan Williams dax_range = get_dax_range(dev);
7080b07ce87SDan Williams if (!dax_range)
7090b07ce87SDan Williams return -ENXIO;
7100b07ce87SDan Williams rc = sprintf(buf, "%#llx\n", dax_range->range.start);
7110b07ce87SDan Williams put_dax_range(dax_range);
7120b07ce87SDan Williams
7130b07ce87SDan Williams return rc;
7140b07ce87SDan Williams }
7150b07ce87SDan Williams static DEVICE_ATTR(start, 0400, start_show, NULL);
7160b07ce87SDan Williams
end_show(struct device * dev,struct device_attribute * attr,char * buf)7170b07ce87SDan Williams static ssize_t end_show(struct device *dev,
7180b07ce87SDan Williams struct device_attribute *attr, char *buf)
7190b07ce87SDan Williams {
7200b07ce87SDan Williams struct dev_dax_range *dax_range;
7210b07ce87SDan Williams ssize_t rc;
7220b07ce87SDan Williams
7230b07ce87SDan Williams dax_range = get_dax_range(dev);
7240b07ce87SDan Williams if (!dax_range)
7250b07ce87SDan Williams return -ENXIO;
7260b07ce87SDan Williams rc = sprintf(buf, "%#llx\n", dax_range->range.end);
7270b07ce87SDan Williams put_dax_range(dax_range);
7280b07ce87SDan Williams
7290b07ce87SDan Williams return rc;
7300b07ce87SDan Williams }
7310b07ce87SDan Williams static DEVICE_ATTR(end, 0400, end_show, NULL);
7320b07ce87SDan Williams
pgoff_show(struct device * dev,struct device_attribute * attr,char * buf)7330b07ce87SDan Williams static ssize_t pgoff_show(struct device *dev,
7340b07ce87SDan Williams struct device_attribute *attr, char *buf)
7350b07ce87SDan Williams {
7360b07ce87SDan Williams struct dev_dax_range *dax_range;
7370b07ce87SDan Williams ssize_t rc;
7380b07ce87SDan Williams
7390b07ce87SDan Williams dax_range = get_dax_range(dev);
7400b07ce87SDan Williams if (!dax_range)
7410b07ce87SDan Williams return -ENXIO;
7420b07ce87SDan Williams rc = sprintf(buf, "%#lx\n", dax_range->pgoff);
7430b07ce87SDan Williams put_dax_range(dax_range);
7440b07ce87SDan Williams
7450b07ce87SDan Williams return rc;
7460b07ce87SDan Williams }
7470b07ce87SDan Williams static DEVICE_ATTR(page_offset, 0400, pgoff_show, NULL);
7480b07ce87SDan Williams
7490b07ce87SDan Williams static struct attribute *dax_mapping_attributes[] = {
7500b07ce87SDan Williams &dev_attr_start.attr,
7510b07ce87SDan Williams &dev_attr_end.attr,
7520b07ce87SDan Williams &dev_attr_page_offset.attr,
7530b07ce87SDan Williams NULL,
7540b07ce87SDan Williams };
7550b07ce87SDan Williams
7560b07ce87SDan Williams static const struct attribute_group dax_mapping_attribute_group = {
7570b07ce87SDan Williams .attrs = dax_mapping_attributes,
7580b07ce87SDan Williams };
7590b07ce87SDan Williams
7600b07ce87SDan Williams static const struct attribute_group *dax_mapping_attribute_groups[] = {
7610b07ce87SDan Williams &dax_mapping_attribute_group,
7620b07ce87SDan Williams NULL,
7630b07ce87SDan Williams };
7640b07ce87SDan Williams
7650b07ce87SDan Williams static struct device_type dax_mapping_type = {
7660b07ce87SDan Williams .release = dax_mapping_release,
7670b07ce87SDan Williams .groups = dax_mapping_attribute_groups,
7680b07ce87SDan Williams };
7690b07ce87SDan Williams
devm_register_dax_mapping(struct dev_dax * dev_dax,int range_id)7700b07ce87SDan Williams static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id)
7710b07ce87SDan Williams {
7720b07ce87SDan Williams struct dax_region *dax_region = dev_dax->region;
7730b07ce87SDan Williams struct dax_mapping *mapping;
7740b07ce87SDan Williams struct device *dev;
7750b07ce87SDan Williams int rc;
7760b07ce87SDan Williams
7770b07ce87SDan Williams device_lock_assert(dax_region->dev);
7780b07ce87SDan Williams
7790b07ce87SDan Williams if (dev_WARN_ONCE(&dev_dax->dev, !dax_region->dev->driver,
7800b07ce87SDan Williams "region disabled\n"))
7810b07ce87SDan Williams return -ENXIO;
7820b07ce87SDan Williams
7830b07ce87SDan Williams mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
7840b07ce87SDan Williams if (!mapping)
7850b07ce87SDan Williams return -ENOMEM;
7860b07ce87SDan Williams mapping->range_id = range_id;
7870b07ce87SDan Williams mapping->id = ida_alloc(&dev_dax->ida, GFP_KERNEL);
7880b07ce87SDan Williams if (mapping->id < 0) {
7890b07ce87SDan Williams kfree(mapping);
7900b07ce87SDan Williams return -ENOMEM;
7910b07ce87SDan Williams }
7920b07ce87SDan Williams dev_dax->ranges[range_id].mapping = mapping;
7930b07ce87SDan Williams dev = &mapping->dev;
7940b07ce87SDan Williams device_initialize(dev);
7950b07ce87SDan Williams dev->parent = &dev_dax->dev;
7966d24b170SDan Williams get_device(dev->parent);
7970b07ce87SDan Williams dev->type = &dax_mapping_type;
7980b07ce87SDan Williams dev_set_name(dev, "mapping%d", mapping->id);
7990b07ce87SDan Williams rc = device_add(dev);
8000b07ce87SDan Williams if (rc) {
8010b07ce87SDan Williams put_device(dev);
8020b07ce87SDan Williams return rc;
8030b07ce87SDan Williams }
8040b07ce87SDan Williams
8050b07ce87SDan Williams rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_mapping,
8060b07ce87SDan Williams dev);
8070b07ce87SDan Williams if (rc)
8080b07ce87SDan Williams return rc;
8090b07ce87SDan Williams return 0;
8100b07ce87SDan Williams }
8110b07ce87SDan Williams
alloc_dev_dax_range(struct dev_dax * dev_dax,u64 start,resource_size_t size)812fcffb6a1SDan Williams static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start,
813fcffb6a1SDan Williams resource_size_t size)
814c2f3011eSDan Williams {
815c2f3011eSDan Williams struct dax_region *dax_region = dev_dax->region;
816c2f3011eSDan Williams struct resource *res = &dax_region->res;
817c2f3011eSDan Williams struct device *dev = &dev_dax->dev;
81860e93dc0SDan Williams struct dev_dax_range *ranges;
81960e93dc0SDan Williams unsigned long pgoff = 0;
820c2f3011eSDan Williams struct resource *alloc;
8210b07ce87SDan Williams int i, rc;
822c2f3011eSDan Williams
823c2f3011eSDan Williams device_lock_assert(dax_region->dev);
824c2f3011eSDan Williams
8250f3da14aSDan Williams /* handle the seed alloc special case */
8260f3da14aSDan Williams if (!size) {
82760e93dc0SDan Williams if (dev_WARN_ONCE(dev, dev_dax->nr_range,
82860e93dc0SDan Williams "0-size allocation must be first\n"))
82960e93dc0SDan Williams return -EBUSY;
83060e93dc0SDan Williams /* nr_range == 0 is elsewhere special cased as 0-size device */
8310f3da14aSDan Williams return 0;
8320f3da14aSDan Williams }
8330f3da14aSDan Williams
834ff8da37dSZhen Lei alloc = __request_region(res, start, size, dev_name(dev), 0);
835ff8da37dSZhen Lei if (!alloc)
836c2f3011eSDan Williams return -ENOMEM;
837c2f3011eSDan Williams
838ff8da37dSZhen Lei ranges = krealloc(dev_dax->ranges, sizeof(*ranges)
839ff8da37dSZhen Lei * (dev_dax->nr_range + 1), GFP_KERNEL);
840ff8da37dSZhen Lei if (!ranges) {
841ff8da37dSZhen Lei __release_region(res, alloc->start, resource_size(alloc));
84260e93dc0SDan Williams return -ENOMEM;
84360e93dc0SDan Williams }
84460e93dc0SDan Williams
84560e93dc0SDan Williams for (i = 0; i < dev_dax->nr_range; i++)
84660e93dc0SDan Williams pgoff += PHYS_PFN(range_len(&ranges[i].range));
84760e93dc0SDan Williams dev_dax->ranges = ranges;
84860e93dc0SDan Williams ranges[dev_dax->nr_range++] = (struct dev_dax_range) {
84960e93dc0SDan Williams .pgoff = pgoff,
85060e93dc0SDan Williams .range = {
851c2f3011eSDan Williams .start = alloc->start,
852c2f3011eSDan Williams .end = alloc->end,
85360e93dc0SDan Williams },
854c2f3011eSDan Williams };
855c2f3011eSDan Williams
85660e93dc0SDan Williams dev_dbg(dev, "alloc range[%d]: %pa:%pa\n", dev_dax->nr_range - 1,
85760e93dc0SDan Williams &alloc->start, &alloc->end);
8580b07ce87SDan Williams /*
8590b07ce87SDan Williams * A dev_dax instance must be registered before mapping device
8600b07ce87SDan Williams * children can be added. Defer to devm_create_dev_dax() to add
8610b07ce87SDan Williams * the initial mapping device.
8620b07ce87SDan Williams */
8630b07ce87SDan Williams if (!device_is_registered(&dev_dax->dev))
8640b07ce87SDan Williams return 0;
8650b07ce87SDan Williams
8660b07ce87SDan Williams rc = devm_register_dax_mapping(dev_dax, dev_dax->nr_range - 1);
8676268d7daSDan Williams if (rc)
8686268d7daSDan Williams trim_dev_dax_range(dev_dax);
86960e93dc0SDan Williams
8706268d7daSDan Williams return rc;
871c2f3011eSDan Williams }
872c2f3011eSDan Williams
adjust_dev_dax_range(struct dev_dax * dev_dax,struct resource * res,resource_size_t size)873fcffb6a1SDan Williams static int adjust_dev_dax_range(struct dev_dax *dev_dax, struct resource *res, resource_size_t size)
874fcffb6a1SDan Williams {
87560e93dc0SDan Williams int last_range = dev_dax->nr_range - 1;
87660e93dc0SDan Williams struct dev_dax_range *dax_range = &dev_dax->ranges[last_range];
877fcffb6a1SDan Williams struct dax_region *dax_region = dev_dax->region;
87860e93dc0SDan Williams bool is_shrink = resource_size(res) > size;
87960e93dc0SDan Williams struct range *range = &dax_range->range;
88060e93dc0SDan Williams struct device *dev = &dev_dax->dev;
88160e93dc0SDan Williams int rc;
882fcffb6a1SDan Williams
883fcffb6a1SDan Williams device_lock_assert(dax_region->dev);
884fcffb6a1SDan Williams
88560e93dc0SDan Williams if (dev_WARN_ONCE(dev, !size, "deletion is handled by dev_dax_shrink\n"))
88660e93dc0SDan Williams return -EINVAL;
88760e93dc0SDan Williams
888fcffb6a1SDan Williams rc = adjust_resource(res, range->start, size);
889fcffb6a1SDan Williams if (rc)
890fcffb6a1SDan Williams return rc;
891fcffb6a1SDan Williams
89260e93dc0SDan Williams *range = (struct range) {
893fcffb6a1SDan Williams .start = range->start,
894fcffb6a1SDan Williams .end = range->start + size - 1,
895fcffb6a1SDan Williams };
896fcffb6a1SDan Williams
89760e93dc0SDan Williams dev_dbg(dev, "%s range[%d]: %#llx:%#llx\n", is_shrink ? "shrink" : "extend",
89860e93dc0SDan Williams last_range, (unsigned long long) range->start,
89960e93dc0SDan Williams (unsigned long long) range->end);
90060e93dc0SDan Williams
901fcffb6a1SDan Williams return 0;
902fcffb6a1SDan Williams }
903fcffb6a1SDan Williams
size_show(struct device * dev,struct device_attribute * attr,char * buf)90451cf784cSDan Williams static ssize_t size_show(struct device *dev,
90551cf784cSDan Williams struct device_attribute *attr, char *buf)
90651cf784cSDan Williams {
90751cf784cSDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
90860e93dc0SDan Williams unsigned long long size;
90960e93dc0SDan Williams
91060e93dc0SDan Williams device_lock(dev);
91160e93dc0SDan Williams size = dev_dax_size(dev_dax);
91260e93dc0SDan Williams device_unlock(dev);
91351cf784cSDan Williams
91451cf784cSDan Williams return sprintf(buf, "%llu\n", size);
91551cf784cSDan Williams }
916fcffb6a1SDan Williams
alloc_is_aligned(struct dev_dax * dev_dax,resource_size_t size)9176d82120fSDan Williams static bool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size)
918fcffb6a1SDan Williams {
919fcffb6a1SDan Williams /*
920fcffb6a1SDan Williams * The minimum mapping granularity for a device instance is a
921fcffb6a1SDan Williams * single subsection, unless the arch says otherwise.
922fcffb6a1SDan Williams */
9236d82120fSDan Williams return IS_ALIGNED(size, max_t(unsigned long, dev_dax->align, memremap_compat_align()));
924fcffb6a1SDan Williams }
925fcffb6a1SDan Williams
dev_dax_shrink(struct dev_dax * dev_dax,resource_size_t size)926fcffb6a1SDan Williams static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size)
927fcffb6a1SDan Williams {
92860e93dc0SDan Williams resource_size_t to_shrink = dev_dax_size(dev_dax) - size;
929fcffb6a1SDan Williams struct dax_region *dax_region = dev_dax->region;
930fcffb6a1SDan Williams struct device *dev = &dev_dax->dev;
93160e93dc0SDan Williams int i;
93260e93dc0SDan Williams
93360e93dc0SDan Williams for (i = dev_dax->nr_range - 1; i >= 0; i--) {
93460e93dc0SDan Williams struct range *range = &dev_dax->ranges[i].range;
9350b07ce87SDan Williams struct dax_mapping *mapping = dev_dax->ranges[i].mapping;
93660e93dc0SDan Williams struct resource *adjust = NULL, *res;
93760e93dc0SDan Williams resource_size_t shrink;
93860e93dc0SDan Williams
93960e93dc0SDan Williams shrink = min_t(u64, to_shrink, range_len(range));
94060e93dc0SDan Williams if (shrink >= range_len(range)) {
9410b07ce87SDan Williams devm_release_action(dax_region->dev,
9420b07ce87SDan Williams unregister_dax_mapping, &mapping->dev);
9436268d7daSDan Williams trim_dev_dax_range(dev_dax);
94460e93dc0SDan Williams to_shrink -= shrink;
94560e93dc0SDan Williams if (!to_shrink)
94660e93dc0SDan Williams break;
94760e93dc0SDan Williams continue;
94860e93dc0SDan Williams }
949fcffb6a1SDan Williams
950fcffb6a1SDan Williams for_each_dax_region_resource(dax_region, res)
951fcffb6a1SDan Williams if (strcmp(res->name, dev_name(dev)) == 0
952fcffb6a1SDan Williams && res->start == range->start) {
953fcffb6a1SDan Williams adjust = res;
954fcffb6a1SDan Williams break;
955fcffb6a1SDan Williams }
956fcffb6a1SDan Williams
95760e93dc0SDan Williams if (dev_WARN_ONCE(dev, !adjust || i != dev_dax->nr_range - 1,
95860e93dc0SDan Williams "failed to find matching resource\n"))
959fcffb6a1SDan Williams return -ENXIO;
96060e93dc0SDan Williams return adjust_dev_dax_range(dev_dax, adjust, range_len(range)
96160e93dc0SDan Williams - shrink);
96260e93dc0SDan Williams }
96360e93dc0SDan Williams return 0;
96460e93dc0SDan Williams }
96560e93dc0SDan Williams
96660e93dc0SDan Williams /*
96760e93dc0SDan Williams * Only allow adjustments that preserve the relative pgoff of existing
96860e93dc0SDan Williams * allocations. I.e. the dev_dax->ranges array is ordered by increasing pgoff.
96960e93dc0SDan Williams */
adjust_ok(struct dev_dax * dev_dax,struct resource * res)97060e93dc0SDan Williams static bool adjust_ok(struct dev_dax *dev_dax, struct resource *res)
97160e93dc0SDan Williams {
97260e93dc0SDan Williams struct dev_dax_range *last;
97360e93dc0SDan Williams int i;
97460e93dc0SDan Williams
97560e93dc0SDan Williams if (dev_dax->nr_range == 0)
97660e93dc0SDan Williams return false;
97760e93dc0SDan Williams if (strcmp(res->name, dev_name(&dev_dax->dev)) != 0)
97860e93dc0SDan Williams return false;
97960e93dc0SDan Williams last = &dev_dax->ranges[dev_dax->nr_range - 1];
98060e93dc0SDan Williams if (last->range.start != res->start || last->range.end != res->end)
98160e93dc0SDan Williams return false;
98260e93dc0SDan Williams for (i = 0; i < dev_dax->nr_range - 1; i++) {
98360e93dc0SDan Williams struct dev_dax_range *dax_range = &dev_dax->ranges[i];
98460e93dc0SDan Williams
98560e93dc0SDan Williams if (dax_range->pgoff > last->pgoff)
98660e93dc0SDan Williams return false;
98760e93dc0SDan Williams }
98860e93dc0SDan Williams
98960e93dc0SDan Williams return true;
990fcffb6a1SDan Williams }
991fcffb6a1SDan Williams
dev_dax_resize(struct dax_region * dax_region,struct dev_dax * dev_dax,resource_size_t size)992fcffb6a1SDan Williams static ssize_t dev_dax_resize(struct dax_region *dax_region,
993fcffb6a1SDan Williams struct dev_dax *dev_dax, resource_size_t size)
994fcffb6a1SDan Williams {
995fcffb6a1SDan Williams resource_size_t avail = dax_region_avail_size(dax_region), to_alloc;
99660e93dc0SDan Williams resource_size_t dev_size = dev_dax_size(dev_dax);
997fcffb6a1SDan Williams struct resource *region_res = &dax_region->res;
998fcffb6a1SDan Williams struct device *dev = &dev_dax->dev;
999fcffb6a1SDan Williams struct resource *res, *first;
100060e93dc0SDan Williams resource_size_t alloc = 0;
100160e93dc0SDan Williams int rc;
1002fcffb6a1SDan Williams
1003fcffb6a1SDan Williams if (dev->driver)
1004fcffb6a1SDan Williams return -EBUSY;
1005fcffb6a1SDan Williams if (size == dev_size)
1006fcffb6a1SDan Williams return 0;
1007fcffb6a1SDan Williams if (size > dev_size && size - dev_size > avail)
1008fcffb6a1SDan Williams return -ENOSPC;
1009fcffb6a1SDan Williams if (size < dev_size)
1010fcffb6a1SDan Williams return dev_dax_shrink(dev_dax, size);
1011fcffb6a1SDan Williams
1012fcffb6a1SDan Williams to_alloc = size - dev_size;
10136d82120fSDan Williams if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc),
1014fcffb6a1SDan Williams "resize of %pa misaligned\n", &to_alloc))
1015fcffb6a1SDan Williams return -ENXIO;
1016fcffb6a1SDan Williams
1017fcffb6a1SDan Williams /*
1018fcffb6a1SDan Williams * Expand the device into the unused portion of the region. This
1019fcffb6a1SDan Williams * may involve adjusting the end of an existing resource, or
1020fcffb6a1SDan Williams * allocating a new resource.
1021fcffb6a1SDan Williams */
102260e93dc0SDan Williams retry:
1023fcffb6a1SDan Williams first = region_res->child;
1024fcffb6a1SDan Williams if (!first)
1025fcffb6a1SDan Williams return alloc_dev_dax_range(dev_dax, dax_region->res.start, to_alloc);
102660e93dc0SDan Williams
102760e93dc0SDan Williams rc = -ENOSPC;
102860e93dc0SDan Williams for (res = first; res; res = res->sibling) {
1029fcffb6a1SDan Williams struct resource *next = res->sibling;
1030fcffb6a1SDan Williams
1031fcffb6a1SDan Williams /* space at the beginning of the region */
103260e93dc0SDan Williams if (res == first && res->start > dax_region->res.start) {
103360e93dc0SDan Williams alloc = min(res->start - dax_region->res.start, to_alloc);
103460e93dc0SDan Williams rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, alloc);
103560e93dc0SDan Williams break;
103660e93dc0SDan Williams }
1037fcffb6a1SDan Williams
103860e93dc0SDan Williams alloc = 0;
1039fcffb6a1SDan Williams /* space between allocations */
1040fcffb6a1SDan Williams if (next && next->start > res->end + 1)
104160e93dc0SDan Williams alloc = min(next->start - (res->end + 1), to_alloc);
1042fcffb6a1SDan Williams
1043fcffb6a1SDan Williams /* space at the end of the region */
104460e93dc0SDan Williams if (!alloc && !next && res->end < region_res->end)
104560e93dc0SDan Williams alloc = min(region_res->end - res->end, to_alloc);
1046fcffb6a1SDan Williams
104760e93dc0SDan Williams if (!alloc)
104860e93dc0SDan Williams continue;
104960e93dc0SDan Williams
105060e93dc0SDan Williams if (adjust_ok(dev_dax, res)) {
105160e93dc0SDan Williams rc = adjust_dev_dax_range(dev_dax, res, resource_size(res) + alloc);
105260e93dc0SDan Williams break;
1053fcffb6a1SDan Williams }
105460e93dc0SDan Williams rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc);
105560e93dc0SDan Williams break;
105660e93dc0SDan Williams }
105760e93dc0SDan Williams if (rc)
105860e93dc0SDan Williams return rc;
105960e93dc0SDan Williams to_alloc -= alloc;
106060e93dc0SDan Williams if (to_alloc)
106160e93dc0SDan Williams goto retry;
106260e93dc0SDan Williams return 0;
1063fcffb6a1SDan Williams }
1064fcffb6a1SDan Williams
size_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1065fcffb6a1SDan Williams static ssize_t size_store(struct device *dev, struct device_attribute *attr,
1066fcffb6a1SDan Williams const char *buf, size_t len)
1067fcffb6a1SDan Williams {
1068fcffb6a1SDan Williams ssize_t rc;
1069fcffb6a1SDan Williams unsigned long long val;
1070fcffb6a1SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
1071fcffb6a1SDan Williams struct dax_region *dax_region = dev_dax->region;
1072fcffb6a1SDan Williams
1073fcffb6a1SDan Williams rc = kstrtoull(buf, 0, &val);
1074fcffb6a1SDan Williams if (rc)
1075fcffb6a1SDan Williams return rc;
1076fcffb6a1SDan Williams
10776d82120fSDan Williams if (!alloc_is_aligned(dev_dax, val)) {
1078fcffb6a1SDan Williams dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val);
1079fcffb6a1SDan Williams return -EINVAL;
1080fcffb6a1SDan Williams }
1081fcffb6a1SDan Williams
1082fcffb6a1SDan Williams device_lock(dax_region->dev);
1083fcffb6a1SDan Williams if (!dax_region->dev->driver) {
1084fcffb6a1SDan Williams device_unlock(dax_region->dev);
1085fcffb6a1SDan Williams return -ENXIO;
1086fcffb6a1SDan Williams }
1087fcffb6a1SDan Williams device_lock(dev);
1088fcffb6a1SDan Williams rc = dev_dax_resize(dax_region, dev_dax, val);
1089fcffb6a1SDan Williams device_unlock(dev);
1090fcffb6a1SDan Williams device_unlock(dax_region->dev);
1091fcffb6a1SDan Williams
1092fcffb6a1SDan Williams return rc == 0 ? len : rc;
1093fcffb6a1SDan Williams }
1094fcffb6a1SDan Williams static DEVICE_ATTR_RW(size);
109551cf784cSDan Williams
range_parse(const char * opt,size_t len,struct range * range)10968490e2e2SJoao Martins static ssize_t range_parse(const char *opt, size_t len, struct range *range)
10978490e2e2SJoao Martins {
10988490e2e2SJoao Martins unsigned long long addr = 0;
10998490e2e2SJoao Martins char *start, *end, *str;
11007323fb22SShiyang Ruan ssize_t rc = -EINVAL;
11018490e2e2SJoao Martins
11028490e2e2SJoao Martins str = kstrdup(opt, GFP_KERNEL);
11038490e2e2SJoao Martins if (!str)
11048490e2e2SJoao Martins return rc;
11058490e2e2SJoao Martins
11068490e2e2SJoao Martins end = str;
11078490e2e2SJoao Martins start = strsep(&end, "-");
11088490e2e2SJoao Martins if (!start || !end)
11098490e2e2SJoao Martins goto err;
11108490e2e2SJoao Martins
11118490e2e2SJoao Martins rc = kstrtoull(start, 16, &addr);
11128490e2e2SJoao Martins if (rc)
11138490e2e2SJoao Martins goto err;
11148490e2e2SJoao Martins range->start = addr;
11158490e2e2SJoao Martins
11168490e2e2SJoao Martins rc = kstrtoull(end, 16, &addr);
11178490e2e2SJoao Martins if (rc)
11188490e2e2SJoao Martins goto err;
11198490e2e2SJoao Martins range->end = addr;
11208490e2e2SJoao Martins
11218490e2e2SJoao Martins err:
11228490e2e2SJoao Martins kfree(str);
11238490e2e2SJoao Martins return rc;
11248490e2e2SJoao Martins }
11258490e2e2SJoao Martins
mapping_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)11268490e2e2SJoao Martins static ssize_t mapping_store(struct device *dev, struct device_attribute *attr,
11278490e2e2SJoao Martins const char *buf, size_t len)
11288490e2e2SJoao Martins {
11298490e2e2SJoao Martins struct dev_dax *dev_dax = to_dev_dax(dev);
11308490e2e2SJoao Martins struct dax_region *dax_region = dev_dax->region;
11318490e2e2SJoao Martins size_t to_alloc;
11328490e2e2SJoao Martins struct range r;
11338490e2e2SJoao Martins ssize_t rc;
11348490e2e2SJoao Martins
11358490e2e2SJoao Martins rc = range_parse(buf, len, &r);
11368490e2e2SJoao Martins if (rc)
11378490e2e2SJoao Martins return rc;
11388490e2e2SJoao Martins
11398490e2e2SJoao Martins rc = -ENXIO;
11408490e2e2SJoao Martins device_lock(dax_region->dev);
11418490e2e2SJoao Martins if (!dax_region->dev->driver) {
11428490e2e2SJoao Martins device_unlock(dax_region->dev);
11438490e2e2SJoao Martins return rc;
11448490e2e2SJoao Martins }
11458490e2e2SJoao Martins device_lock(dev);
11468490e2e2SJoao Martins
11478490e2e2SJoao Martins to_alloc = range_len(&r);
11488490e2e2SJoao Martins if (alloc_is_aligned(dev_dax, to_alloc))
11498490e2e2SJoao Martins rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc);
11508490e2e2SJoao Martins device_unlock(dev);
11518490e2e2SJoao Martins device_unlock(dax_region->dev);
11528490e2e2SJoao Martins
11538490e2e2SJoao Martins return rc == 0 ? len : rc;
11548490e2e2SJoao Martins }
11558490e2e2SJoao Martins static DEVICE_ATTR_WO(mapping);
11568490e2e2SJoao Martins
align_show(struct device * dev,struct device_attribute * attr,char * buf)11576d82120fSDan Williams static ssize_t align_show(struct device *dev,
11586d82120fSDan Williams struct device_attribute *attr, char *buf)
11596d82120fSDan Williams {
11606d82120fSDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
11616d82120fSDan Williams
11626d82120fSDan Williams return sprintf(buf, "%d\n", dev_dax->align);
11636d82120fSDan Williams }
11646d82120fSDan Williams
dev_dax_validate_align(struct dev_dax * dev_dax)11656d82120fSDan Williams static ssize_t dev_dax_validate_align(struct dev_dax *dev_dax)
11666d82120fSDan Williams {
11676d82120fSDan Williams struct device *dev = &dev_dax->dev;
11686d82120fSDan Williams int i;
11696d82120fSDan Williams
11706d82120fSDan Williams for (i = 0; i < dev_dax->nr_range; i++) {
11716d82120fSDan Williams size_t len = range_len(&dev_dax->ranges[i].range);
11726d82120fSDan Williams
11736d82120fSDan Williams if (!alloc_is_aligned(dev_dax, len)) {
11746d82120fSDan Williams dev_dbg(dev, "%s: align %u invalid for range %d\n",
11756d82120fSDan Williams __func__, dev_dax->align, i);
11766d82120fSDan Williams return -EINVAL;
11776d82120fSDan Williams }
11786d82120fSDan Williams }
11796d82120fSDan Williams
11806d82120fSDan Williams return 0;
11816d82120fSDan Williams }
11826d82120fSDan Williams
align_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)11836d82120fSDan Williams static ssize_t align_store(struct device *dev, struct device_attribute *attr,
11846d82120fSDan Williams const char *buf, size_t len)
11856d82120fSDan Williams {
11866d82120fSDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
11876d82120fSDan Williams struct dax_region *dax_region = dev_dax->region;
11886d82120fSDan Williams unsigned long val, align_save;
11896d82120fSDan Williams ssize_t rc;
11906d82120fSDan Williams
11916d82120fSDan Williams rc = kstrtoul(buf, 0, &val);
11926d82120fSDan Williams if (rc)
11936d82120fSDan Williams return -ENXIO;
11946d82120fSDan Williams
11956d82120fSDan Williams if (!dax_align_valid(val))
11966d82120fSDan Williams return -EINVAL;
11976d82120fSDan Williams
11986d82120fSDan Williams device_lock(dax_region->dev);
11996d82120fSDan Williams if (!dax_region->dev->driver) {
12006d82120fSDan Williams device_unlock(dax_region->dev);
12016d82120fSDan Williams return -ENXIO;
12026d82120fSDan Williams }
12036d82120fSDan Williams
12046d82120fSDan Williams device_lock(dev);
12056d82120fSDan Williams if (dev->driver) {
12066d82120fSDan Williams rc = -EBUSY;
12076d82120fSDan Williams goto out_unlock;
12086d82120fSDan Williams }
12096d82120fSDan Williams
12106d82120fSDan Williams align_save = dev_dax->align;
12116d82120fSDan Williams dev_dax->align = val;
12126d82120fSDan Williams rc = dev_dax_validate_align(dev_dax);
12136d82120fSDan Williams if (rc)
12146d82120fSDan Williams dev_dax->align = align_save;
12156d82120fSDan Williams out_unlock:
12166d82120fSDan Williams device_unlock(dev);
12176d82120fSDan Williams device_unlock(dax_region->dev);
12186d82120fSDan Williams return rc == 0 ? len : rc;
12196d82120fSDan Williams }
12206d82120fSDan Williams static DEVICE_ATTR_RW(align);
12216d82120fSDan Williams
dev_dax_target_node(struct dev_dax * dev_dax)122221c75763SDan Williams static int dev_dax_target_node(struct dev_dax *dev_dax)
122321c75763SDan Williams {
122421c75763SDan Williams struct dax_region *dax_region = dev_dax->region;
122521c75763SDan Williams
122621c75763SDan Williams return dax_region->target_node;
122721c75763SDan Williams }
122821c75763SDan Williams
target_node_show(struct device * dev,struct device_attribute * attr,char * buf)122921c75763SDan Williams static ssize_t target_node_show(struct device *dev,
123021c75763SDan Williams struct device_attribute *attr, char *buf)
123121c75763SDan Williams {
123221c75763SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
123321c75763SDan Williams
123421c75763SDan Williams return sprintf(buf, "%d\n", dev_dax_target_node(dev_dax));
123521c75763SDan Williams }
123621c75763SDan Williams static DEVICE_ATTR_RO(target_node);
123721c75763SDan Williams
resource_show(struct device * dev,struct device_attribute * attr,char * buf)123840cdc60aSVishal Verma static ssize_t resource_show(struct device *dev,
123940cdc60aSVishal Verma struct device_attribute *attr, char *buf)
124040cdc60aSVishal Verma {
124140cdc60aSVishal Verma struct dev_dax *dev_dax = to_dev_dax(dev);
124260e93dc0SDan Williams struct dax_region *dax_region = dev_dax->region;
124360e93dc0SDan Williams unsigned long long start;
124440cdc60aSVishal Verma
124560e93dc0SDan Williams if (dev_dax->nr_range < 1)
124660e93dc0SDan Williams start = dax_region->res.start;
124760e93dc0SDan Williams else
124860e93dc0SDan Williams start = dev_dax->ranges[0].range.start;
124960e93dc0SDan Williams
125060e93dc0SDan Williams return sprintf(buf, "%#llx\n", start);
125140cdc60aSVishal Verma }
1252153dd286SDan Williams static DEVICE_ATTR(resource, 0400, resource_show, NULL);
125340cdc60aSVishal Verma
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)1254c347bd71SVishal Verma static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
1255c347bd71SVishal Verma char *buf)
1256c347bd71SVishal Verma {
1257c347bd71SVishal Verma /*
1258c347bd71SVishal Verma * We only ever expect to handle device-dax instances, i.e. the
1259c347bd71SVishal Verma * @type argument to MODULE_ALIAS_DAX_DEVICE() is always zero
1260c347bd71SVishal Verma */
1261c347bd71SVishal Verma return sprintf(buf, DAX_DEVICE_MODALIAS_FMT "\n", 0);
1262c347bd71SVishal Verma }
1263c347bd71SVishal Verma static DEVICE_ATTR_RO(modalias);
1264c347bd71SVishal Verma
numa_node_show(struct device * dev,struct device_attribute * attr,char * buf)1265cb4dd729SDan Williams static ssize_t numa_node_show(struct device *dev,
1266cb4dd729SDan Williams struct device_attribute *attr, char *buf)
1267cb4dd729SDan Williams {
1268cb4dd729SDan Williams return sprintf(buf, "%d\n", dev_to_node(dev));
1269cb4dd729SDan Williams }
1270cb4dd729SDan Williams static DEVICE_ATTR_RO(numa_node);
1271cb4dd729SDan Williams
dev_dax_visible(struct kobject * kobj,struct attribute * a,int n)127221c75763SDan Williams static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n)
127321c75763SDan Williams {
127421c75763SDan Williams struct device *dev = container_of(kobj, struct device, kobj);
127521c75763SDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
1276fcffb6a1SDan Williams struct dax_region *dax_region = dev_dax->region;
127721c75763SDan Williams
127821c75763SDan Williams if (a == &dev_attr_target_node.attr && dev_dax_target_node(dev_dax) < 0)
127921c75763SDan Williams return 0;
1280cb4dd729SDan Williams if (a == &dev_attr_numa_node.attr && !IS_ENABLED(CONFIG_NUMA))
1281cb4dd729SDan Williams return 0;
12828490e2e2SJoao Martins if (a == &dev_attr_mapping.attr && is_static(dax_region))
12838490e2e2SJoao Martins return 0;
12846d82120fSDan Williams if ((a == &dev_attr_align.attr ||
12856d82120fSDan Williams a == &dev_attr_size.attr) && is_static(dax_region))
1286fcffb6a1SDan Williams return 0444;
128721c75763SDan Williams return a->mode;
128821c75763SDan Williams }
128921c75763SDan Williams
129051cf784cSDan Williams static struct attribute *dev_dax_attributes[] = {
1291c347bd71SVishal Verma &dev_attr_modalias.attr,
129251cf784cSDan Williams &dev_attr_size.attr,
12938490e2e2SJoao Martins &dev_attr_mapping.attr,
129421c75763SDan Williams &dev_attr_target_node.attr,
12956d82120fSDan Williams &dev_attr_align.attr,
129640cdc60aSVishal Verma &dev_attr_resource.attr,
1297cb4dd729SDan Williams &dev_attr_numa_node.attr,
129851cf784cSDan Williams NULL,
129951cf784cSDan Williams };
130051cf784cSDan Williams
130151cf784cSDan Williams static const struct attribute_group dev_dax_attribute_group = {
130251cf784cSDan Williams .attrs = dev_dax_attributes,
130321c75763SDan Williams .is_visible = dev_dax_visible,
130451cf784cSDan Williams };
130551cf784cSDan Williams
13069567da0bSDan Williams static const struct attribute_group *dax_attribute_groups[] = {
130751cf784cSDan Williams &dev_dax_attribute_group,
130851cf784cSDan Williams NULL,
130951cf784cSDan Williams };
131051cf784cSDan Williams
dev_dax_release(struct device * dev)13119567da0bSDan Williams static void dev_dax_release(struct device *dev)
131251cf784cSDan Williams {
131351cf784cSDan Williams struct dev_dax *dev_dax = to_dev_dax(dev);
131451cf784cSDan Williams struct dax_device *dax_dev = dev_dax->dax_dev;
131551cf784cSDan Williams
13169567da0bSDan Williams put_dax(dax_dev);
13170f3da14aSDan Williams free_dev_dax_id(dev_dax);
1318f5516ec5SDan Williams kfree(dev_dax->pgmap);
13199567da0bSDan Williams kfree(dev_dax);
13209567da0bSDan Williams }
13219567da0bSDan Williams
1322770619a9SDan Williams static const struct device_type dev_dax_type = {
1323770619a9SDan Williams .release = dev_dax_release,
1324770619a9SDan Williams .groups = dax_attribute_groups,
1325770619a9SDan Williams };
1326770619a9SDan Williams
devm_create_dev_dax(struct dev_dax_data * data)1327174ebeceSDan Williams struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data)
13289567da0bSDan Williams {
1329174ebeceSDan Williams struct dax_region *dax_region = data->dax_region;
13309567da0bSDan Williams struct device *parent = dax_region->dev;
13319567da0bSDan Williams struct dax_device *dax_dev;
13329567da0bSDan Williams struct dev_dax *dev_dax;
13339567da0bSDan Williams struct inode *inode;
13349567da0bSDan Williams struct device *dev;
1335c2f3011eSDan Williams int rc;
13369567da0bSDan Williams
13379567da0bSDan Williams dev_dax = kzalloc(sizeof(*dev_dax), GFP_KERNEL);
13389567da0bSDan Williams if (!dev_dax)
13399567da0bSDan Williams return ERR_PTR(-ENOMEM);
13409567da0bSDan Williams
134170aab281SDan Williams dev_dax->region = dax_region;
13420f3da14aSDan Williams if (is_static(dax_region)) {
13430f3da14aSDan Williams if (dev_WARN_ONCE(parent, data->id < 0,
13440f3da14aSDan Williams "dynamic id specified to static region\n")) {
13450f3da14aSDan Williams rc = -EINVAL;
13460f3da14aSDan Williams goto err_id;
13470f3da14aSDan Williams }
13480f3da14aSDan Williams
13490f3da14aSDan Williams dev_dax->id = data->id;
13500f3da14aSDan Williams } else {
13510f3da14aSDan Williams if (dev_WARN_ONCE(parent, data->id >= 0,
13520f3da14aSDan Williams "static id specified to dynamic region\n")) {
13530f3da14aSDan Williams rc = -EINVAL;
13540f3da14aSDan Williams goto err_id;
13550f3da14aSDan Williams }
13560f3da14aSDan Williams
135770aab281SDan Williams rc = alloc_dev_dax_id(dev_dax);
13580f3da14aSDan Williams if (rc < 0)
13590f3da14aSDan Williams goto err_id;
13600f3da14aSDan Williams }
13610f3da14aSDan Williams
1362c2f3011eSDan Williams dev = &dev_dax->dev;
1363c2f3011eSDan Williams device_initialize(dev);
13640f3da14aSDan Williams dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id);
1365c2f3011eSDan Williams
1366fcffb6a1SDan Williams rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, data->size);
1367c2f3011eSDan Williams if (rc)
1368c2f3011eSDan Williams goto err_range;
1369c2f3011eSDan Williams
1370f5516ec5SDan Williams if (data->pgmap) {
1371c2f3011eSDan Williams dev_WARN_ONCE(parent, !is_static(dax_region),
1372c2f3011eSDan Williams "custom dev_pagemap requires a static dax_region\n");
1373c2f3011eSDan Williams
1374f5516ec5SDan Williams dev_dax->pgmap = kmemdup(data->pgmap,
1375f5516ec5SDan Williams sizeof(struct dev_pagemap), GFP_KERNEL);
1376c2f3011eSDan Williams if (!dev_dax->pgmap) {
1377c2f3011eSDan Williams rc = -ENOMEM;
1378f5516ec5SDan Williams goto err_pgmap;
1379f5516ec5SDan Williams }
1380c2f3011eSDan Williams }
138189ec9f2cSDan Williams
13829567da0bSDan Williams /*
1383fb08a190SChristoph Hellwig * No dax_operations since there is no access to this device outside of
1384fb08a190SChristoph Hellwig * mmap of the resulting character device.
13859567da0bSDan Williams */
138630c6828aSChristoph Hellwig dax_dev = alloc_dax(dev_dax, NULL);
13874e4ced93SVivek Goyal if (IS_ERR(dax_dev)) {
13884e4ced93SVivek Goyal rc = PTR_ERR(dax_dev);
1389f5516ec5SDan Williams goto err_alloc_dax;
13904e4ced93SVivek Goyal }
139130c6828aSChristoph Hellwig set_dax_synchronous(dax_dev);
13927ac5360cSChristoph Hellwig set_dax_nocache(dax_dev);
13937ac5360cSChristoph Hellwig set_dax_nomc(dax_dev);
13949567da0bSDan Williams
13959567da0bSDan Williams /* a device_dax instance is dead while the driver is not attached */
13969567da0bSDan Williams kill_dax(dax_dev);
13979567da0bSDan Williams
13989567da0bSDan Williams dev_dax->dax_dev = dax_dev;
13998fc5c735SDan Williams dev_dax->target_node = dax_region->target_node;
140033cf94d7SJoao Martins dev_dax->align = dax_region->align;
14010b07ce87SDan Williams ida_init(&dev_dax->ida);
14029567da0bSDan Williams
14039567da0bSDan Williams inode = dax_inode(dax_dev);
14049567da0bSDan Williams dev->devt = inode->i_rdev;
14059567da0bSDan Williams dev->bus = &dax_bus_type;
14069567da0bSDan Williams dev->parent = parent;
1407770619a9SDan Williams dev->type = &dev_dax_type;
14089567da0bSDan Williams
14099567da0bSDan Williams rc = device_add(dev);
14109567da0bSDan Williams if (rc) {
14119567da0bSDan Williams kill_dev_dax(dev_dax);
14129567da0bSDan Williams put_device(dev);
14139567da0bSDan Williams return ERR_PTR(rc);
14149567da0bSDan Williams }
14159567da0bSDan Williams
14169567da0bSDan Williams rc = devm_add_action_or_reset(dax_region->dev, unregister_dev_dax, dev);
14179567da0bSDan Williams if (rc)
14189567da0bSDan Williams return ERR_PTR(rc);
14199567da0bSDan Williams
14200b07ce87SDan Williams /* register mapping device for the initial allocation range */
14210b07ce87SDan Williams if (dev_dax->nr_range && range_len(&dev_dax->ranges[0].range)) {
14220b07ce87SDan Williams rc = devm_register_dax_mapping(dev_dax, 0);
14230b07ce87SDan Williams if (rc)
14240b07ce87SDan Williams return ERR_PTR(rc);
14250b07ce87SDan Williams }
14260b07ce87SDan Williams
14279567da0bSDan Williams return dev_dax;
1428c2f3011eSDan Williams
1429f5516ec5SDan Williams err_alloc_dax:
1430f5516ec5SDan Williams kfree(dev_dax->pgmap);
1431f5516ec5SDan Williams err_pgmap:
143260e93dc0SDan Williams free_dev_dax_ranges(dev_dax);
1433c2f3011eSDan Williams err_range:
14340f3da14aSDan Williams free_dev_dax_id(dev_dax);
14350f3da14aSDan Williams err_id:
14369567da0bSDan Williams kfree(dev_dax);
14379567da0bSDan Williams
14389567da0bSDan Williams return ERR_PTR(rc);
14399567da0bSDan Williams }
1440174ebeceSDan Williams EXPORT_SYMBOL_GPL(devm_create_dev_dax);
14419567da0bSDan Williams
__dax_driver_register(struct dax_device_driver * dax_drv,struct module * module,const char * mod_name)1442d200781eSDan Williams int __dax_driver_register(struct dax_device_driver *dax_drv,
14439567da0bSDan Williams struct module *module, const char *mod_name)
14449567da0bSDan Williams {
1445d200781eSDan Williams struct device_driver *drv = &dax_drv->drv;
1446d200781eSDan Williams
14475b8e64f1SUwe Kleine-König /*
14485b8e64f1SUwe Kleine-König * dax_bus_probe() calls dax_drv->probe() unconditionally.
14495b8e64f1SUwe Kleine-König * So better be safe than sorry and ensure it is provided.
14505b8e64f1SUwe Kleine-König */
14515b8e64f1SUwe Kleine-König if (!dax_drv->probe)
14525b8e64f1SUwe Kleine-König return -EINVAL;
14535b8e64f1SUwe Kleine-König
1454d200781eSDan Williams INIT_LIST_HEAD(&dax_drv->ids);
14559567da0bSDan Williams drv->owner = module;
14569567da0bSDan Williams drv->name = mod_name;
14579567da0bSDan Williams drv->mod_name = mod_name;
14589567da0bSDan Williams drv->bus = &dax_bus_type;
1459d200781eSDan Williams
1460e9ee9fe3SDan Williams return driver_register(drv);
14619567da0bSDan Williams }
14629567da0bSDan Williams EXPORT_SYMBOL_GPL(__dax_driver_register);
14639567da0bSDan Williams
dax_driver_unregister(struct dax_device_driver * dax_drv)1464d200781eSDan Williams void dax_driver_unregister(struct dax_device_driver *dax_drv)
1465d200781eSDan Williams {
1466730926c3SDan Williams struct device_driver *drv = &dax_drv->drv;
1467d200781eSDan Williams struct dax_id *dax_id, *_id;
1468d200781eSDan Williams
1469d200781eSDan Williams mutex_lock(&dax_bus_lock);
1470d200781eSDan Williams list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) {
1471d200781eSDan Williams list_del(&dax_id->list);
1472d200781eSDan Williams kfree(dax_id);
1473d200781eSDan Williams }
1474d200781eSDan Williams mutex_unlock(&dax_bus_lock);
1475730926c3SDan Williams driver_unregister(drv);
1476d200781eSDan Williams }
1477d200781eSDan Williams EXPORT_SYMBOL_GPL(dax_driver_unregister);
1478d200781eSDan Williams
dax_bus_init(void)14799567da0bSDan Williams int __init dax_bus_init(void)
14809567da0bSDan Williams {
148183762cb5SDan Williams return bus_register(&dax_bus_type);
14829567da0bSDan Williams }
14839567da0bSDan Williams
dax_bus_exit(void)14849567da0bSDan Williams void __exit dax_bus_exit(void)
14859567da0bSDan Williams {
14869567da0bSDan Williams bus_unregister(&dax_bus_type);
14879567da0bSDan Williams }
1488