cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

region.c (3973B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
      4 */
      5#include <linux/cpumask.h>
      6#include <linux/module.h>
      7#include <linux/device.h>
      8#include <linux/nd.h>
      9#include "nd-core.h"
     10#include "nd.h"
     11
     12static int nd_region_probe(struct device *dev)
     13{
     14	int err, rc;
     15	static unsigned long once;
     16	struct nd_region_data *ndrd;
     17	struct nd_region *nd_region = to_nd_region(dev);
     18	struct range range = {
     19		.start = nd_region->ndr_start,
     20		.end = nd_region->ndr_start + nd_region->ndr_size - 1,
     21	};
     22
     23	if (nd_region->num_lanes > num_online_cpus()
     24			&& nd_region->num_lanes < num_possible_cpus()
     25			&& !test_and_set_bit(0, &once)) {
     26		dev_dbg(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n",
     27				num_online_cpus(), nd_region->num_lanes,
     28				num_possible_cpus());
     29		dev_dbg(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n",
     30				nd_region->num_lanes);
     31	}
     32
     33	rc = nd_region_activate(nd_region);
     34	if (rc)
     35		return rc;
     36
     37	if (devm_init_badblocks(dev, &nd_region->bb))
     38		return -ENODEV;
     39	nd_region->bb_state =
     40		sysfs_get_dirent(nd_region->dev.kobj.sd, "badblocks");
     41	if (!nd_region->bb_state)
     42		dev_warn(dev, "'badblocks' notification disabled\n");
     43	nvdimm_badblocks_populate(nd_region, &nd_region->bb, &range);
     44
     45	rc = nd_region_register_namespaces(nd_region, &err);
     46	if (rc < 0)
     47		return rc;
     48
     49	ndrd = dev_get_drvdata(dev);
     50	ndrd->ns_active = rc;
     51	ndrd->ns_count = rc + err;
     52
     53	if (rc && err && rc == err)
     54		return -ENODEV;
     55
     56	nd_region->btt_seed = nd_btt_create(nd_region);
     57	nd_region->pfn_seed = nd_pfn_create(nd_region);
     58	nd_region->dax_seed = nd_dax_create(nd_region);
     59	if (err == 0)
     60		return 0;
     61
     62	/*
     63	 * Given multiple namespaces per region, we do not want to
     64	 * disable all the successfully registered peer namespaces upon
     65	 * a single registration failure.  If userspace is missing a
     66	 * namespace that it expects it can disable/re-enable the region
     67	 * to retry discovery after correcting the failure.
     68	 * <regionX>/namespaces returns the current
     69	 * "<async-registered>/<total>" namespace count.
     70	 */
     71	dev_err(dev, "failed to register %d namespace%s, continuing...\n",
     72			err, err == 1 ? "" : "s");
     73	return 0;
     74}
     75
     76static int child_unregister(struct device *dev, void *data)
     77{
     78	nd_device_unregister(dev, ND_SYNC);
     79	return 0;
     80}
     81
     82static void nd_region_remove(struct device *dev)
     83{
     84	struct nd_region *nd_region = to_nd_region(dev);
     85
     86	device_for_each_child(dev, NULL, child_unregister);
     87
     88	/* flush attribute readers and disable */
     89	nvdimm_bus_lock(dev);
     90	nd_region->ns_seed = NULL;
     91	nd_region->btt_seed = NULL;
     92	nd_region->pfn_seed = NULL;
     93	nd_region->dax_seed = NULL;
     94	dev_set_drvdata(dev, NULL);
     95	nvdimm_bus_unlock(dev);
     96
     97	/*
     98	 * Note, this assumes device_lock() context to not race
     99	 * nd_region_notify()
    100	 */
    101	sysfs_put(nd_region->bb_state);
    102	nd_region->bb_state = NULL;
    103}
    104
    105static int child_notify(struct device *dev, void *data)
    106{
    107	nd_device_notify(dev, *(enum nvdimm_event *) data);
    108	return 0;
    109}
    110
    111static void nd_region_notify(struct device *dev, enum nvdimm_event event)
    112{
    113	if (event == NVDIMM_REVALIDATE_POISON) {
    114		struct nd_region *nd_region = to_nd_region(dev);
    115
    116		if (is_memory(&nd_region->dev)) {
    117			struct range range = {
    118				.start = nd_region->ndr_start,
    119				.end = nd_region->ndr_start +
    120					nd_region->ndr_size - 1,
    121			};
    122
    123			nvdimm_badblocks_populate(nd_region,
    124					&nd_region->bb, &range);
    125			if (nd_region->bb_state)
    126				sysfs_notify_dirent(nd_region->bb_state);
    127		}
    128	}
    129	device_for_each_child(dev, &event, child_notify);
    130}
    131
    132static struct nd_device_driver nd_region_driver = {
    133	.probe = nd_region_probe,
    134	.remove = nd_region_remove,
    135	.notify = nd_region_notify,
    136	.drv = {
    137		.name = "nd_region",
    138	},
    139	.type = ND_DRIVER_REGION_BLK | ND_DRIVER_REGION_PMEM,
    140};
    141
    142int __init nd_region_init(void)
    143{
    144	return nd_driver_register(&nd_region_driver);
    145}
    146
    147void nd_region_exit(void)
    148{
    149	driver_unregister(&nd_region_driver.drv);
    150}
    151
    152MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_PMEM);