]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/nvdimm/bus.c
acpi: Add acpi_map_pxm_to_online_node()
[mirror_ubuntu-artful-kernel.git] / drivers / nvdimm / bus.c
CommitLineData
45def22c
DW
1/*
2 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 */
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
62232e45 14#include <linux/vmalloc.h>
45def22c 15#include <linux/uaccess.h>
3d88002e 16#include <linux/module.h>
8c2f7e86 17#include <linux/blkdev.h>
45def22c 18#include <linux/fcntl.h>
e6dfb2de 19#include <linux/async.h>
8c2f7e86 20#include <linux/genhd.h>
62232e45 21#include <linux/ndctl.h>
4d88a97a 22#include <linux/sched.h>
45def22c
DW
23#include <linux/slab.h>
24#include <linux/fs.h>
25#include <linux/io.h>
62232e45 26#include <linux/mm.h>
4d88a97a 27#include <linux/nd.h>
45def22c 28#include "nd-core.h"
4d88a97a 29#include "nd.h"
45def22c 30
62232e45 31int nvdimm_major;
45def22c
DW
32static int nvdimm_bus_major;
33static struct class *nd_class;
34
4d88a97a
DW
35static int to_nd_device_type(struct device *dev)
36{
37 if (is_nvdimm(dev))
38 return ND_DEVICE_DIMM;
3d88002e
DW
39 else if (is_nd_pmem(dev))
40 return ND_DEVICE_REGION_PMEM;
41 else if (is_nd_blk(dev))
42 return ND_DEVICE_REGION_BLK;
43 else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
44 return nd_region_to_nstype(to_nd_region(dev->parent));
4d88a97a
DW
45
46 return 0;
47}
48
49static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
50{
51 return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
52 to_nd_device_type(dev));
53}
54
55static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
56{
57 struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
58
59 return test_bit(to_nd_device_type(dev), &nd_drv->type);
60}
61
3d88002e
DW
62static struct module *to_bus_provider(struct device *dev)
63{
64 /* pin bus providers while regions are enabled */
65 if (is_nd_pmem(dev) || is_nd_blk(dev)) {
66 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
67
68 return nvdimm_bus->module;
69 }
70 return NULL;
71}
72
eaf96153
DW
73static void nvdimm_bus_probe_start(struct nvdimm_bus *nvdimm_bus)
74{
75 nvdimm_bus_lock(&nvdimm_bus->dev);
76 nvdimm_bus->probe_active++;
77 nvdimm_bus_unlock(&nvdimm_bus->dev);
78}
79
80static void nvdimm_bus_probe_end(struct nvdimm_bus *nvdimm_bus)
81{
82 nvdimm_bus_lock(&nvdimm_bus->dev);
83 if (--nvdimm_bus->probe_active == 0)
84 wake_up(&nvdimm_bus->probe_wait);
85 nvdimm_bus_unlock(&nvdimm_bus->dev);
86}
87
4d88a97a
DW
88static int nvdimm_bus_probe(struct device *dev)
89{
90 struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
3d88002e 91 struct module *provider = to_bus_provider(dev);
4d88a97a
DW
92 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
93 int rc;
94
3d88002e
DW
95 if (!try_module_get(provider))
96 return -ENXIO;
97
eaf96153 98 nvdimm_bus_probe_start(nvdimm_bus);
4d88a97a 99 rc = nd_drv->probe(dev);
eaf96153
DW
100 if (rc == 0)
101 nd_region_probe_success(nvdimm_bus, dev);
bf9bccc1
DW
102 else
103 nd_region_disable(nvdimm_bus, dev);
eaf96153
DW
104 nvdimm_bus_probe_end(nvdimm_bus);
105
4d88a97a
DW
106 dev_dbg(&nvdimm_bus->dev, "%s.probe(%s) = %d\n", dev->driver->name,
107 dev_name(dev), rc);
8c2f7e86 108
3d88002e
DW
109 if (rc != 0)
110 module_put(provider);
4d88a97a
DW
111 return rc;
112}
113
114static int nvdimm_bus_remove(struct device *dev)
115{
116 struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
3d88002e 117 struct module *provider = to_bus_provider(dev);
4d88a97a
DW
118 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
119 int rc;
120
121 rc = nd_drv->remove(dev);
eaf96153
DW
122 nd_region_disable(nvdimm_bus, dev);
123
4d88a97a
DW
124 dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
125 dev_name(dev), rc);
3d88002e 126 module_put(provider);
4d88a97a
DW
127 return rc;
128}
129
130static struct bus_type nvdimm_bus_type = {
e6dfb2de 131 .name = "nd",
4d88a97a
DW
132 .uevent = nvdimm_bus_uevent,
133 .match = nvdimm_bus_match,
134 .probe = nvdimm_bus_probe,
135 .remove = nvdimm_bus_remove,
136};
137
138static ASYNC_DOMAIN_EXCLUSIVE(nd_async_domain);
139
140void nd_synchronize(void)
141{
142 async_synchronize_full_domain(&nd_async_domain);
143}
144EXPORT_SYMBOL_GPL(nd_synchronize);
145
146static void nd_async_device_register(void *d, async_cookie_t cookie)
147{
148 struct device *dev = d;
149
150 if (device_add(dev) != 0) {
151 dev_err(dev, "%s: failed\n", __func__);
152 put_device(dev);
153 }
154 put_device(dev);
155}
156
157static void nd_async_device_unregister(void *d, async_cookie_t cookie)
158{
159 struct device *dev = d;
160
0ba1c634
DW
161 /* flush bus operations before delete */
162 nvdimm_bus_lock(dev);
163 nvdimm_bus_unlock(dev);
164
4d88a97a
DW
165 device_unregister(dev);
166 put_device(dev);
167}
168
8c2f7e86 169void __nd_device_register(struct device *dev)
4d88a97a
DW
170{
171 dev->bus = &nvdimm_bus_type;
4d88a97a
DW
172 get_device(dev);
173 async_schedule_domain(nd_async_device_register, dev,
174 &nd_async_domain);
175}
8c2f7e86
DW
176
177void nd_device_register(struct device *dev)
178{
179 device_initialize(dev);
180 __nd_device_register(dev);
181}
4d88a97a
DW
182EXPORT_SYMBOL(nd_device_register);
183
184void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
185{
186 switch (mode) {
187 case ND_ASYNC:
188 get_device(dev);
189 async_schedule_domain(nd_async_device_unregister, dev,
190 &nd_async_domain);
191 break;
192 case ND_SYNC:
193 nd_synchronize();
194 device_unregister(dev);
195 break;
196 }
197}
198EXPORT_SYMBOL(nd_device_unregister);
199
200/**
201 * __nd_driver_register() - register a region or a namespace driver
202 * @nd_drv: driver to register
203 * @owner: automatically set by nd_driver_register() macro
204 * @mod_name: automatically set by nd_driver_register() macro
205 */
206int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner,
207 const char *mod_name)
208{
209 struct device_driver *drv = &nd_drv->drv;
210
211 if (!nd_drv->type) {
212 pr_debug("driver type bitmask not set (%pf)\n",
213 __builtin_return_address(0));
214 return -EINVAL;
215 }
216
217 if (!nd_drv->probe || !nd_drv->remove) {
218 pr_debug("->probe() and ->remove() must be specified\n");
219 return -EINVAL;
220 }
221
222 drv->bus = &nvdimm_bus_type;
223 drv->owner = owner;
224 drv->mod_name = mod_name;
225
226 return driver_register(drv);
227}
228EXPORT_SYMBOL(__nd_driver_register);
229
58138820
DW
230int nvdimm_revalidate_disk(struct gendisk *disk)
231{
232 struct device *dev = disk->driverfs_dev;
233 struct nd_region *nd_region = to_nd_region(dev->parent);
234 const char *pol = nd_region->ro ? "only" : "write";
235
236 if (nd_region->ro == get_disk_ro(disk))
237 return 0;
238
239 dev_info(dev, "%s read-%s, marking %s read-%s\n",
240 dev_name(&nd_region->dev), pol, disk->disk_name, pol);
241 set_disk_ro(disk, nd_region->ro);
242
243 return 0;
244
245}
246EXPORT_SYMBOL(nvdimm_revalidate_disk);
247
4d88a97a
DW
248static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
249 char *buf)
250{
251 return sprintf(buf, ND_DEVICE_MODALIAS_FMT "\n",
252 to_nd_device_type(dev));
253}
254static DEVICE_ATTR_RO(modalias);
255
256static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
257 char *buf)
258{
259 return sprintf(buf, "%s\n", dev->type->name);
260}
261static DEVICE_ATTR_RO(devtype);
262
263static struct attribute *nd_device_attributes[] = {
264 &dev_attr_modalias.attr,
265 &dev_attr_devtype.attr,
266 NULL,
267};
268
269/**
270 * nd_device_attribute_group - generic attributes for all devices on an nd bus
271 */
272struct attribute_group nd_device_attribute_group = {
273 .attrs = nd_device_attributes,
e6dfb2de 274};
4d88a97a 275EXPORT_SYMBOL_GPL(nd_device_attribute_group);
e6dfb2de 276
45def22c
DW
277int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
278{
279 dev_t devt = MKDEV(nvdimm_bus_major, nvdimm_bus->id);
280 struct device *dev;
281
282 dev = device_create(nd_class, &nvdimm_bus->dev, devt, nvdimm_bus,
283 "ndctl%d", nvdimm_bus->id);
284
285 if (IS_ERR(dev)) {
286 dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %ld\n",
287 nvdimm_bus->id, PTR_ERR(dev));
288 return PTR_ERR(dev);
289 }
290 return 0;
291}
292
293void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus)
294{
295 device_destroy(nd_class, MKDEV(nvdimm_bus_major, nvdimm_bus->id));
296}
297
62232e45
DW
298static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = {
299 [ND_CMD_IMPLEMENTED] = { },
300 [ND_CMD_SMART] = {
301 .out_num = 2,
302 .out_sizes = { 4, 8, },
303 },
304 [ND_CMD_SMART_THRESHOLD] = {
305 .out_num = 2,
306 .out_sizes = { 4, 8, },
307 },
308 [ND_CMD_DIMM_FLAGS] = {
309 .out_num = 2,
310 .out_sizes = { 4, 4 },
311 },
312 [ND_CMD_GET_CONFIG_SIZE] = {
313 .out_num = 3,
314 .out_sizes = { 4, 4, 4, },
315 },
316 [ND_CMD_GET_CONFIG_DATA] = {
317 .in_num = 2,
318 .in_sizes = { 4, 4, },
319 .out_num = 2,
320 .out_sizes = { 4, UINT_MAX, },
321 },
322 [ND_CMD_SET_CONFIG_DATA] = {
323 .in_num = 3,
324 .in_sizes = { 4, 4, UINT_MAX, },
325 .out_num = 1,
326 .out_sizes = { 4, },
327 },
328 [ND_CMD_VENDOR] = {
329 .in_num = 3,
330 .in_sizes = { 4, 4, UINT_MAX, },
331 .out_num = 3,
332 .out_sizes = { 4, 4, UINT_MAX, },
333 },
334};
335
336const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd)
337{
338 if (cmd < ARRAY_SIZE(__nd_cmd_dimm_descs))
339 return &__nd_cmd_dimm_descs[cmd];
340 return NULL;
341}
342EXPORT_SYMBOL_GPL(nd_cmd_dimm_desc);
343
344static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
345 [ND_CMD_IMPLEMENTED] = { },
346 [ND_CMD_ARS_CAP] = {
347 .in_num = 2,
348 .in_sizes = { 8, 8, },
349 .out_num = 2,
350 .out_sizes = { 4, 4, },
351 },
352 [ND_CMD_ARS_START] = {
353 .in_num = 4,
354 .in_sizes = { 8, 8, 2, 6, },
355 .out_num = 1,
356 .out_sizes = { 4, },
357 },
358 [ND_CMD_ARS_STATUS] = {
359 .out_num = 2,
360 .out_sizes = { 4, UINT_MAX, },
361 },
362};
363
364const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd)
365{
366 if (cmd < ARRAY_SIZE(__nd_cmd_bus_descs))
367 return &__nd_cmd_bus_descs[cmd];
368 return NULL;
369}
370EXPORT_SYMBOL_GPL(nd_cmd_bus_desc);
371
372u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
373 const struct nd_cmd_desc *desc, int idx, void *buf)
374{
375 if (idx >= desc->in_num)
376 return UINT_MAX;
377
378 if (desc->in_sizes[idx] < UINT_MAX)
379 return desc->in_sizes[idx];
380
381 if (nvdimm && cmd == ND_CMD_SET_CONFIG_DATA && idx == 2) {
382 struct nd_cmd_set_config_hdr *hdr = buf;
383
384 return hdr->in_length;
385 } else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2) {
386 struct nd_cmd_vendor_hdr *hdr = buf;
387
388 return hdr->in_length;
389 }
390
391 return UINT_MAX;
392}
393EXPORT_SYMBOL_GPL(nd_cmd_in_size);
394
395u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
396 const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
397 const u32 *out_field)
398{
399 if (idx >= desc->out_num)
400 return UINT_MAX;
401
402 if (desc->out_sizes[idx] < UINT_MAX)
403 return desc->out_sizes[idx];
404
405 if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && idx == 1)
406 return in_field[1];
407 else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
408 return out_field[1];
409 else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 1)
410 return ND_CMD_ARS_STATUS_MAX;
411
412 return UINT_MAX;
413}
414EXPORT_SYMBOL_GPL(nd_cmd_out_size);
415
bf9bccc1 416void wait_nvdimm_bus_probe_idle(struct device *dev)
eaf96153 417{
bf9bccc1
DW
418 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
419
eaf96153
DW
420 do {
421 if (nvdimm_bus->probe_active == 0)
422 break;
423 nvdimm_bus_unlock(&nvdimm_bus->dev);
424 wait_event(nvdimm_bus->probe_wait,
425 nvdimm_bus->probe_active == 0);
426 nvdimm_bus_lock(&nvdimm_bus->dev);
427 } while (true);
428}
429
430/* set_config requires an idle interleave set */
431static int nd_cmd_clear_to_send(struct nvdimm *nvdimm, unsigned int cmd)
432{
433 struct nvdimm_bus *nvdimm_bus;
434
435 if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA)
436 return 0;
437
438 nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev);
bf9bccc1 439 wait_nvdimm_bus_probe_idle(&nvdimm_bus->dev);
eaf96153
DW
440
441 if (atomic_read(&nvdimm->busy))
442 return -EBUSY;
443 return 0;
444}
445
62232e45
DW
446static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
447 int read_only, unsigned int ioctl_cmd, unsigned long arg)
448{
449 struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
450 size_t buf_len = 0, in_len = 0, out_len = 0;
451 static char out_env[ND_CMD_MAX_ENVELOPE];
452 static char in_env[ND_CMD_MAX_ENVELOPE];
453 const struct nd_cmd_desc *desc = NULL;
454 unsigned int cmd = _IOC_NR(ioctl_cmd);
455 void __user *p = (void __user *) arg;
456 struct device *dev = &nvdimm_bus->dev;
457 const char *cmd_name, *dimm_name;
458 unsigned long dsm_mask;
459 void *buf;
460 int rc, i;
461
462 if (nvdimm) {
463 desc = nd_cmd_dimm_desc(cmd);
464 cmd_name = nvdimm_cmd_name(cmd);
465 dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0;
466 dimm_name = dev_name(&nvdimm->dev);
467 } else {
468 desc = nd_cmd_bus_desc(cmd);
469 cmd_name = nvdimm_bus_cmd_name(cmd);
470 dsm_mask = nd_desc->dsm_mask;
471 dimm_name = "bus";
472 }
473
474 if (!desc || (desc->out_num + desc->in_num == 0) ||
475 !test_bit(cmd, &dsm_mask))
476 return -ENOTTY;
477
478 /* fail write commands (when read-only) */
479 if (read_only)
480 switch (ioctl_cmd) {
481 case ND_IOCTL_VENDOR:
482 case ND_IOCTL_SET_CONFIG_DATA:
483 case ND_IOCTL_ARS_START:
484 dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
485 nvdimm ? nvdimm_cmd_name(cmd)
486 : nvdimm_bus_cmd_name(cmd));
487 return -EPERM;
488 default:
489 break;
490 }
491
492 /* process an input envelope */
493 for (i = 0; i < desc->in_num; i++) {
494 u32 in_size, copy;
495
496 in_size = nd_cmd_in_size(nvdimm, cmd, desc, i, in_env);
497 if (in_size == UINT_MAX) {
498 dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
499 __func__, dimm_name, cmd_name, i);
500 return -ENXIO;
501 }
502 if (!access_ok(VERIFY_READ, p + in_len, in_size))
503 return -EFAULT;
504 if (in_len < sizeof(in_env))
505 copy = min_t(u32, sizeof(in_env) - in_len, in_size);
506 else
507 copy = 0;
508 if (copy && copy_from_user(&in_env[in_len], p + in_len, copy))
509 return -EFAULT;
510 in_len += in_size;
511 }
512
513 /* process an output envelope */
514 for (i = 0; i < desc->out_num; i++) {
515 u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
516 (u32 *) in_env, (u32 *) out_env);
517 u32 copy;
518
519 if (out_size == UINT_MAX) {
520 dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n",
521 __func__, dimm_name, cmd_name, i);
522 return -EFAULT;
523 }
524 if (!access_ok(VERIFY_WRITE, p + in_len + out_len, out_size))
525 return -EFAULT;
526 if (out_len < sizeof(out_env))
527 copy = min_t(u32, sizeof(out_env) - out_len, out_size);
528 else
529 copy = 0;
530 if (copy && copy_from_user(&out_env[out_len],
531 p + in_len + out_len, copy))
532 return -EFAULT;
533 out_len += out_size;
534 }
535
536 buf_len = out_len + in_len;
537 if (!access_ok(VERIFY_WRITE, p, sizeof(buf_len)))
538 return -EFAULT;
539
540 if (buf_len > ND_IOCTL_MAX_BUFLEN) {
541 dev_dbg(dev, "%s:%s cmd: %s buf_len: %zu > %d\n", __func__,
542 dimm_name, cmd_name, buf_len,
543 ND_IOCTL_MAX_BUFLEN);
544 return -EINVAL;
545 }
546
547 buf = vmalloc(buf_len);
548 if (!buf)
549 return -ENOMEM;
550
551 if (copy_from_user(buf, p, buf_len)) {
552 rc = -EFAULT;
553 goto out;
554 }
555
eaf96153
DW
556 nvdimm_bus_lock(&nvdimm_bus->dev);
557 rc = nd_cmd_clear_to_send(nvdimm, cmd);
558 if (rc)
559 goto out_unlock;
560
62232e45
DW
561 rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
562 if (rc < 0)
eaf96153 563 goto out_unlock;
62232e45
DW
564 if (copy_to_user(p, buf, buf_len))
565 rc = -EFAULT;
eaf96153
DW
566 out_unlock:
567 nvdimm_bus_unlock(&nvdimm_bus->dev);
62232e45
DW
568 out:
569 vfree(buf);
570 return rc;
571}
572
45def22c
DW
573static long nd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
574{
62232e45
DW
575 long id = (long) file->private_data;
576 int rc = -ENXIO, read_only;
577 struct nvdimm_bus *nvdimm_bus;
578
579 read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
580 mutex_lock(&nvdimm_bus_list_mutex);
581 list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
582 if (nvdimm_bus->id == id) {
583 rc = __nd_ioctl(nvdimm_bus, NULL, read_only, cmd, arg);
584 break;
585 }
586 }
587 mutex_unlock(&nvdimm_bus_list_mutex);
588
589 return rc;
590}
591
592static int match_dimm(struct device *dev, void *data)
593{
594 long id = (long) data;
595
596 if (is_nvdimm(dev)) {
597 struct nvdimm *nvdimm = to_nvdimm(dev);
598
599 return nvdimm->id == id;
600 }
601
602 return 0;
603}
604
605static long nvdimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
606{
607 int rc = -ENXIO, read_only;
608 struct nvdimm_bus *nvdimm_bus;
609
610 read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
611 mutex_lock(&nvdimm_bus_list_mutex);
612 list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
613 struct device *dev = device_find_child(&nvdimm_bus->dev,
614 file->private_data, match_dimm);
615 struct nvdimm *nvdimm;
616
617 if (!dev)
618 continue;
619
620 nvdimm = to_nvdimm(dev);
621 rc = __nd_ioctl(nvdimm_bus, nvdimm, read_only, cmd, arg);
622 put_device(dev);
623 break;
624 }
625 mutex_unlock(&nvdimm_bus_list_mutex);
626
627 return rc;
628}
629
630static int nd_open(struct inode *inode, struct file *file)
631{
632 long minor = iminor(inode);
633
634 file->private_data = (void *) minor;
635 return 0;
45def22c
DW
636}
637
638static const struct file_operations nvdimm_bus_fops = {
639 .owner = THIS_MODULE,
62232e45 640 .open = nd_open,
45def22c
DW
641 .unlocked_ioctl = nd_ioctl,
642 .compat_ioctl = nd_ioctl,
643 .llseek = noop_llseek,
644};
645
62232e45
DW
646static const struct file_operations nvdimm_fops = {
647 .owner = THIS_MODULE,
648 .open = nd_open,
649 .unlocked_ioctl = nvdimm_ioctl,
650 .compat_ioctl = nvdimm_ioctl,
651 .llseek = noop_llseek,
652};
653
45def22c
DW
654int __init nvdimm_bus_init(void)
655{
656 int rc;
657
e6dfb2de
DW
658 rc = bus_register(&nvdimm_bus_type);
659 if (rc)
660 return rc;
661
45def22c
DW
662 rc = register_chrdev(0, "ndctl", &nvdimm_bus_fops);
663 if (rc < 0)
62232e45 664 goto err_bus_chrdev;
45def22c
DW
665 nvdimm_bus_major = rc;
666
62232e45
DW
667 rc = register_chrdev(0, "dimmctl", &nvdimm_fops);
668 if (rc < 0)
669 goto err_dimm_chrdev;
670 nvdimm_major = rc;
671
45def22c
DW
672 nd_class = class_create(THIS_MODULE, "nd");
673 if (IS_ERR(nd_class))
674 goto err_class;
675
676 return 0;
677
678 err_class:
62232e45
DW
679 unregister_chrdev(nvdimm_major, "dimmctl");
680 err_dimm_chrdev:
45def22c 681 unregister_chrdev(nvdimm_bus_major, "ndctl");
62232e45 682 err_bus_chrdev:
e6dfb2de 683 bus_unregister(&nvdimm_bus_type);
45def22c
DW
684
685 return rc;
686}
687
4d88a97a 688void nvdimm_bus_exit(void)
45def22c
DW
689{
690 class_destroy(nd_class);
691 unregister_chrdev(nvdimm_bus_major, "ndctl");
62232e45 692 unregister_chrdev(nvdimm_major, "dimmctl");
e6dfb2de 693 bus_unregister(&nvdimm_bus_type);
45def22c 694}