13d88002eSDan Williams /* 23d88002eSDan Williams * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. 33d88002eSDan Williams * 43d88002eSDan Williams * This program is free software; you can redistribute it and/or modify 53d88002eSDan Williams * it under the terms of version 2 of the GNU General Public License as 63d88002eSDan Williams * published by the Free Software Foundation. 73d88002eSDan Williams * 83d88002eSDan Williams * This program is distributed in the hope that it will be useful, but 93d88002eSDan Williams * WITHOUT ANY WARRANTY; without even the implied warranty of 103d88002eSDan Williams * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 113d88002eSDan Williams * General Public License for more details. 123d88002eSDan Williams */ 135212e11fSVishal Verma #include <linux/cpumask.h> 143d88002eSDan Williams #include <linux/module.h> 153d88002eSDan Williams #include <linux/device.h> 163d88002eSDan Williams #include <linux/nd.h> 173d88002eSDan Williams #include "nd.h" 183d88002eSDan Williams 193d88002eSDan Williams static int nd_region_probe(struct device *dev) 203d88002eSDan Williams { 21047fc8a1SRoss Zwisler int err, rc; 225212e11fSVishal Verma static unsigned long once; 233d88002eSDan Williams struct nd_region_namespaces *num_ns; 243d88002eSDan Williams struct nd_region *nd_region = to_nd_region(dev); 253d88002eSDan Williams 265212e11fSVishal Verma if (nd_region->num_lanes > num_online_cpus() 275212e11fSVishal Verma && nd_region->num_lanes < num_possible_cpus() 285212e11fSVishal Verma && !test_and_set_bit(0, &once)) { 295212e11fSVishal Verma dev_info(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n", 305212e11fSVishal Verma num_online_cpus(), nd_region->num_lanes, 315212e11fSVishal Verma num_possible_cpus()); 325212e11fSVishal Verma dev_info(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n", 335212e11fSVishal Verma nd_region->num_lanes); 345212e11fSVishal Verma } 355212e11fSVishal Verma 36047fc8a1SRoss Zwisler rc = nd_blk_region_init(nd_region); 37047fc8a1SRoss Zwisler if (rc) 38047fc8a1SRoss Zwisler return rc; 39047fc8a1SRoss Zwisler 40047fc8a1SRoss Zwisler rc = nd_region_register_namespaces(nd_region, &err); 413d88002eSDan Williams num_ns = devm_kzalloc(dev, sizeof(*num_ns), GFP_KERNEL); 423d88002eSDan Williams if (!num_ns) 433d88002eSDan Williams return -ENOMEM; 443d88002eSDan Williams 453d88002eSDan Williams if (rc < 0) 463d88002eSDan Williams return rc; 473d88002eSDan Williams 483d88002eSDan Williams num_ns->active = rc; 493d88002eSDan Williams num_ns->count = rc + err; 503d88002eSDan Williams dev_set_drvdata(dev, num_ns); 513d88002eSDan Williams 528c2f7e86SDan Williams if (rc && err && rc == err) 538c2f7e86SDan Williams return -ENODEV; 548c2f7e86SDan Williams 558c2f7e86SDan Williams nd_region->btt_seed = nd_btt_create(nd_region); 56e1455744SDan Williams nd_region->pfn_seed = nd_pfn_create(nd_region); 57cd03412aSDan Williams nd_region->dax_seed = nd_dax_create(nd_region); 583d88002eSDan Williams if (err == 0) 593d88002eSDan Williams return 0; 603d88002eSDan Williams 613d88002eSDan Williams /* 623d88002eSDan Williams * Given multiple namespaces per region, we do not want to 633d88002eSDan Williams * disable all the successfully registered peer namespaces upon 643d88002eSDan Williams * a single registration failure. If userspace is missing a 653d88002eSDan Williams * namespace that it expects it can disable/re-enable the region 663d88002eSDan Williams * to retry discovery after correcting the failure. 673d88002eSDan Williams * <regionX>/namespaces returns the current 683d88002eSDan Williams * "<async-registered>/<total>" namespace count. 693d88002eSDan Williams */ 703d88002eSDan Williams dev_err(dev, "failed to register %d namespace%s, continuing...\n", 713d88002eSDan Williams err, err == 1 ? "" : "s"); 723d88002eSDan Williams return 0; 733d88002eSDan Williams } 743d88002eSDan Williams 753d88002eSDan Williams static int child_unregister(struct device *dev, void *data) 763d88002eSDan Williams { 773d88002eSDan Williams nd_device_unregister(dev, ND_SYNC); 783d88002eSDan Williams return 0; 793d88002eSDan Williams } 803d88002eSDan Williams 813d88002eSDan Williams static int nd_region_remove(struct device *dev) 823d88002eSDan Williams { 83bf9bccc1SDan Williams struct nd_region *nd_region = to_nd_region(dev); 84bf9bccc1SDan Williams 853d88002eSDan Williams /* flush attribute readers and disable */ 863d88002eSDan Williams nvdimm_bus_lock(dev); 87bf9bccc1SDan Williams nd_region->ns_seed = NULL; 888c2f7e86SDan Williams nd_region->btt_seed = NULL; 89e1455744SDan Williams nd_region->pfn_seed = NULL; 90cd03412aSDan Williams nd_region->dax_seed = NULL; 913d88002eSDan Williams dev_set_drvdata(dev, NULL); 923d88002eSDan Williams nvdimm_bus_unlock(dev); 933d88002eSDan Williams 943d88002eSDan Williams device_for_each_child(dev, NULL, child_unregister); 953d88002eSDan Williams return 0; 963d88002eSDan Williams } 973d88002eSDan Williams 9871999466SDan Williams static int child_notify(struct device *dev, void *data) 9971999466SDan Williams { 10071999466SDan Williams nd_device_notify(dev, *(enum nvdimm_event *) data); 10171999466SDan Williams return 0; 10271999466SDan Williams } 10371999466SDan Williams 10471999466SDan Williams static void nd_region_notify(struct device *dev, enum nvdimm_event event) 10571999466SDan Williams { 10671999466SDan Williams device_for_each_child(dev, &event, child_notify); 10771999466SDan Williams } 10871999466SDan Williams 1093d88002eSDan Williams static struct nd_device_driver nd_region_driver = { 1103d88002eSDan Williams .probe = nd_region_probe, 1113d88002eSDan Williams .remove = nd_region_remove, 11271999466SDan Williams .notify = nd_region_notify, 1133d88002eSDan Williams .drv = { 1143d88002eSDan Williams .name = "nd_region", 1153d88002eSDan Williams }, 1163d88002eSDan Williams .type = ND_DRIVER_REGION_BLK | ND_DRIVER_REGION_PMEM, 1173d88002eSDan Williams }; 1183d88002eSDan Williams 1193d88002eSDan Williams int __init nd_region_init(void) 1203d88002eSDan Williams { 1213d88002eSDan Williams return nd_driver_register(&nd_region_driver); 1223d88002eSDan Williams } 1233d88002eSDan Williams 1243d88002eSDan Williams void nd_region_exit(void) 1253d88002eSDan Williams { 1263d88002eSDan Williams driver_unregister(&nd_region_driver.drv); 1273d88002eSDan Williams } 1283d88002eSDan Williams 1293d88002eSDan Williams MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_PMEM); 1303d88002eSDan Williams MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_BLK); 131