From: Dave Jiang <dave.jiang@intel.com>
To: Dan Williams <dan.j.williams@intel.com>, linux-nvdimm@lists.01.org
Cc: linux-acpi@vger.kernel.org
Subject: Re: [PATCH 5/6] nfit, address-range-scrub: rework and simplify ARS state machine
Date: Tue, 3 Apr 2018 08:29:54 -0700 [thread overview]
Message-ID: <f4c0ca57-3c4a-9805-a66a-6a61aec2b108@intel.com> (raw)
In-Reply-To: <152273078779.38372.13062348829183334140.stgit@dwillia2-desk3.amr.corp.intel.com>
On 4/2/2018 9:46 PM, Dan Williams wrote:
> ARS is an operation that can take 10s to 100s of seconds to find media
> errors that should rarely be present. If the platform crashes due to
> media errors in persistent memory, the expectation is that the BIOS will
> report those known errors in a 'short' ARS request.
>
> A 'short' ARS request asks platform firmware to return an ARS payload
> with all known errors, but without issuing a 'long' scrub. At driver
> init a short request is issued to all PMEM ranges before registering
> regions. Then, in the background, a long ARS is scheduled for each
> region.
>
> The ARS implementation is simplified to centralize ARS completion work
> in the ars_complete() helper called from ars_status_process_records().
> The timeout is removed since there is no facility to cancel ARS, and
> system init is never blocked waiting for a 'long' ARS. The ars_state
> flags are used to coordinate ARS requests from driver init, ARS requests
> from userspace, and ARS requests in response to media error
> notifications.
>
> Given that there is no notification of ARS completion the implementation
> still needs to poll, but now it backs off exponentially to a maximum
> poll period of 30 minutes.
>
> Suggested-by: Toshi Kani <toshi.kani@hpe.com>
> Co-developed-by: Dave Jiang <dave.jiang@intel.com>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
> drivers/acpi/nfit/core.c | 415 +++++++++++++++++++---------------------------
> drivers/acpi/nfit/nfit.h | 4
> 2 files changed, 174 insertions(+), 245 deletions(-)
>
> diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
> index 9ba60f58d929..29a033f3455d 100644
> --- a/drivers/acpi/nfit/core.c
> +++ b/drivers/acpi/nfit/core.c
> @@ -35,16 +35,6 @@ static bool force_enable_dimms;
> module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
> MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
>
> -static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
> -module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
> -MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
> -
> -/* after three payloads of overflow, it's dead jim */
> -static unsigned int scrub_overflow_abort = 3;
> -module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
> -MODULE_PARM_DESC(scrub_overflow_abort,
> - "Number of times we overflow ARS results before abort");
> -
> static bool disable_vendor_specific;
> module_param(disable_vendor_specific, bool, S_IRUGO);
> MODULE_PARM_DESC(disable_vendor_specific,
> @@ -1251,7 +1241,7 @@ static ssize_t scrub_show(struct device *dev,
>
> mutex_lock(&acpi_desc->init_mutex);
> rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
> - work_busy(&acpi_desc->work)
> + work_busy(&acpi_desc->dwork.work)
> && !acpi_desc->cancel ? "+\n" : "\n");
> mutex_unlock(&acpi_desc->init_mutex);
> }
> @@ -2452,7 +2442,8 @@ 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 (test_bit(ARS_SHORT, &nfit_spa->ars_state))
> + ars_start.flags = ND_ARS_RETURN_PREV_DATA;
> if (nfit_spa_type(spa) == NFIT_SPA_PM)
> ars_start.type = ND_ARS_PERSISTENT;
> else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
> @@ -2500,9 +2491,56 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
> return cmd_rc;
> }
>
> +static void ars_complete(struct acpi_nfit_desc *acpi_desc,
> + struct nfit_spa *nfit_spa)
> +{
> + struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
> + struct acpi_nfit_system_address *spa = nfit_spa->spa;
> + struct nd_region *nd_region = nfit_spa->nd_region;
> + struct device *dev;
> +
> + if ((ars_status->address >= spa->address && ars_status->address
> + < spa->address + spa->length)
> + || (ars_status->address < spa->address)) {
> + /*
> + * Assume that if a scrub starts at an offset from the
> + * start of nfit_spa that we are in the continuation
> + * case.
> + *
> + * Otherwise, if the scrub covers the spa range, mark
> + * any pending request complete.
> + */
> + if (ars_status->address + ars_status->length
> + >= spa->address + spa->length)
> + /* complete */;
> + else
> + return;
> + } else
> + return;
> +
> + if (test_bit(ARS_DONE, &nfit_spa->ars_state))
> + return;
> +
> + if (!test_and_clear_bit(ARS_REQ, &nfit_spa->ars_state))
> + return;
> +
> + if (nd_region) {
> + dev = nd_region_dev(nd_region);
> + nvdimm_region_notify(nd_region, NVDIMM_REVALIDATE_POISON);
> + } else
> + dev = acpi_desc->dev;
> +
> + dev_dbg(dev, "ARS: range %d %s complete\n", spa->range_index,
> + test_bit(ARS_SHORT, &nfit_spa->ars_state)
> + ? "short" : "long");
> + clear_bit(ARS_SHORT, &nfit_spa->ars_state);
> + set_bit(ARS_DONE, &nfit_spa->ars_state);
> +}
> +
> static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
> - struct nd_cmd_ars_status *ars_status)
> + struct nfit_spa *nfit_spa)
> {
> + struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
> struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
> int rc;
> u32 i;
> @@ -2513,6 +2551,9 @@ static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
> */
> if (ars_status->out_length < 44)
> return 0;
> +
> + ars_complete(acpi_desc, nfit_spa);
> +
> for (i = 0; i < ars_status->num_records; i++) {
> /* only process full records */
> if (ars_status->out_length
> @@ -2792,229 +2833,117 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
> if (rc < 0 && rc != -ENOSPC)
> return rc;
>
> - if (ars_status_process_records(acpi_desc, acpi_desc->ars_status))
> + if (ars_status_process_records(acpi_desc, nfit_spa))
> return -ENOMEM;
>
> return 0;
> }
>
> -static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
> - struct nfit_spa *nfit_spa)
> +static int init_ars(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa,
> + int query_rc)
> {
> - struct acpi_nfit_system_address *spa = nfit_spa->spa;
> - unsigned int overflow_retry = scrub_overflow_abort;
> - u64 init_ars_start = 0, init_ars_len = 0;
> - struct device *dev = acpi_desc->dev;
> - unsigned int tmo = scrub_timeout;
> int rc;
>
> - if (!test_bit(ARS_REQ, &nfit_spa->ars_state) || !nfit_spa->nd_region)
> - return;
> + switch (query_rc) {
> + case 0:
> + /* ARS is idle, lets look for critical known errors... */
> + break;
> + case -EBUSY:
> + /*
> + * ARS is already running, some agent thought it was ok
> + * to busy ARS before handing off to the nfit driver.
> + */
> + clear_bit(ARS_SHORT, &nfit_spa->ars_state);
> + rc = query_rc;
> + goto out;
> + case -ENOSPC:
> + /* ARS continuation needed... */
> + clear_bit(ARS_SHORT, &nfit_spa->ars_state);
> + rc = query_rc;
> + goto out;
> + default:
> + rc = query_rc;
> + goto out;
> + }
>
> + WARN_ON_ONCE(!test_bit(ARS_SHORT, &nfit_spa->ars_state));
> rc = ars_start(acpi_desc, nfit_spa);
> - /*
> - * If we timed out the initial scan we'll still be busy here,
> - * and will wait another timeout before giving up permanently.
> - */
> - if (rc < 0 && rc != -EBUSY)
> - return;
> -
> - do {
> - u64 ars_start, ars_len;
> -
> - if (acpi_desc->cancel)
> - break;
> + if (rc == 0)
> rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
> - if (rc == -ENOTTY)
> - break;
> - if (rc == -EBUSY && !tmo) {
> - dev_warn(dev, "range %d ars timeout, aborting\n",
> - spa->range_index);
> - break;
> - }
> -
> - if (rc == -EBUSY) {
> - /*
> - * Note, entries may be appended to the list
> - * while the lock is dropped, but the workqueue
> - * being active prevents entries being deleted /
> - * freed.
> - */
> - mutex_unlock(&acpi_desc->init_mutex);
> - ssleep(1);
> - tmo--;
> - mutex_lock(&acpi_desc->init_mutex);
> - continue;
> - }
> -
> - /* we got some results, but there are more pending... */
> - if (rc == -ENOSPC && overflow_retry--) {
> - if (!init_ars_len) {
> - init_ars_len = acpi_desc->ars_status->length;
> - init_ars_start = acpi_desc->ars_status->address;
> - }
> - rc = ars_continue(acpi_desc);
> - }
> -
> - if (rc < 0) {
> - dev_warn(dev, "range %d ars continuation failed\n",
> - spa->range_index);
> - break;
> - }
> -
> - if (init_ars_len) {
> - ars_start = init_ars_start;
> - ars_len = init_ars_len;
> - } else {
> - ars_start = acpi_desc->ars_status->address;
> - ars_len = acpi_desc->ars_status->length;
> - }
> - dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
> - spa->range_index, ars_start, ars_len);
> - /* notify the region about new poison entries */
> - nvdimm_region_notify(nfit_spa->nd_region,
> - NVDIMM_REVALIDATE_POISON);
> - break;
> - } while (1);
> +out:
> + if (acpi_nfit_register_region(acpi_desc, nfit_spa))
> + set_bit(ARS_FAILED, &nfit_spa->ars_state);
> + return rc;
> }
>
> static void acpi_nfit_scrub(struct work_struct *work)
> {
> - struct device *dev;
> - u64 init_scrub_length = 0;
> struct nfit_spa *nfit_spa;
> - u64 init_scrub_address = 0;
> - bool init_ars_done = false;
> struct acpi_nfit_desc *acpi_desc;
> - unsigned int tmo = scrub_timeout;
> - unsigned int overflow_retry = scrub_overflow_abort;
>
> - acpi_desc = container_of(work, typeof(*acpi_desc), work);
> - dev = acpi_desc->dev;
> -
> - /*
> - * We scrub in 2 phases. The first phase waits for any platform
> - * firmware initiated scrubs to complete and then we go search for the
> - * affected spa regions to mark them scanned. In the second phase we
> - * initiate a directed scrub for every range that was not scrubbed in
> - * phase 1. If we're called for a 'rescan', we harmlessly pass through
> - * the first phase, but really only care about running phase 2, where
> - * regions can be notified of new poison.
> - */
> -
> - /* process platform firmware initiated scrubs */
> - retry:
> + acpi_desc = container_of(work, typeof(*acpi_desc), dwork.work);
> mutex_lock(&acpi_desc->init_mutex);
> list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
> - struct nd_cmd_ars_status *ars_status;
> - struct acpi_nfit_system_address *spa;
> - u64 ars_start, ars_len;
> - int rc;
> + struct acpi_nfit_system_address *spa = nfit_spa->spa;
> + int rc, ridx = spa->range_index;
> + int type = nfit_spa_type(spa);
> + struct device *dev;
>
> if (acpi_desc->cancel)
> - break;
> -
> - if (nfit_spa->nd_region)
> + goto out;
> + if (type != NFIT_SPA_PM && type != NFIT_SPA_VOLATILE)
> continue;
> -
> - if (init_ars_done) {
> - /*
> - * No need to re-query, we're now just
> - * reconciling all the ranges covered by the
> - * initial scrub
> - */
> - rc = 0;
> - } else
> - rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
> -
> - if (rc == -ENOTTY) {
> - /* no ars capability, just register spa and move on */
> - acpi_nfit_register_region(acpi_desc, nfit_spa);
> + if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
> continue;
> - }
> -
> - if (rc == -EBUSY && !tmo) {
> - /* fallthrough to directed scrub in phase 2 */
> - dev_warn(dev, "timeout awaiting ars results, continuing...\n");
> - break;
> - } else if (rc == -EBUSY) {
> - mutex_unlock(&acpi_desc->init_mutex);
> - ssleep(1);
> - tmo--;
> - goto retry;
> - }
>
> - /* we got some results, but there are more pending... */
> - if (rc == -ENOSPC && overflow_retry--) {
> - ars_status = acpi_desc->ars_status;
> - /*
> - * Record the original scrub range, so that we
> - * can recall all the ranges impacted by the
> - * initial scrub.
> - */
> - if (!init_scrub_length) {
> - init_scrub_length = ars_status->length;
> - init_scrub_address = ars_status->address;
> + rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
> + if (!nfit_spa->nd_region)
> + rc = init_ars(acpi_desc, nfit_spa, rc);
> +
> + dev = nd_region_dev(nfit_spa->nd_region);
> + if (!dev)
> + dev = acpi_desc->dev;
> +
> + switch (rc) {
> + case -EBUSY:
> +busy:
> + dev_dbg(dev, "ARS: range %d ARS busy\n", ridx);
> + queue_delayed_work(nfit_wq, &acpi_desc->dwork,
> + acpi_desc->scrub_tmo * HZ);
> + acpi_desc->scrub_tmo = min(30U * 60U,
> + acpi_desc->scrub_tmo * 2);
> + goto out;
> + case 0:
> + if (test_bit(ARS_REQ, &nfit_spa->ars_state)) {
> + acpi_desc->scrub_tmo = 1;
> + rc = ars_start(acpi_desc, nfit_spa);
> + clear_bit(ARS_DONE, &nfit_spa->ars_state);
> + dev_dbg(dev, "ARS: range %d ARS start (%d)\n",
> + spa->range_index, rc);
> + if (rc == 0 || rc == -EBUSY)
> + goto busy;
> + goto fail;
> }
> + break;
> + case -ENOSPC:
> + acpi_desc->scrub_tmo = 1;
> rc = ars_continue(acpi_desc);
> - if (rc == 0) {
> - mutex_unlock(&acpi_desc->init_mutex);
> - goto retry;
> - }
> - }
> -
> - if (rc < 0) {
> - /*
> - * Initial scrub failed, we'll give it one more
> - * try below...
> - */
> + clear_bit(ARS_DONE, &nfit_spa->ars_state);
> + if (rc == -EBUSY || rc == 0)
> + goto busy;
> + /* fall through */
> + default:
> +fail:
> + dev_dbg(dev, "ARS: range %d failed (%d)\n", ridx, rc);
> + set_bit(ARS_FAILED, &nfit_spa->ars_state);
> break;
> }
> -
> - /* We got some final results, record completed ranges */
> - ars_status = acpi_desc->ars_status;
> - if (init_scrub_length) {
> - ars_start = init_scrub_address;
> - ars_len = ars_start + init_scrub_length;
> - } else {
> - ars_start = ars_status->address;
> - ars_len = ars_status->length;
> - }
> - spa = nfit_spa->spa;
> -
> - if (!init_ars_done) {
> - init_ars_done = true;
> - dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
> - ars_start, ars_len);
> - }
> - if (ars_start <= spa->address && ars_start + ars_len
> - >= spa->address + spa->length)
> - acpi_nfit_register_region(acpi_desc, nfit_spa);
> }
>
> - /*
> - * For all the ranges not covered by an initial scrub we still
> - * want to see if there are errors, but it's ok to discover them
> - * asynchronously.
> - */
> - list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
> - /*
> - * Flag all the ranges that still need scrubbing, but
> - * register them now to make data available.
> - */
> - if (!nfit_spa->nd_region) {
> - set_bit(ARS_REQ, &nfit_spa->ars_state);
> - acpi_nfit_register_region(acpi_desc, nfit_spa);
> - }
> - }
> - acpi_desc->init_complete = 1;
> -
> - 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);
> +out:
> mutex_unlock(&acpi_desc->init_mutex);
> }
>
> @@ -3026,8 +2955,11 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
> int rc, type = nfit_spa_type(nfit_spa->spa);
>
> /* PMEM and VMEM will be registered by the ARS workqueue */
> - if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE)
> + if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE) {
> + set_bit(ARS_REQ, &nfit_spa->ars_state);
> + set_bit(ARS_SHORT, &nfit_spa->ars_state);
> continue;
> + }
> /* BLK apertures belong to BLK region registration below */
> if (type == NFIT_SPA_BDW)
> continue;
> @@ -3037,9 +2969,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);
> + queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
> return 0;
> }
>
> @@ -3174,49 +3104,34 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz)
> }
> EXPORT_SYMBOL_GPL(acpi_nfit_init);
>
> -struct acpi_nfit_flush_work {
> - struct work_struct work;
> - struct completion cmp;
> -};
> -
> static void flush_probe(struct work_struct *work)
> {
> - struct acpi_nfit_flush_work *flush;
> -
> - flush = container_of(work, typeof(*flush), work);
> - complete(&flush->cmp);
> }
>
> static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
> {
> struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
> struct device *dev = acpi_desc->dev;
> - struct acpi_nfit_flush_work flush;
> - int rc;
> + struct work_struct flush;
> +
>
> - /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
> + /* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
> device_lock(dev);
> device_unlock(dev);
>
> - /* bounce the init_mutex to make init_complete valid */
> + /* Bounce the init_mutex to ensure initial scrub work is queued */
> mutex_lock(&acpi_desc->init_mutex);
> - if (acpi_desc->cancel || acpi_desc->init_complete) {
> - mutex_unlock(&acpi_desc->init_mutex);
> - return 0;
> - }
> + mutex_unlock(&acpi_desc->init_mutex);
>
> /*
> - * Scrub work could take 10s of seconds, userspace may give up so we
> - * need to be interruptible while waiting.
> + * Queue one work in the stream and flush to ensure initial
> + * registration work is complete.
> */
> - INIT_WORK_ONSTACK(&flush.work, flush_probe);
> - init_completion(&flush.cmp);
> - queue_work(nfit_wq, &flush.work);
> - mutex_unlock(&acpi_desc->init_mutex);
> + INIT_WORK_ONSTACK(&flush, flush_probe);
> + queue_work(nfit_wq, &flush);
> + flush_work(&flush);
>
> - rc = wait_for_completion_interruptible(&flush.cmp);
> - cancel_work_sync(&flush.work);
> - return rc;
> + return 0;
> }
>
> static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
> @@ -3235,7 +3150,7 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
> * just needs guarantees that any ars it initiates are not
> * interrupted by any intervening start reqeusts from userspace.
> */
> - if (work_busy(&acpi_desc->work))
> + if (work_busy(&acpi_desc->dwork.work))
> return -EBUSY;
>
> return 0;
> @@ -3244,11 +3159,9 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
> int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags)
> {
> struct device *dev = acpi_desc->dev;
> + int scheduled = 0, busy = 0;
> struct nfit_spa *nfit_spa;
>
> - if (work_busy(&acpi_desc->work))
> - return -EBUSY;
> -
> mutex_lock(&acpi_desc->init_mutex);
> if (acpi_desc->cancel) {
> mutex_unlock(&acpi_desc->init_mutex);
> @@ -3258,17 +3171,31 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags)
> list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
> struct acpi_nfit_system_address *spa = nfit_spa->spa;
>
> - if (nfit_spa_type(spa) != NFIT_SPA_PM)
> + if (nfit_spa_type(spa) == NFIT_SPA_DCR)
> continue;
>
> - set_bit(ARS_REQ, &nfit_spa->ars_state);
> + if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
> + continue;
> +
> + if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state))
> + busy++;
> + else {
> + if (flags == ND_ARS_RETURN_PREV_DATA)
if (flags & ND_ARS_RETURN_PREV_DATA)?
I think the spec allows other bits set in the flag byte.
> + set_bit(ARS_SHORT, &nfit_spa->ars_state);
> + scheduled++;
> + }
> + }
> + if (scheduled) {
> + queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
> + dev_dbg(dev, "ars_scan triggered\n");
> }
> - acpi_desc->ars_start_flags = flags;
> - queue_work(nfit_wq, &acpi_desc->work);
> - dev_dbg(dev, "ars_scan triggered\n");
> mutex_unlock(&acpi_desc->init_mutex);
>
> - return 0;
> + if (scheduled)
> + return 0;
> + if (busy)
> + return -EBUSY;
> + return -ENOTTY;
> }
>
> void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
> @@ -3295,7 +3222,8 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
> INIT_LIST_HEAD(&acpi_desc->dimms);
> INIT_LIST_HEAD(&acpi_desc->list);
> mutex_init(&acpi_desc->init_mutex);
> - INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
> + acpi_desc->scrub_tmo = 1;
> + INIT_DELAYED_WORK(&acpi_desc->dwork, acpi_nfit_scrub);
> }
> EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
>
> @@ -3319,6 +3247,7 @@ void acpi_nfit_shutdown(void *data)
>
> mutex_lock(&acpi_desc->init_mutex);
> acpi_desc->cancel = 1;
> + 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 efb6c6bcde42..7b2e074ac39a 100644
> --- a/drivers/acpi/nfit/nfit.h
> +++ b/drivers/acpi/nfit/nfit.h
> @@ -198,17 +198,17 @@ struct acpi_nfit_desc {
> u8 ars_start_flags;
> struct nd_cmd_ars_status *ars_status;
> size_t ars_status_size;
> - struct work_struct work;
> + struct delayed_work dwork;
> struct list_head list;
> struct kernfs_node *scrub_count_state;
> unsigned int scrub_count;
> unsigned int scrub_mode;
> unsigned int cancel:1;
> - unsigned int init_complete:1;
> unsigned long dimm_cmd_force_en;
> unsigned long bus_cmd_force_en;
> unsigned long bus_nfit_cmd_force_en;
> unsigned int platform_cap;
> + unsigned int scrub_tmo;
> int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
> void *iobuf, u64 len, int rw);
> };
>
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
next prev parent reply other threads:[~2018-04-03 15:29 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-03 4:46 [PATCH 0/6] nfit, address-range-scrub: rework and fixes Dan Williams
2018-04-03 4:46 ` [PATCH 1/6] nfit: fix region registration vs block-data-window ranges Dan Williams
2018-04-03 15:30 ` Dave Jiang
[not found] ` <152273076649.38372.8379231668189794225.stgit-p8uTFz9XbKj2zm6wflaqv1nYeNYlB/vhral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-04-06 20:05 ` Sasha Levin
2018-04-03 4:46 ` [PATCH 2/6] nfit, address-range-scrub: fix scrub in-progress reporting Dan Williams
2018-04-03 15:31 ` Dave Jiang
[not found] ` <152273077198.38372.11857145045474104173.stgit-p8uTFz9XbKj2zm6wflaqv1nYeNYlB/vhral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-04-06 20:05 ` Sasha Levin
2018-04-03 4:46 ` [PATCH 3/6] libnvdimm: add an api to cast a 'struct nd_region' to its 'struct device' Dan Williams
2018-04-03 15:31 ` Dave Jiang
2018-04-03 4:46 ` [PATCH 4/6] nfit, address-range-scrub: introduce nfit_spa->ars_state Dan Williams
2018-04-03 15:31 ` Dave Jiang
2018-04-03 4:46 ` [PATCH 5/6] nfit, address-range-scrub: rework and simplify ARS state machine Dan Williams
2018-04-03 15:29 ` Dave Jiang [this message]
2018-04-03 15:33 ` Dan Williams
2018-04-04 16:26 ` Kani, Toshi
2018-04-04 17:08 ` Dan Williams
2018-04-03 4:46 ` [PATCH 6/6] nfit, address-range-scrub: add module option to skip initial ars Dan Williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f4c0ca57-3c4a-9805-a66a-6a61aec2b108@intel.com \
--to=dave.jiang@intel.com \
--cc=dan.j.williams@intel.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-nvdimm@lists.01.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).