xref: /openbmc/linux/drivers/dax/bus.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
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", &region_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