mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
libnvdimm for 4.13
* Introduce the _flushcache() family of memory copy helpers and use them
for persistent memory write operations on x86. The _flushcache()
semantic indicates that the cache is either bypassed for the copy
operation (movnt) or any lines dirtied by the copy operation are
written back (clwb, clflushopt, or clflush).
* Extend dax_operations with ->copy_from_iter() and ->flush()
operations. These operations and other infrastructure updates allow
all persistent memory specific dax functionality to be pushed into
libnvdimm and the pmem driver directly. It also allows dax-specific
sysfs attributes to be linked to a host device, for example:
/sys/block/pmem0/dax/write_cache
* Add support for the new NVDIMM platform/firmware mechanisms introduced
in ACPI 6.2 and UEFI 2.7. This support includes the v1.2 namespace
label format, extensions to the address-range-scrub command set, new
error injection commands, and a new BTT (block-translation-table)
layout. These updates support inter-OS and pre-OS compatibility.
* Fix a longstanding memory corruption bug in nfit_test.
* Make the pmem and nvdimm-region 'badblocks' sysfs files poll(2)
capable.
* Miscellaneous fixes and small updates across libnvdimm and the nfit
driver.
Acknowledgements that came after the branch was pushed:
commit 6aa734a2f3 "libnvdimm, region, pmem: fix 'badblocks'
sysfs_get_dirent() reference lifetime"
Reviewed-by: Toshi Kani <[email protected]>
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJZXsUtAAoJEB7SkWpmfYgCOXcP/06bncqTEvtgrOF2b7O8w+8e
mTySD51RUn6UpkFd37SMRch+rmbojuqj465TAE7XIXgyLgIOJixKaTlHYUoEnP3X
rC4Q/g5mN0nittMDwL+vQaa1lQWd2kbjOlrqCgnLHVEEJpHmiQussunjvir4G1U7
5ROooP8W+qMK5y5XPLJAg/gyGhYkjpRSlDg3Eo5meZZ0IdURbI7+WCLKrPcQUERT
WmDc9gLhJdSQVxBV/0m2gdAER4ADmFjcrlm8kjXRBhdlUmEFjM0zpvlHJutHTkks
rNZWCmCJs0Sas+DmRKszFmvVFHRHqUVA3dWK4P6PJEX+tl7BwlPcxpbfacHTG2EZ
btArFc584DZ+EIrim1cXXRvLFlxnKOFBtBeteFs7l2kZjEcN6S4I5OZgTyeDpe/i
2WDpHWLQWibkcIzH9y1EuMBkYnQjTJl1pecHzJoTaC+jAQ+opLiY7EecjLmCmQS6
MBYUeQZNufLGfT5b8KXfpKeiXhpFkYrAGp+ErfoH/6RKy2zqTdagN1yVhos2y+a7
JJu/Weetpn8qv+KTGUShO8TGyWv3wU46YkG2rKWl0FL1+C+6LMMw1/L0A97lwVlg
BpypVVyaNu1D22ifZ8O5wbqPIYghoZ5akA0CiduhX19cpl5rTeTd8EvLjvcYhZEZ
pMHuMAqIcIyLhIe2/sRF
=xKQB
-----END PGP SIGNATURE-----
Merge tag 'libnvdimm-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams:
"libnvdimm updates for the latest ACPI and UEFI specifications. This
pull request also includes new 'struct dax_operations' enabling to
undo the abuse of copy_user_nocache() for copy operations to pmem.
The dax work originally missed 4.12 to address concerns raised by Al.
Summary:
- Introduce the _flushcache() family of memory copy helpers and use
them for persistent memory write operations on x86. The
_flushcache() semantic indicates that the cache is either bypassed
for the copy operation (movnt) or any lines dirtied by the copy
operation are written back (clwb, clflushopt, or clflush).
- Extend dax_operations with ->copy_from_iter() and ->flush()
operations. These operations and other infrastructure updates allow
all persistent memory specific dax functionality to be pushed into
libnvdimm and the pmem driver directly. It also allows dax-specific
sysfs attributes to be linked to a host device, for example:
/sys/block/pmem0/dax/write_cache
- Add support for the new NVDIMM platform/firmware mechanisms
introduced in ACPI 6.2 and UEFI 2.7. This support includes the v1.2
namespace label format, extensions to the address-range-scrub
command set, new error injection commands, and a new BTT
(block-translation-table) layout. These updates support inter-OS
and pre-OS compatibility.
- Fix a longstanding memory corruption bug in nfit_test.
- Make the pmem and nvdimm-region 'badblocks' sysfs files poll(2)
capable.
- Miscellaneous fixes and small updates across libnvdimm and the nfit
driver.
Acknowledgements that came after the branch was pushed: commit
6aa734a2f3 ("libnvdimm, region, pmem: fix 'badblocks'
sysfs_get_dirent() reference lifetime") was reviewed by Toshi Kani
<[email protected]>"
* tag 'libnvdimm-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (42 commits)
libnvdimm, namespace: record 'lbasize' for pmem namespaces
acpi/nfit: Issue Start ARS to retrieve existing records
libnvdimm: New ACPI 6.2 DSM functions
acpi, nfit: Show bus_dsm_mask in sysfs
libnvdimm, acpi, nfit: Add bus level dsm mask for pass thru.
acpi, nfit: Enable DSM pass thru for root functions.
libnvdimm: passthru functions clear to send
libnvdimm, btt: convert some info messages to warn/err
libnvdimm, region, pmem: fix 'badblocks' sysfs_get_dirent() reference lifetime
libnvdimm: fix the clear-error check in nsio_rw_bytes
libnvdimm, btt: fix btt_rw_page not returning errors
acpi, nfit: quiet invalid block-aperture-region warnings
libnvdimm, btt: BTT updates for UEFI 2.7 format
acpi, nfit: constify *_attribute_group
libnvdimm, pmem: disable dax flushing when pmem is fronting a volatile region
libnvdimm, pmem, dax: export a cache control attribute
dax: convert to bitmask for flags
dax: remove default copy_from_iter fallback
libnvdimm, nfit: enable support for volatile ranges
libnvdimm, pmem: fix persistence warning
...
This commit is contained in:
commit
b6ffe9ba46
47 changed files with 1504 additions and 460 deletions
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/pmem.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/nd.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
|
@ -253,6 +252,8 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
|||
cmd_name = nvdimm_bus_cmd_name(cmd);
|
||||
cmd_mask = nd_desc->cmd_mask;
|
||||
dsm_mask = cmd_mask;
|
||||
if (cmd == ND_CMD_CALL)
|
||||
dsm_mask = nd_desc->bus_dsm_mask;
|
||||
desc = nd_cmd_bus_desc(cmd);
|
||||
guid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
handle = adev->handle;
|
||||
|
|
@ -927,6 +928,17 @@ static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t bus_dsm_mask_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
|
||||
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
|
||||
|
||||
return sprintf(buf, "%#lx\n", nd_desc->bus_dsm_mask);
|
||||
}
|
||||
static struct device_attribute dev_attr_bus_dsm_mask =
|
||||
__ATTR(dsm_mask, 0444, bus_dsm_mask_show, NULL);
|
||||
|
||||
static ssize_t revision_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -1031,7 +1043,7 @@ static ssize_t scrub_store(struct device *dev,
|
|||
if (nd_desc) {
|
||||
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
||||
|
||||
rc = acpi_nfit_ars_rescan(acpi_desc);
|
||||
rc = acpi_nfit_ars_rescan(acpi_desc, 0);
|
||||
}
|
||||
device_unlock(dev);
|
||||
if (rc)
|
||||
|
|
@ -1063,10 +1075,11 @@ static struct attribute *acpi_nfit_attributes[] = {
|
|||
&dev_attr_revision.attr,
|
||||
&dev_attr_scrub.attr,
|
||||
&dev_attr_hw_error_scrub.attr,
|
||||
&dev_attr_bus_dsm_mask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group acpi_nfit_attribute_group = {
|
||||
static const struct attribute_group acpi_nfit_attribute_group = {
|
||||
.name = "nfit",
|
||||
.attrs = acpi_nfit_attributes,
|
||||
.is_visible = nfit_visible,
|
||||
|
|
@ -1346,7 +1359,7 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
|
|||
return a->mode;
|
||||
}
|
||||
|
||||
static struct attribute_group acpi_nfit_dimm_attribute_group = {
|
||||
static const struct attribute_group acpi_nfit_dimm_attribute_group = {
|
||||
.name = "nfit",
|
||||
.attrs = acpi_nfit_dimm_attributes,
|
||||
.is_visible = acpi_nfit_dimm_attr_visible,
|
||||
|
|
@ -1608,11 +1621,23 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
|
|||
acpi_desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* These constants are private because there are no kernel consumers of
|
||||
* these commands.
|
||||
*/
|
||||
enum nfit_aux_cmds {
|
||||
NFIT_CMD_TRANSLATE_SPA = 5,
|
||||
NFIT_CMD_ARS_INJECT_SET = 7,
|
||||
NFIT_CMD_ARS_INJECT_CLEAR = 8,
|
||||
NFIT_CMD_ARS_INJECT_GET = 9,
|
||||
};
|
||||
|
||||
static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
||||
{
|
||||
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
|
||||
const guid_t *guid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
struct acpi_device *adev;
|
||||
unsigned long dsm_mask;
|
||||
int i;
|
||||
|
||||
nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
|
||||
|
|
@ -1623,6 +1648,20 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
|||
for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
|
||||
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
|
||||
set_bit(i, &nd_desc->cmd_mask);
|
||||
set_bit(ND_CMD_CALL, &nd_desc->cmd_mask);
|
||||
|
||||
dsm_mask =
|
||||
(1 << ND_CMD_ARS_CAP) |
|
||||
(1 << ND_CMD_ARS_START) |
|
||||
(1 << ND_CMD_ARS_STATUS) |
|
||||
(1 << ND_CMD_CLEAR_ERROR) |
|
||||
(1 << NFIT_CMD_TRANSLATE_SPA) |
|
||||
(1 << NFIT_CMD_ARS_INJECT_SET) |
|
||||
(1 << NFIT_CMD_ARS_INJECT_CLEAR) |
|
||||
(1 << NFIT_CMD_ARS_INJECT_GET);
|
||||
for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
|
||||
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
|
||||
set_bit(i, &nd_desc->bus_dsm_mask);
|
||||
}
|
||||
|
||||
static ssize_t range_index_show(struct device *dev,
|
||||
|
|
@ -1640,7 +1679,7 @@ static struct attribute *acpi_nfit_region_attributes[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group acpi_nfit_region_attribute_group = {
|
||||
static const struct attribute_group acpi_nfit_region_attribute_group = {
|
||||
.name = "nfit",
|
||||
.attrs = acpi_nfit_region_attributes,
|
||||
};
|
||||
|
|
@ -1663,12 +1702,29 @@ struct nfit_set_info {
|
|||
} mapping[0];
|
||||
};
|
||||
|
||||
struct nfit_set_info2 {
|
||||
struct nfit_set_info_map2 {
|
||||
u64 region_offset;
|
||||
u32 serial_number;
|
||||
u16 vendor_id;
|
||||
u16 manufacturing_date;
|
||||
u8 manufacturing_location;
|
||||
u8 reserved[31];
|
||||
} mapping[0];
|
||||
};
|
||||
|
||||
static size_t sizeof_nfit_set_info(int num_mappings)
|
||||
{
|
||||
return sizeof(struct nfit_set_info)
|
||||
+ num_mappings * sizeof(struct nfit_set_info_map);
|
||||
}
|
||||
|
||||
static size_t sizeof_nfit_set_info2(int num_mappings)
|
||||
{
|
||||
return sizeof(struct nfit_set_info2)
|
||||
+ num_mappings * sizeof(struct nfit_set_info_map2);
|
||||
}
|
||||
|
||||
static int cmp_map_compat(const void *m0, const void *m1)
|
||||
{
|
||||
const struct nfit_set_info_map *map0 = m0;
|
||||
|
|
@ -1690,6 +1746,18 @@ static int cmp_map(const void *m0, const void *m1)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_map2(const void *m0, const void *m1)
|
||||
{
|
||||
const struct nfit_set_info_map2 *map0 = m0;
|
||||
const struct nfit_set_info_map2 *map1 = m1;
|
||||
|
||||
if (map0->region_offset < map1->region_offset)
|
||||
return -1;
|
||||
else if (map0->region_offset > map1->region_offset)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve the nth entry referencing this spa */
|
||||
static struct acpi_nfit_memory_map *memdev_from_spa(
|
||||
struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
|
||||
|
|
@ -1707,27 +1775,31 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
|
|||
struct nd_region_desc *ndr_desc,
|
||||
struct acpi_nfit_system_address *spa)
|
||||
{
|
||||
int i, spa_type = nfit_spa_type(spa);
|
||||
struct device *dev = acpi_desc->dev;
|
||||
struct nd_interleave_set *nd_set;
|
||||
u16 nr = ndr_desc->num_mappings;
|
||||
struct nfit_set_info2 *info2;
|
||||
struct nfit_set_info *info;
|
||||
|
||||
if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
|
||||
/* pass */;
|
||||
else
|
||||
return 0;
|
||||
int i;
|
||||
|
||||
nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
|
||||
if (!nd_set)
|
||||
return -ENOMEM;
|
||||
ndr_desc->nd_set = nd_set;
|
||||
guid_copy(&nd_set->type_guid, (guid_t *) spa->range_guid);
|
||||
|
||||
info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info2 = devm_kzalloc(dev, sizeof_nfit_set_info2(nr), GFP_KERNEL);
|
||||
if (!info2)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
|
||||
struct nfit_set_info_map *map = &info->mapping[i];
|
||||
struct nfit_set_info_map2 *map2 = &info2->mapping[i];
|
||||
struct nvdimm *nvdimm = mapping->nvdimm;
|
||||
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
||||
struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
|
||||
|
|
@ -1740,19 +1812,32 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
|
|||
|
||||
map->region_offset = memdev->region_offset;
|
||||
map->serial_number = nfit_mem->dcr->serial_number;
|
||||
|
||||
map2->region_offset = memdev->region_offset;
|
||||
map2->serial_number = nfit_mem->dcr->serial_number;
|
||||
map2->vendor_id = nfit_mem->dcr->vendor_id;
|
||||
map2->manufacturing_date = nfit_mem->dcr->manufacturing_date;
|
||||
map2->manufacturing_location = nfit_mem->dcr->manufacturing_location;
|
||||
}
|
||||
|
||||
/* v1.1 namespaces */
|
||||
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
|
||||
cmp_map, NULL);
|
||||
nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
|
||||
nd_set->cookie1 = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
|
||||
|
||||
/* support namespaces created with the wrong sort order */
|
||||
/* v1.2 namespaces */
|
||||
sort(&info2->mapping[0], nr, sizeof(struct nfit_set_info_map2),
|
||||
cmp_map2, NULL);
|
||||
nd_set->cookie2 = nd_fletcher64(info2, sizeof_nfit_set_info2(nr), 0);
|
||||
|
||||
/* support v1.1 namespaces created with the wrong sort order */
|
||||
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
|
||||
cmp_map_compat, NULL);
|
||||
nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
|
||||
|
||||
ndr_desc->nd_set = nd_set;
|
||||
devm_kfree(dev, info);
|
||||
devm_kfree(dev, info2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1842,8 +1927,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
|
|||
}
|
||||
|
||||
if (rw)
|
||||
memcpy_to_pmem(mmio->addr.aperture + offset,
|
||||
iobuf + copied, c);
|
||||
memcpy_flushcache(mmio->addr.aperture + offset, iobuf + copied, c);
|
||||
else {
|
||||
if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
|
||||
mmio_flush_range((void __force *)
|
||||
|
|
@ -1957,7 +2041,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
|
|||
nfit_blk->bdw_offset = nfit_mem->bdw->offset;
|
||||
mmio = &nfit_blk->mmio[BDW];
|
||||
mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address,
|
||||
nfit_mem->spa_bdw->length, ARCH_MEMREMAP_PMEM);
|
||||
nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr));
|
||||
if (!mmio->addr.base) {
|
||||
dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
|
||||
nvdimm_name(nvdimm));
|
||||
|
|
@ -2051,6 +2135,7 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa
|
|||
memset(&ars_start, 0, sizeof(ars_start));
|
||||
ars_start.address = spa->address;
|
||||
ars_start.length = spa->length;
|
||||
ars_start.flags = acpi_desc->ars_start_flags;
|
||||
if (nfit_spa_type(spa) == NFIT_SPA_PM)
|
||||
ars_start.type = ND_ARS_PERSISTENT;
|
||||
else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
|
||||
|
|
@ -2077,6 +2162,7 @@ static int ars_continue(struct acpi_nfit_desc *acpi_desc)
|
|||
ars_start.address = ars_status->restart_address;
|
||||
ars_start.length = ars_status->restart_length;
|
||||
ars_start.type = ars_status->type;
|
||||
ars_start.flags = acpi_desc->ars_start_flags;
|
||||
rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
|
||||
sizeof(ars_start), &cmd_rc);
|
||||
if (rc < 0)
|
||||
|
|
@ -2179,7 +2265,7 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
|
|||
struct acpi_nfit_system_address *spa = nfit_spa->spa;
|
||||
struct nd_blk_region_desc *ndbr_desc;
|
||||
struct nfit_mem *nfit_mem;
|
||||
int blk_valid = 0;
|
||||
int blk_valid = 0, rc;
|
||||
|
||||
if (!nvdimm) {
|
||||
dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
|
||||
|
|
@ -2211,6 +2297,9 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
|
|||
ndbr_desc = to_blk_region_desc(ndr_desc);
|
||||
ndbr_desc->enable = acpi_nfit_blk_region_enable;
|
||||
ndbr_desc->do_io = acpi_desc->blk_do_io;
|
||||
rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
|
||||
if (rc)
|
||||
return rc;
|
||||
nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
|
||||
ndr_desc);
|
||||
if (!nfit_spa->nd_region)
|
||||
|
|
@ -2229,6 +2318,13 @@ static bool nfit_spa_is_virtual(struct acpi_nfit_system_address *spa)
|
|||
nfit_spa_type(spa) == NFIT_SPA_PCD);
|
||||
}
|
||||
|
||||
static bool nfit_spa_is_volatile(struct acpi_nfit_system_address *spa)
|
||||
{
|
||||
return (nfit_spa_type(spa) == NFIT_SPA_VDISK ||
|
||||
nfit_spa_type(spa) == NFIT_SPA_VCD ||
|
||||
nfit_spa_type(spa) == NFIT_SPA_VOLATILE);
|
||||
}
|
||||
|
||||
static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
|
||||
struct nfit_spa *nfit_spa)
|
||||
{
|
||||
|
|
@ -2303,7 +2399,7 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
|
|||
ndr_desc);
|
||||
if (!nfit_spa->nd_region)
|
||||
rc = -ENOMEM;
|
||||
} else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
|
||||
} else if (nfit_spa_is_volatile(spa)) {
|
||||
nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
|
||||
ndr_desc);
|
||||
if (!nfit_spa->nd_region)
|
||||
|
|
@ -2595,6 +2691,7 @@ static void acpi_nfit_scrub(struct work_struct *work)
|
|||
list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
|
||||
acpi_nfit_async_scrub(acpi_desc, nfit_spa);
|
||||
acpi_desc->scrub_count++;
|
||||
acpi_desc->ars_start_flags = 0;
|
||||
if (acpi_desc->scrub_count_state)
|
||||
sysfs_notify_dirent(acpi_desc->scrub_count_state);
|
||||
mutex_unlock(&acpi_desc->init_mutex);
|
||||
|
|
@ -2613,6 +2710,7 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
|
|||
return rc;
|
||||
}
|
||||
|
||||
acpi_desc->ars_start_flags = 0;
|
||||
if (!acpi_desc->cancel)
|
||||
queue_work(nfit_wq, &acpi_desc->work);
|
||||
return 0;
|
||||
|
|
@ -2817,7 +2915,7 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc)
|
||||
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags)
|
||||
{
|
||||
struct device *dev = acpi_desc->dev;
|
||||
struct nfit_spa *nfit_spa;
|
||||
|
|
@ -2839,6 +2937,7 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc)
|
|||
|
||||
nfit_spa->ars_required = 1;
|
||||
}
|
||||
acpi_desc->ars_start_flags = flags;
|
||||
queue_work(nfit_wq, &acpi_desc->work);
|
||||
dev_dbg(dev, "%s: ars_scan triggered\n", __func__);
|
||||
mutex_unlock(&acpi_desc->init_mutex);
|
||||
|
|
@ -2967,7 +3066,7 @@ static int acpi_nfit_remove(struct acpi_device *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
|
||||
static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
|
||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
|
@ -2975,11 +3074,6 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
|
|||
acpi_status status;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s: event: %d\n", __func__, event);
|
||||
|
||||
if (event != NFIT_NOTIFY_UPDATE)
|
||||
return;
|
||||
|
||||
if (!dev->driver) {
|
||||
/* dev->driver may be null if we're being removed */
|
||||
dev_dbg(dev, "%s: no driver found for dev\n", __func__);
|
||||
|
|
@ -3016,6 +3110,29 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
|
|||
dev_err(dev, "Invalid _FIT\n");
|
||||
kfree(buf.pointer);
|
||||
}
|
||||
|
||||
static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
|
||||
u8 flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ?
|
||||
0 : ND_ARS_RETURN_PREV_DATA;
|
||||
|
||||
acpi_nfit_ars_rescan(acpi_desc, flags);
|
||||
}
|
||||
|
||||
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
|
||||
{
|
||||
dev_dbg(dev, "%s: event: 0x%x\n", __func__, event);
|
||||
|
||||
switch (event) {
|
||||
case NFIT_NOTIFY_UPDATE:
|
||||
return acpi_nfit_update_notify(dev, handle);
|
||||
case NFIT_NOTIFY_UC_MEMORY_ERROR:
|
||||
return acpi_nfit_uc_error_notify(dev, handle);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__acpi_nfit_notify);
|
||||
|
||||
static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val,
|
|||
* already in progress, just let that be the last
|
||||
* authoritative one
|
||||
*/
|
||||
acpi_nfit_ars_rescan(acpi_desc);
|
||||
acpi_nfit_ars_rescan(acpi_desc, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ enum {
|
|||
|
||||
enum nfit_root_notifiers {
|
||||
NFIT_NOTIFY_UPDATE = 0x80,
|
||||
NFIT_NOTIFY_UC_MEMORY_ERROR = 0x81,
|
||||
};
|
||||
|
||||
enum nfit_dimm_notifiers {
|
||||
|
|
@ -154,6 +155,7 @@ struct acpi_nfit_desc {
|
|||
struct list_head idts;
|
||||
struct nvdimm_bus *nvdimm_bus;
|
||||
struct device *dev;
|
||||
u8 ars_start_flags;
|
||||
struct nd_cmd_ars_status *ars_status;
|
||||
size_t ars_status_size;
|
||||
struct work_struct work;
|
||||
|
|
@ -206,7 +208,7 @@ struct nfit_blk {
|
|||
|
||||
extern struct list_head acpi_descs;
|
||||
extern struct mutex acpi_desc_lock;
|
||||
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc);
|
||||
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags);
|
||||
|
||||
#ifdef CONFIG_X86_MCE
|
||||
void nfit_mce_register(void);
|
||||
|
|
|
|||
Loading…
Reference in a new issue