mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
ccache: Add a compatible for the pic64gx SoC. No driver change needed, as it falls back to the PolarFire SoC. hisi hha/generic cpu cache maintenance: Add support for a non-architectural mechanism for invalidating memory regions, needed for some cxl implementations on arm64 (and probably elsewhere in the future). The HiSilicon Hydra Home Agent is the first driver to provide this support. Signed-off-by: Conor Dooley <conor.dooley@microchip.com> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRh246EGq/8RLhDjO14tDGHoIJi0gUCaSiFRQAKCRB4tDGHoIJi 0glXAQDJ0NsReTniO9TgJkzw05oWwCKoOL4MadxBM/4MRLJXyQD/YWW09btaYxTZ fDVHpb/P2BDD5qNwaXkONMIeoU/iHAo= =zk03 -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmkoyhIACgkQmmx57+YA GNla4xAAw7gN+w/AIBFzh50ZT1DFxIaey67k3OGNEnictgWA8IOYu28brmqv04dT vqppDeviw/fT6MC9A1qykRS8KVPbD1UAfD9w3akQsN6Kzb1h+cjhhv2qw4ZsWbjH XcRj0ZeraL/3Pc7ecTiRvJ3ZebvzPeQNOVmkgaEWZusAsTPPzj+riNg0+LwazHrw BDTLXgDZel/lyt8AIkLWWmzUUnr57VO22ZY1/seT4i161+2XjCaECbsCQzV6rTmo EsYsQWf7G8jX5c2DxjVEkmPGVLJMBclvSgtfLABF/Co2rvVFZbdMjkCkHcySmWq5 KcvXsF+hRcHLC2kZ5jmxpyc0rlChYNGNgJUqJGSKM/sQRQmM0zsAGRZMiEb5ZEF5 xXNYAKVkFVAiIo+zw2ph334GIgv2tU5KB2WrNJu6kxqT7qQGZXO44Bg+1jmc6Q9n efZOTAqOfyeT0pwVpdp8ZJfp/mwLceehFhb8u3OUrkM/xiJlvMFSY3cV568bR2z4 XYvEw5UEJybWPgsm5qXUMPgjPqd8nK/UFAwGSJ7zK6p/EM1B3rrNGo2Kdz2AJwxZ /c4lSpr6Nz0MMQJpCfET9eet8fsAJi7UYopDDdNNTSYgiZ+1ZkUAffQX5wBQpGMI czzuDEHwsLhKFPyQ2bqTYs77YS2qiVaHuKtBABkKYvoNodl8Tik= =wip1 -----END PGP SIGNATURE----- Merge tag 'cache-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/drivers-late standalone cache drivers for v6.19 ccache: Add a compatible for the pic64gx SoC. No driver change needed, as it falls back to the PolarFire SoC. hisi hha/generic cpu cache maintenance: Add support for a non-architectural mechanism for invalidating memory regions, needed for some cxl implementations on arm64 (and probably elsewhere in the future). The HiSilicon Hydra Home Agent is the first driver to provide this support. Signed-off-by: Conor Dooley <conor.dooley@microchip.com> * tag 'cache-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux: MAINTAINERS: refer to intended file in STANDALONE CACHE CONTROLLER DRIVERS cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent cache: Make top level Kconfig menu a boolean dependent on RISCV MAINTAINERS: Add Jonathan Cameron to drivers/cache and add lib/cache_maint.c + header arm64: Select GENERIC_CPU_CACHE_MAINTENANCE lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion() memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion() dt-bindings: cache: sifive,ccache0: add a pic64gx compatible Signed-off-by: Arnd Bergmann <arnd@arndb.de>
164 lines
4.3 KiB
C
164 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
|
|
*/
|
|
#include <linux/memregion.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/nd.h>
|
|
#include "nd-core.h"
|
|
#include "nd.h"
|
|
|
|
static int nd_region_probe(struct device *dev)
|
|
{
|
|
int err, rc;
|
|
static unsigned long once;
|
|
struct nd_region_data *ndrd;
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
struct range range = {
|
|
.start = nd_region->ndr_start,
|
|
.end = nd_region->ndr_start + nd_region->ndr_size - 1,
|
|
};
|
|
|
|
if (nd_region->num_lanes > num_online_cpus()
|
|
&& nd_region->num_lanes < num_possible_cpus()
|
|
&& !test_and_set_bit(0, &once)) {
|
|
dev_dbg(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n",
|
|
num_online_cpus(), nd_region->num_lanes,
|
|
num_possible_cpus());
|
|
dev_dbg(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n",
|
|
nd_region->num_lanes);
|
|
}
|
|
|
|
rc = nd_region_activate(nd_region);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (devm_init_badblocks(dev, &nd_region->bb))
|
|
return -ENODEV;
|
|
nd_region->bb_state =
|
|
sysfs_get_dirent(nd_region->dev.kobj.sd, "badblocks");
|
|
if (!nd_region->bb_state)
|
|
dev_warn(dev, "'badblocks' notification disabled\n");
|
|
nvdimm_badblocks_populate(nd_region, &nd_region->bb, &range);
|
|
|
|
rc = nd_region_register_namespaces(nd_region, &err);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
ndrd = dev_get_drvdata(dev);
|
|
ndrd->ns_active = rc;
|
|
ndrd->ns_count = rc + err;
|
|
|
|
if (rc && err && rc == err)
|
|
return -ENODEV;
|
|
|
|
nd_region->btt_seed = nd_btt_create(nd_region);
|
|
nd_region->pfn_seed = nd_pfn_create(nd_region);
|
|
nd_region->dax_seed = nd_dax_create(nd_region);
|
|
if (err == 0)
|
|
return 0;
|
|
|
|
/*
|
|
* Given multiple namespaces per region, we do not want to
|
|
* disable all the successfully registered peer namespaces upon
|
|
* a single registration failure. If userspace is missing a
|
|
* namespace that it expects it can disable/re-enable the region
|
|
* to retry discovery after correcting the failure.
|
|
* <regionX>/namespaces returns the current
|
|
* "<async-registered>/<total>" namespace count.
|
|
*/
|
|
dev_err(dev, "failed to register %d namespace%s, continuing...\n",
|
|
err, str_plural(err));
|
|
return 0;
|
|
}
|
|
|
|
static int child_unregister(struct device *dev, void *data)
|
|
{
|
|
nd_device_unregister(dev, ND_SYNC);
|
|
return 0;
|
|
}
|
|
|
|
static void nd_region_remove(struct device *dev)
|
|
{
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
device_for_each_child(dev, NULL, child_unregister);
|
|
|
|
/* flush attribute readers and disable */
|
|
scoped_guard(nvdimm_bus, dev) {
|
|
nd_region->ns_seed = NULL;
|
|
nd_region->btt_seed = NULL;
|
|
nd_region->pfn_seed = NULL;
|
|
nd_region->dax_seed = NULL;
|
|
dev_set_drvdata(dev, NULL);
|
|
}
|
|
|
|
/*
|
|
* Note, this assumes device_lock() context to not race
|
|
* nd_region_notify()
|
|
*/
|
|
sysfs_put(nd_region->bb_state);
|
|
nd_region->bb_state = NULL;
|
|
|
|
/*
|
|
* Try to flush caches here since a disabled region may be subject to
|
|
* secure erase while disabled, and previous dirty data should not be
|
|
* written back to a new instance of the region. This only matters on
|
|
* bare metal where security commands are available, so silent failure
|
|
* here is ok.
|
|
*/
|
|
if (cpu_cache_has_invalidate_memregion())
|
|
cpu_cache_invalidate_all();
|
|
}
|
|
|
|
static int child_notify(struct device *dev, void *data)
|
|
{
|
|
nd_device_notify(dev, *(enum nvdimm_event *) data);
|
|
return 0;
|
|
}
|
|
|
|
static void nd_region_notify(struct device *dev, enum nvdimm_event event)
|
|
{
|
|
if (event == NVDIMM_REVALIDATE_POISON) {
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
if (is_memory(&nd_region->dev)) {
|
|
struct range range = {
|
|
.start = nd_region->ndr_start,
|
|
.end = nd_region->ndr_start +
|
|
nd_region->ndr_size - 1,
|
|
};
|
|
|
|
nvdimm_badblocks_populate(nd_region,
|
|
&nd_region->bb, &range);
|
|
if (nd_region->bb_state)
|
|
sysfs_notify_dirent(nd_region->bb_state);
|
|
}
|
|
}
|
|
device_for_each_child(dev, &event, child_notify);
|
|
}
|
|
|
|
static struct nd_device_driver nd_region_driver = {
|
|
.probe = nd_region_probe,
|
|
.remove = nd_region_remove,
|
|
.notify = nd_region_notify,
|
|
.drv = {
|
|
.name = "nd_region",
|
|
},
|
|
.type = ND_DRIVER_REGION_BLK | ND_DRIVER_REGION_PMEM,
|
|
};
|
|
|
|
int __init nd_region_init(void)
|
|
{
|
|
return nd_driver_register(&nd_region_driver);
|
|
}
|
|
|
|
void nd_region_exit(void)
|
|
{
|
|
driver_unregister(&nd_region_driver.drv);
|
|
}
|
|
|
|
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_PMEM);
|