commit 317a992ab9266b86b774b9f6b0f87eb4f59879a1 upstream.
The ars_start_flags property of 'struct acpi_nfit_desc' is no longer used since ARS_REQ_SHORT and ARS_REQ_LONG were added.
Reviewed-by: Toshi Kani toshi.kani@hpe.com Signed-off-by: Dan Williams dan.j.williams@intel.com --- drivers/acpi/nfit/core.c | 10 +++++----- drivers/acpi/nfit/nfit.h | 1 - 2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index f75f8f870ce3..1a48c92eaed5 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2660,11 +2660,11 @@ static int ars_continue(struct acpi_nfit_desc *acpi_desc) struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc; struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
- memset(&ars_start, 0, sizeof(ars_start)); - 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; + ars_start = (struct nd_cmd_ars_start) { + .address = ars_status->restart_address, + .length = ars_status->restart_length, + .type = ars_status->type, + }; rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start, sizeof(ars_start), &cmd_rc); if (rc < 0) diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 33691aecfcee..871fb3de3b30 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -223,7 +223,6 @@ 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; struct nfit_spa *scrub_spa; struct delayed_work dwork;
commit e34b8252a3d2893ca55c82dbfcdaa302fa03d400 upstream.
In preparation for introducing new flags to gate whether ARS results are stale, or poll the completion state, convert the existing flags to an unsigned long with enumerated values. This conversion allows the flags to be atomically updated outside of ->init_mutex.
Reviewed-by: Toshi Kani toshi.kani@hpe.com Signed-off-by: Dan Williams dan.j.williams@intel.com --- drivers/acpi/nfit/core.c | 30 +++++++++++++++++------------- drivers/acpi/nfit/nfit.h | 8 ++++++-- 2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 1a48c92eaed5..64308e669250 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1319,19 +1319,23 @@ static ssize_t scrub_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvdimm_bus_descriptor *nd_desc; + struct acpi_nfit_desc *acpi_desc; ssize_t rc = -ENXIO; + bool busy;
device_lock(dev); nd_desc = dev_get_drvdata(dev); - if (nd_desc) { - struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - - mutex_lock(&acpi_desc->init_mutex); - rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, - acpi_desc->scrub_busy - && !acpi_desc->cancel ? "+\n" : "\n"); - mutex_unlock(&acpi_desc->init_mutex); + if (!nd_desc) { + device_unlock(dev); + return rc; } + acpi_desc = to_acpi_desc(nd_desc); + + mutex_lock(&acpi_desc->init_mutex); + busy = test_bit(ARS_BUSY, &acpi_desc->scrub_flags) + && !test_bit(ARS_CANCEL, &acpi_desc->scrub_flags); + rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n"); + mutex_unlock(&acpi_desc->init_mutex); device_unlock(dev); return rc; } @@ -3081,7 +3085,7 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc,
lockdep_assert_held(&acpi_desc->init_mutex);
- if (acpi_desc->cancel) + if (test_bit(ARS_CANCEL, &acpi_desc->scrub_flags)) return 0;
if (query_rc == -EBUSY) { @@ -3155,7 +3159,7 @@ static void __sched_ars(struct acpi_nfit_desc *acpi_desc, unsigned int tmo) { lockdep_assert_held(&acpi_desc->init_mutex);
- acpi_desc->scrub_busy = 1; + set_bit(ARS_BUSY, &acpi_desc->scrub_flags); /* note this should only be set from within the workqueue */ if (tmo) acpi_desc->scrub_tmo = tmo; @@ -3171,7 +3175,7 @@ static void notify_ars_done(struct acpi_nfit_desc *acpi_desc) { lockdep_assert_held(&acpi_desc->init_mutex);
- acpi_desc->scrub_busy = 0; + clear_bit(ARS_BUSY, &acpi_desc->scrub_flags); acpi_desc->scrub_count++; if (acpi_desc->scrub_count_state) sysfs_notify_dirent(acpi_desc->scrub_count_state); @@ -3460,7 +3464,7 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa;
mutex_lock(&acpi_desc->init_mutex); - if (acpi_desc->cancel) { + if (test_bit(ARS_CANCEL, &acpi_desc->scrub_flags)) { mutex_unlock(&acpi_desc->init_mutex); return 0; } @@ -3539,7 +3543,7 @@ void acpi_nfit_shutdown(void *data) mutex_unlock(&acpi_desc_lock);
mutex_lock(&acpi_desc->init_mutex); - acpi_desc->cancel = 1; + set_bit(ARS_CANCEL, &acpi_desc->scrub_flags); cancel_delayed_work_sync(&acpi_desc->dwork); mutex_unlock(&acpi_desc->init_mutex);
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 871fb3de3b30..897ce10192a0 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -210,6 +210,11 @@ struct nfit_mem { int family; };
+enum scrub_flags { + ARS_BUSY, + ARS_CANCEL, +}; + struct acpi_nfit_desc { struct nvdimm_bus_descriptor nd_desc; struct acpi_table_header acpi_header; @@ -231,8 +236,7 @@ struct acpi_nfit_desc { unsigned int max_ars; unsigned int scrub_count; unsigned int scrub_mode; - unsigned int scrub_busy:1; - unsigned int cancel:1; + unsigned long scrub_flags; unsigned long dimm_cmd_force_en; unsigned long bus_cmd_force_en; unsigned long bus_nfit_cmd_force_en;
commit 5479b2757f26fe9908fc341d105b2097fe820b6f upstream.
The ARS implementation implements exponential back-off on the poll interval to prevent high-frequency access to the DIMM / platform interface. Depending on when the ARS completes the poll interval may exceed the completion event by minutes. Allow root to reset the timeout each time it probes the status. A one-second timeout is still enforced, but root can otherwise can control the poll interval.
Fixes: bc6ba8085842 ("nfit, address-range-scrub: rework and simplify ARS...") Cc: stable@vger.kernel.org Reported-by: Erwin Tsaur erwin.tsaur@oracle.com Reviewed-by: Toshi Kani toshi.kani@hpe.com Signed-off-by: Dan Williams dan.j.williams@intel.com --- drivers/acpi/nfit/core.c | 8 ++++++++ drivers/acpi/nfit/nfit.h | 1 + 2 files changed, 9 insertions(+)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 64308e669250..61d3fd65fbe9 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1335,6 +1335,13 @@ static ssize_t scrub_show(struct device *dev, busy = test_bit(ARS_BUSY, &acpi_desc->scrub_flags) && !test_bit(ARS_CANCEL, &acpi_desc->scrub_flags); rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n"); + /* Allow an admin to poll the busy state at a higher rate */ + if (busy && capable(CAP_SYS_RAWIO) && !test_and_set_bit(ARS_POLL, + &acpi_desc->scrub_flags)) { + acpi_desc->scrub_tmo = 1; + mod_delayed_work(nfit_wq, &acpi_desc->dwork, HZ); + } + mutex_unlock(&acpi_desc->init_mutex); device_unlock(dev); return rc; @@ -3196,6 +3203,7 @@ static void acpi_nfit_scrub(struct work_struct *work) else notify_ars_done(acpi_desc); memset(acpi_desc->ars_status, 0, acpi_desc->max_ars); + clear_bit(ARS_POLL, &acpi_desc->scrub_flags); mutex_unlock(&acpi_desc->init_mutex); }
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 897ce10192a0..d14bad687fb8 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -213,6 +213,7 @@ struct nfit_mem { enum scrub_flags { ARS_BUSY, ARS_CANCEL, + ARS_POLL, };
struct acpi_nfit_desc {
commit 78153dd45e7e0596ba32b15d02bda08e1513111e upstream.
Gate ARS result consumption on whether the OS issued start-ARS since the previous consumption. The BIOS may only clear its result buffers after a successful start-ARS.
Fixes: 0caeef63e6d2 ("libnvdimm: Add a poison list and export badblocks") Cc: stable@vger.kernel.org Reported-by: Krzysztof Rusocki krzysztof.rusocki@intel.com Reported-by: Vishal Verma vishal.l.verma@intel.com Reviewed-by: Toshi Kani toshi.kani@hpe.com Signed-off-by: Dan Williams dan.j.williams@intel.com --- drivers/acpi/nfit/core.c | 17 ++++++++++++++++- drivers/acpi/nfit/nfit.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 61d3fd65fbe9..4be4dc3e8aa6 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2661,7 +2661,10 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc,
if (rc < 0) return rc; - return cmd_rc; + if (cmd_rc < 0) + return cmd_rc; + set_bit(ARS_VALID, &acpi_desc->scrub_flags); + return 0; }
static int ars_continue(struct acpi_nfit_desc *acpi_desc) @@ -2754,6 +2757,17 @@ static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) */ if (ars_status->out_length < 44) return 0; + + /* + * Ignore potentially stale results that are only refreshed + * after a start-ARS event. + */ + if (!test_and_clear_bit(ARS_VALID, &acpi_desc->scrub_flags)) { + dev_dbg(acpi_desc->dev, "skip %d stale records\n", + ars_status->num_records); + return 0; + } + for (i = 0; i < ars_status->num_records; i++) { /* only process full records */ if (ars_status->out_length @@ -3238,6 +3252,7 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) struct nfit_spa *nfit_spa; int rc;
+ set_bit(ARS_VALID, &acpi_desc->scrub_flags); list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { switch (nfit_spa_type(nfit_spa->spa)) { case NFIT_SPA_VOLATILE: diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index d14bad687fb8..0cbe5009eb2c 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -213,6 +213,7 @@ struct nfit_mem { enum scrub_flags { ARS_BUSY, ARS_CANCEL, + ARS_VALID, ARS_POLL, };
On Mon, Apr 22, 2019 at 04:08:10PM -0700, Dan Williams wrote:
commit 317a992ab9266b86b774b9f6b0f87eb4f59879a1 upstream.
The ars_start_flags property of 'struct acpi_nfit_desc' is no longer used since ARS_REQ_SHORT and ARS_REQ_LONG were added.
Reviewed-by: Toshi Kani toshi.kani@hpe.com Signed-off-by: Dan Williams dan.j.williams@intel.com
I've queued this series for both 4.19 and 5.0, thanks!
-- Thanks, Sasha
linux-stable-mirror@lists.linaro.org