All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: Toshi Kani <toshi.kani@hp.com>
Cc: "linux-nvdimm@lists.01.org" <linux-nvdimm@lists.01.org>,
	linux-acpi@vger.kernel.org,
	"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
	Robert Moore <robert.moore@intel.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [Linux-nvdimm] [PATCH 08/21] nd: ndctl.h, the nd ioctl abi
Date: Tue, 21 Apr 2015 15:05:56 -0700	[thread overview]
Message-ID: <CAPcyv4ifYUQWBxem2w2JXxJ9YHirzuZbmcE8D8=br2sfOk53jw@mail.gmail.com> (raw)
In-Reply-To: <1429651258.17259.60.camel@misato.fc.hp.com>

On Tue, Apr 21, 2015 at 2:20 PM, Toshi Kani <toshi.kani@hp.com> wrote:
> On Fri, 2015-04-17 at 21:35 -0400, Dan Williams wrote:
>> Most configuration of the nd-subsystem is done via nd-sysfs.  However,
>> the NFIT specification defines a small set of messages that can be
>> passed to the subsystem via platform-firmware-defined methods.  The
>> command set (as of the current version of the NFIT-DSM spec) is:
>>
>>     NFIT_CMD_SMART: media health and diagnostics
>>     NFIT_CMD_GET_CONFIG_SIZE: size of the label space
>>     NFIT_CMD_GET_CONFIG_DATA: read label
>>     NFIT_CMD_SET_CONFIG_DATA: write label
>>     NFIT_CMD_VENDOR: vendor-specific command passthrough
>>     NFIT_CMD_ARS_CAP: report address-range-scrubbing capabilities
>>     NFIT_CMD_START_ARS: initiate scrubbing
>>     NFIT_CMD_QUERY_ARS: report on scrubbing state
>>     NFIT_CMD_SMART_THRESHOLD: configure alarm thresholds for smart events
>>
>> Most of the commands target a specific dimm.  However, the
>> address-range-scrubbing commands target the entire NFIT-bus / platform.
>> The 'commands' attribute of an nd-bus, or an nd-dimm enumerate the
>> supported commands for that object.
>>
>> Cc: <linux-acpi@vger.kernel.org>
>> Cc: Robert Moore <robert.moore@intel.com>
>> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Reported-by: Nicholas Moulin <nicholas.w.moulin@linux.intel.com>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> ---
>>  drivers/block/nd/Kconfig      |   11 +
>>  drivers/block/nd/acpi.c       |  333 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/block/nd/bus.c        |  230 ++++++++++++++++++++++++++++
>>  drivers/block/nd/core.c       |   17 ++
>>  drivers/block/nd/dimm_devs.c  |   69 ++++++++
>>  drivers/block/nd/nd-private.h |   11 +
>>  drivers/block/nd/nd.h         |   21 +++
>>  drivers/block/nd/test/nfit.c  |   89 +++++++++++
>>  include/uapi/linux/Kbuild     |    1
>>  include/uapi/linux/ndctl.h    |  178 ++++++++++++++++++++++
>>  10 files changed, 950 insertions(+), 10 deletions(-)
>>  create mode 100644 drivers/block/nd/nd.h
>>  create mode 100644 include/uapi/linux/ndctl.h
>>
>> diff --git a/drivers/block/nd/Kconfig b/drivers/block/nd/Kconfig
>> index 0106b3807202..6c15d10bf4e0 100644
>> --- a/drivers/block/nd/Kconfig
>> +++ b/drivers/block/nd/Kconfig
>> @@ -42,6 +42,17 @@ config NFIT_ACPI
>>         enables the core to craft ACPI._DSM messages for platform/dimm
>>         configuration.
>>
>> +config NFIT_ACPI_DEBUG
>> +     bool "NFIT ACPI: Turn on extra debugging"
>> +     depends on NFIT_ACPI
>> +     depends on DYNAMIC_DEBUG
>> +     default n
>> +     help
>> +       Enabling this option causes the nd_acpi driver to dump the
>> +       input and output buffers of _DSM operations on the ACPI0012
>> +       device, which can be very verbose.  Leave it disabled unless
>> +       you are debugging a hardware / firmware issue.
>> +
>>  config NFIT_TEST
>>       tristate "NFIT TEST: Manufactured NFIT for interface testing"
>>       depends on DMA_CMA
>> diff --git a/drivers/block/nd/acpi.c b/drivers/block/nd/acpi.c
>> index 48db723d7a90..073ff28fdbfe 100644
>> --- a/drivers/block/nd/acpi.c
>> +++ b/drivers/block/nd/acpi.c
>> @@ -13,8 +13,10 @@
>>  #include <linux/list.h>
>>  #include <linux/acpi.h>
>>  #include <linux/mutex.h>
>> +#include <linux/ndctl.h>
>>  #include <linux/module.h>
>>  #include "nfit.h"
>> +#include "nd.h"
>>
>>  enum {
>>       NFIT_ACPI_NOTIFY_TABLE = 0x80,
>> @@ -26,20 +28,330 @@ struct acpi_nfit {
>>       struct nd_bus *nd_bus;
>>  };
>>
>> +static struct acpi_nfit *to_acpi_nfit(struct nfit_bus_descriptor *nfit_desc)
>> +{
>> +     return container_of(nfit_desc, struct acpi_nfit, nfit_desc);
>> +}
>> +
>> +#define NFIT_ACPI_MAX_ELEM 4
>> +struct nfit_cmd_desc {
>> +     int in_num;
>> +     int out_num;
>> +     u32 in_sizes[NFIT_ACPI_MAX_ELEM];
>> +     int out_sizes[NFIT_ACPI_MAX_ELEM];
>> +};
>> +
>> +static const struct nfit_cmd_desc nfit_dimm_descs[] = {
>> +     [NFIT_CMD_IMPLEMENTED] = { },
>> +     [NFIT_CMD_SMART] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 8, },
>> +     },
>> +     [NFIT_CMD_SMART_THRESHOLD] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 8, },
>> +     },
>> +     [NFIT_CMD_DIMM_FLAGS] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 4 },
>> +     },
>> +     [NFIT_CMD_GET_CONFIG_SIZE] = {
>> +             .out_num = 3,
>> +             .out_sizes = { 4, 4, 4, },
>> +     },
>> +     [NFIT_CMD_GET_CONFIG_DATA] = {
>> +             .in_num = 2,
>> +             .in_sizes = { 4, 4, },
>> +             .out_num = 2,
>> +             .out_sizes = { 4, UINT_MAX, },
>> +     },
>> +     [NFIT_CMD_SET_CONFIG_DATA] = {
>> +             .in_num = 3,
>> +             .in_sizes = { 4, 4, UINT_MAX, },
>> +             .out_num = 1,
>> +             .out_sizes = { 4, },
>> +     },
>> +     [NFIT_CMD_VENDOR] = {
>> +             .in_num = 3,
>> +             .in_sizes = { 4, 4, UINT_MAX, },
>> +             .out_num = 3,
>> +             .out_sizes = { 4, 4, UINT_MAX, },
>> +     },
>> +};
>> +
>> +static const struct nfit_cmd_desc nfit_acpi_descs[] = {
>> +     [NFIT_CMD_IMPLEMENTED] = { },
>> +     [NFIT_CMD_ARS_CAP] = {
>> +             .in_num = 2,
>> +             .in_sizes = { 8, 8, },
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 4, },
>> +     },
>> +     [NFIT_CMD_ARS_START] = {
>> +             .in_num = 4,
>> +             .in_sizes = { 8, 8, 2, 6, },
>> +             .out_num = 1,
>> +             .out_sizes = { 4, },
>> +     },
>> +     [NFIT_CMD_ARS_QUERY] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, UINT_MAX, },
>> +     },
>> +};
>> +
>> +static u32 to_cmd_in_size(struct nd_dimm *nd_dimm, int cmd,
>> +             const struct nfit_cmd_desc *desc, int idx, void *buf)
>> +{
>> +     if (idx >= desc->in_num)
>> +             return UINT_MAX;
>> +
>> +     if (desc->in_sizes[idx] < UINT_MAX)
>> +             return desc->in_sizes[idx];
>> +
>> +     if (nd_dimm && cmd == NFIT_CMD_SET_CONFIG_DATA && idx == 2) {
>> +             struct nfit_cmd_set_config_hdr *hdr = buf;
>> +
>> +             return hdr->in_length;
>> +     } else if (nd_dimm && cmd == NFIT_CMD_VENDOR && idx == 2) {
>> +             struct nfit_cmd_vendor_hdr *hdr = buf;
>> +
>> +             return hdr->in_length;
>> +     }
>> +
>> +     return UINT_MAX;
>> +}
>> +
>> +static u32 to_cmd_out_size(struct nd_dimm *nd_dimm, int cmd,
>> +             const struct nfit_cmd_desc *desc, int idx,
>> +             void *buf, u32 out_length, u32 offset)
>> +{
>> +     if (idx >= desc->out_num)
>> +             return UINT_MAX;
>> +
>> +     if (desc->out_sizes[idx] < UINT_MAX)
>> +             return desc->out_sizes[idx];
>> +
>> +     if (offset >= out_length)
>> +             return UINT_MAX;
>> +
>> +     if (nd_dimm && cmd == NFIT_CMD_GET_CONFIG_DATA && idx == 1)
>> +             return out_length - offset;
>> +     else if (nd_dimm && cmd == NFIT_CMD_VENDOR && idx == 2)
>> +             return out_length - offset;
>> +     else if (!nd_dimm && cmd == NFIT_CMD_ARS_QUERY && idx == 1)
>> +             return out_length - offset;
>> +
>> +     return UINT_MAX;
>> +}
>> +
>> +static u8 nd_acpi_uuids[2][16]; /* initialized at nd_acpi_init */
>> +
>> +static u8 *nd_acpi_bus_uuid(void)
>> +{
>> +     return nd_acpi_uuids[0];
>> +}
>> +
>> +static u8 *nd_acpi_dimm_uuid(void)
>> +{
>> +     return nd_acpi_uuids[1];
>> +}
>> +
>>  static int nd_acpi_ctl(struct nfit_bus_descriptor *nfit_desc,
>>               struct nd_dimm *nd_dimm, unsigned int cmd, void *buf,
>>               unsigned int buf_len)
>>  {
>> -     return -ENOTTY;
>> +     struct acpi_nfit *nfit = to_acpi_nfit(nfit_desc);
>> +     union acpi_object in_obj, in_buf, *out_obj;
>> +     const struct nfit_cmd_desc *desc = NULL;
>> +     struct device *dev = &nfit->dev->dev;
>> +     const char *cmd_name, *dimm_name;
>> +     unsigned long dsm_mask;
>> +     acpi_handle handle;
>> +     u32 offset;
>> +     int rc, i;
>> +     u8 *uuid;
>> +
>> +     if (nd_dimm) {
>> +             struct acpi_device *adev = nd_dimm_get_pdata(nd_dimm);
>> +
>> +             if (cmd < ARRAY_SIZE(nfit_dimm_descs))
>> +                     desc = &nfit_dimm_descs[cmd];
>> +             cmd_name = nfit_dimm_cmd_name(cmd);
>> +             dsm_mask = nd_dimm_get_dsm_mask(nd_dimm);
>> +             handle = adev->handle;
>> +             uuid = nd_acpi_dimm_uuid();
>> +             dimm_name = dev_name(&adev->dev);
>> +     } else {
>> +             if (cmd < ARRAY_SIZE(nfit_acpi_descs))
>> +                     desc = &nfit_acpi_descs[cmd];
>> +             cmd_name = nfit_bus_cmd_name(cmd);
>> +             dsm_mask = nfit_desc->dsm_mask;
>> +             handle = nfit->dev->handle;
>> +             uuid = nd_acpi_bus_uuid();
>> +             dimm_name = "bus";
>> +     }
>> +
>> +     if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
>> +             return -ENOTTY;
>> +
>> +     if (!test_bit(cmd, &dsm_mask))
>> +             return -ENOTTY;
>> +
>> +     in_obj.type = ACPI_TYPE_PACKAGE;
>> +     in_obj.package.count = 1;
>> +     in_obj.package.elements = &in_buf;
>> +     in_buf.type = ACPI_TYPE_BUFFER;
>> +     in_buf.buffer.pointer = buf;
>> +     in_buf.buffer.length = 0;
>> +
>> +     /* double check that the nfit_acpi_cmd_descs table is self consistent */
>> +     if (desc->in_num > NFIT_ACPI_MAX_ELEM) {
>> +             WARN_ON_ONCE(1);
>> +             return -ENXIO;
>> +     }
>> +
>> +     for (i = 0; i < desc->in_num; i++) {
>> +             u32 in_size;
>> +
>> +             in_size = to_cmd_in_size(nd_dimm, cmd, desc, i, buf);
>> +             if (in_size == UINT_MAX) {
>> +                     dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     return -ENXIO;
>> +             }
>> +             in_buf.buffer.length += in_size;
>> +             if (in_buf.buffer.length > buf_len) {
>> +                     dev_err(dev, "%s:%s input underrun cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     return -ENXIO;
>> +             }
>> +     }
>> +
>> +     dev_dbg(dev, "%s:%s cmd: %s input length: %d\n", __func__, dimm_name,
>> +                     cmd_name, in_buf.buffer.length);
>> +     if (IS_ENABLED(CONFIG_NFIT_ACPI_DEBUG))
>> +             print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
>> +                             4, in_buf.buffer.pointer, min_t(u32, 128,
>> +                                     in_buf.buffer.length), true);
>> +
>> +     out_obj = acpi_evaluate_dsm(handle, uuid, 1, cmd, &in_obj);
>> +     if (!out_obj) {
>> +             dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
>> +                             cmd_name);
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (out_obj->package.type != ACPI_TYPE_BUFFER) {
>> +             dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
>> +                             __func__, dimm_name, cmd_name, out_obj->type);
>> +             rc = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__, dimm_name,
>> +                     cmd_name, out_obj->buffer.length);
>> +     if (IS_ENABLED(CONFIG_NFIT_ACPI_DEBUG))
>> +             print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
>> +                             4, out_obj->buffer.pointer, min_t(u32, 128,
>> +                                     out_obj->buffer.length), true);
>> +
>> +     for (i = 0, offset = 0; i < desc->out_num; i++) {
>> +             u32 out_size = to_cmd_out_size(nd_dimm, cmd, desc, i, buf,
>> +                             out_obj->buffer.length, offset);
>> +
>> +             if (out_size == UINT_MAX) {
>> +                     dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     break;
>> +             }
>> +
>> +             if (offset + out_size > out_obj->buffer.length) {
>> +                     dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     break;
>> +             }
>> +
>> +             if (in_buf.buffer.length + offset + out_size > buf_len) {
>> +                     dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     rc = -ENXIO;
>> +                     goto out;
>> +             }
>> +             memcpy(buf + in_buf.buffer.length + offset,
>> +                             out_obj->buffer.pointer + offset, out_size);
>> +             offset += out_size;
>> +     }
>> +     if (offset + in_buf.buffer.length < buf_len) {
>> +             if (i >= 1) {
>> +                     /*
>> +                      * status valid, return the number of bytes left
>> +                      * unfilled in the output buffer
>> +                      */
>> +                     rc = buf_len - offset - in_buf.buffer.length;
>> +             } else {
>> +                     dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
>> +                                     __func__, dimm_name, cmd_name, buf_len, offset);
>> +                     rc = -ENXIO;
>> +             }
>> +     } else
>> +             rc = 0;
>> +
>> + out:
>> +     ACPI_FREE(out_obj);
>> +
>> +     return rc;
>> +}
>> +
>> +static int nd_acpi_add_dimm(struct nfit_bus_descriptor *nfit_desc,
>> +             struct nd_dimm *nd_dimm)
>> +{
>> +     struct acpi_nfit *nfit = to_acpi_nfit(nfit_desc);
>> +     u32 nfit_handle = to_nfit_handle(nd_dimm);
>> +     struct device *dev = &nfit->dev->dev;
>> +     struct acpi_device *acpi_dimm;
>> +     unsigned long dsm_mask = 0;
>> +     u8 *uuid = nd_acpi_dimm_uuid();
>> +     unsigned long long sta;
>> +     int i, rc = -ENODEV;
>> +     acpi_status status;
>> +
>> +     acpi_dimm = acpi_find_child_device(nfit->dev, nfit_handle, false);
>> +     if (!acpi_dimm) {
>> +             dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
>> +                             nfit_handle);
>> +             return -ENODEV;
>> +     }
>> +
>> +     status = acpi_evaluate_integer(acpi_dimm->handle, "_STA", NULL, &sta);
>> +     if (status == AE_NOT_FOUND)
>> +             dev_err(dev, "%s missing _STA, disabling...\n",
>> +                             dev_name(&acpi_dimm->dev));
>
> I do not think it is correct to set a DIMM _ADR object disabled when it
> has no _STA.  ACPI 6.0 spec states the followings:
>
>  - Section 6.3.7 _STA, "If a device object describes a device that is
> not on an enumerable bus and the device object does not have an _STA
> object, then OSPM assumes that the device is present, enabled, shown in
> the UI, and functioning."

Ok, I'll take a look.
[..]
> So, in this case, it should set the DIMM object enabled or look up the
> NFIT table to check the presence.

At this point we've already determined that a dimm device is present
because nd_acpi_add_dimm() is called for each dimm found in the NFIT.
Does that count as "enumerable" and require an _STA?

WARNING: multiple messages have this Message-ID (diff)
From: Dan Williams <dan.j.williams@intel.com>
To: Toshi Kani <toshi.kani@hp.com>
Cc: "linux-nvdimm@lists.01.org" <linux-nvdimm@ml01.01.org>,
	linux-acpi@vger.kernel.org,
	"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
	Robert Moore <robert.moore@intel.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [Linux-nvdimm] [PATCH 08/21] nd: ndctl.h, the nd ioctl abi
Date: Tue, 21 Apr 2015 15:05:56 -0700	[thread overview]
Message-ID: <CAPcyv4ifYUQWBxem2w2JXxJ9YHirzuZbmcE8D8=br2sfOk53jw@mail.gmail.com> (raw)
In-Reply-To: <1429651258.17259.60.camel@misato.fc.hp.com>

On Tue, Apr 21, 2015 at 2:20 PM, Toshi Kani <toshi.kani@hp.com> wrote:
> On Fri, 2015-04-17 at 21:35 -0400, Dan Williams wrote:
>> Most configuration of the nd-subsystem is done via nd-sysfs.  However,
>> the NFIT specification defines a small set of messages that can be
>> passed to the subsystem via platform-firmware-defined methods.  The
>> command set (as of the current version of the NFIT-DSM spec) is:
>>
>>     NFIT_CMD_SMART: media health and diagnostics
>>     NFIT_CMD_GET_CONFIG_SIZE: size of the label space
>>     NFIT_CMD_GET_CONFIG_DATA: read label
>>     NFIT_CMD_SET_CONFIG_DATA: write label
>>     NFIT_CMD_VENDOR: vendor-specific command passthrough
>>     NFIT_CMD_ARS_CAP: report address-range-scrubbing capabilities
>>     NFIT_CMD_START_ARS: initiate scrubbing
>>     NFIT_CMD_QUERY_ARS: report on scrubbing state
>>     NFIT_CMD_SMART_THRESHOLD: configure alarm thresholds for smart events
>>
>> Most of the commands target a specific dimm.  However, the
>> address-range-scrubbing commands target the entire NFIT-bus / platform.
>> The 'commands' attribute of an nd-bus, or an nd-dimm enumerate the
>> supported commands for that object.
>>
>> Cc: <linux-acpi@vger.kernel.org>
>> Cc: Robert Moore <robert.moore@intel.com>
>> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Reported-by: Nicholas Moulin <nicholas.w.moulin@linux.intel.com>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> ---
>>  drivers/block/nd/Kconfig      |   11 +
>>  drivers/block/nd/acpi.c       |  333 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/block/nd/bus.c        |  230 ++++++++++++++++++++++++++++
>>  drivers/block/nd/core.c       |   17 ++
>>  drivers/block/nd/dimm_devs.c  |   69 ++++++++
>>  drivers/block/nd/nd-private.h |   11 +
>>  drivers/block/nd/nd.h         |   21 +++
>>  drivers/block/nd/test/nfit.c  |   89 +++++++++++
>>  include/uapi/linux/Kbuild     |    1
>>  include/uapi/linux/ndctl.h    |  178 ++++++++++++++++++++++
>>  10 files changed, 950 insertions(+), 10 deletions(-)
>>  create mode 100644 drivers/block/nd/nd.h
>>  create mode 100644 include/uapi/linux/ndctl.h
>>
>> diff --git a/drivers/block/nd/Kconfig b/drivers/block/nd/Kconfig
>> index 0106b3807202..6c15d10bf4e0 100644
>> --- a/drivers/block/nd/Kconfig
>> +++ b/drivers/block/nd/Kconfig
>> @@ -42,6 +42,17 @@ config NFIT_ACPI
>>         enables the core to craft ACPI._DSM messages for platform/dimm
>>         configuration.
>>
>> +config NFIT_ACPI_DEBUG
>> +     bool "NFIT ACPI: Turn on extra debugging"
>> +     depends on NFIT_ACPI
>> +     depends on DYNAMIC_DEBUG
>> +     default n
>> +     help
>> +       Enabling this option causes the nd_acpi driver to dump the
>> +       input and output buffers of _DSM operations on the ACPI0012
>> +       device, which can be very verbose.  Leave it disabled unless
>> +       you are debugging a hardware / firmware issue.
>> +
>>  config NFIT_TEST
>>       tristate "NFIT TEST: Manufactured NFIT for interface testing"
>>       depends on DMA_CMA
>> diff --git a/drivers/block/nd/acpi.c b/drivers/block/nd/acpi.c
>> index 48db723d7a90..073ff28fdbfe 100644
>> --- a/drivers/block/nd/acpi.c
>> +++ b/drivers/block/nd/acpi.c
>> @@ -13,8 +13,10 @@
>>  #include <linux/list.h>
>>  #include <linux/acpi.h>
>>  #include <linux/mutex.h>
>> +#include <linux/ndctl.h>
>>  #include <linux/module.h>
>>  #include "nfit.h"
>> +#include "nd.h"
>>
>>  enum {
>>       NFIT_ACPI_NOTIFY_TABLE = 0x80,
>> @@ -26,20 +28,330 @@ struct acpi_nfit {
>>       struct nd_bus *nd_bus;
>>  };
>>
>> +static struct acpi_nfit *to_acpi_nfit(struct nfit_bus_descriptor *nfit_desc)
>> +{
>> +     return container_of(nfit_desc, struct acpi_nfit, nfit_desc);
>> +}
>> +
>> +#define NFIT_ACPI_MAX_ELEM 4
>> +struct nfit_cmd_desc {
>> +     int in_num;
>> +     int out_num;
>> +     u32 in_sizes[NFIT_ACPI_MAX_ELEM];
>> +     int out_sizes[NFIT_ACPI_MAX_ELEM];
>> +};
>> +
>> +static const struct nfit_cmd_desc nfit_dimm_descs[] = {
>> +     [NFIT_CMD_IMPLEMENTED] = { },
>> +     [NFIT_CMD_SMART] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 8, },
>> +     },
>> +     [NFIT_CMD_SMART_THRESHOLD] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 8, },
>> +     },
>> +     [NFIT_CMD_DIMM_FLAGS] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 4 },
>> +     },
>> +     [NFIT_CMD_GET_CONFIG_SIZE] = {
>> +             .out_num = 3,
>> +             .out_sizes = { 4, 4, 4, },
>> +     },
>> +     [NFIT_CMD_GET_CONFIG_DATA] = {
>> +             .in_num = 2,
>> +             .in_sizes = { 4, 4, },
>> +             .out_num = 2,
>> +             .out_sizes = { 4, UINT_MAX, },
>> +     },
>> +     [NFIT_CMD_SET_CONFIG_DATA] = {
>> +             .in_num = 3,
>> +             .in_sizes = { 4, 4, UINT_MAX, },
>> +             .out_num = 1,
>> +             .out_sizes = { 4, },
>> +     },
>> +     [NFIT_CMD_VENDOR] = {
>> +             .in_num = 3,
>> +             .in_sizes = { 4, 4, UINT_MAX, },
>> +             .out_num = 3,
>> +             .out_sizes = { 4, 4, UINT_MAX, },
>> +     },
>> +};
>> +
>> +static const struct nfit_cmd_desc nfit_acpi_descs[] = {
>> +     [NFIT_CMD_IMPLEMENTED] = { },
>> +     [NFIT_CMD_ARS_CAP] = {
>> +             .in_num = 2,
>> +             .in_sizes = { 8, 8, },
>> +             .out_num = 2,
>> +             .out_sizes = { 4, 4, },
>> +     },
>> +     [NFIT_CMD_ARS_START] = {
>> +             .in_num = 4,
>> +             .in_sizes = { 8, 8, 2, 6, },
>> +             .out_num = 1,
>> +             .out_sizes = { 4, },
>> +     },
>> +     [NFIT_CMD_ARS_QUERY] = {
>> +             .out_num = 2,
>> +             .out_sizes = { 4, UINT_MAX, },
>> +     },
>> +};
>> +
>> +static u32 to_cmd_in_size(struct nd_dimm *nd_dimm, int cmd,
>> +             const struct nfit_cmd_desc *desc, int idx, void *buf)
>> +{
>> +     if (idx >= desc->in_num)
>> +             return UINT_MAX;
>> +
>> +     if (desc->in_sizes[idx] < UINT_MAX)
>> +             return desc->in_sizes[idx];
>> +
>> +     if (nd_dimm && cmd == NFIT_CMD_SET_CONFIG_DATA && idx == 2) {
>> +             struct nfit_cmd_set_config_hdr *hdr = buf;
>> +
>> +             return hdr->in_length;
>> +     } else if (nd_dimm && cmd == NFIT_CMD_VENDOR && idx == 2) {
>> +             struct nfit_cmd_vendor_hdr *hdr = buf;
>> +
>> +             return hdr->in_length;
>> +     }
>> +
>> +     return UINT_MAX;
>> +}
>> +
>> +static u32 to_cmd_out_size(struct nd_dimm *nd_dimm, int cmd,
>> +             const struct nfit_cmd_desc *desc, int idx,
>> +             void *buf, u32 out_length, u32 offset)
>> +{
>> +     if (idx >= desc->out_num)
>> +             return UINT_MAX;
>> +
>> +     if (desc->out_sizes[idx] < UINT_MAX)
>> +             return desc->out_sizes[idx];
>> +
>> +     if (offset >= out_length)
>> +             return UINT_MAX;
>> +
>> +     if (nd_dimm && cmd == NFIT_CMD_GET_CONFIG_DATA && idx == 1)
>> +             return out_length - offset;
>> +     else if (nd_dimm && cmd == NFIT_CMD_VENDOR && idx == 2)
>> +             return out_length - offset;
>> +     else if (!nd_dimm && cmd == NFIT_CMD_ARS_QUERY && idx == 1)
>> +             return out_length - offset;
>> +
>> +     return UINT_MAX;
>> +}
>> +
>> +static u8 nd_acpi_uuids[2][16]; /* initialized at nd_acpi_init */
>> +
>> +static u8 *nd_acpi_bus_uuid(void)
>> +{
>> +     return nd_acpi_uuids[0];
>> +}
>> +
>> +static u8 *nd_acpi_dimm_uuid(void)
>> +{
>> +     return nd_acpi_uuids[1];
>> +}
>> +
>>  static int nd_acpi_ctl(struct nfit_bus_descriptor *nfit_desc,
>>               struct nd_dimm *nd_dimm, unsigned int cmd, void *buf,
>>               unsigned int buf_len)
>>  {
>> -     return -ENOTTY;
>> +     struct acpi_nfit *nfit = to_acpi_nfit(nfit_desc);
>> +     union acpi_object in_obj, in_buf, *out_obj;
>> +     const struct nfit_cmd_desc *desc = NULL;
>> +     struct device *dev = &nfit->dev->dev;
>> +     const char *cmd_name, *dimm_name;
>> +     unsigned long dsm_mask;
>> +     acpi_handle handle;
>> +     u32 offset;
>> +     int rc, i;
>> +     u8 *uuid;
>> +
>> +     if (nd_dimm) {
>> +             struct acpi_device *adev = nd_dimm_get_pdata(nd_dimm);
>> +
>> +             if (cmd < ARRAY_SIZE(nfit_dimm_descs))
>> +                     desc = &nfit_dimm_descs[cmd];
>> +             cmd_name = nfit_dimm_cmd_name(cmd);
>> +             dsm_mask = nd_dimm_get_dsm_mask(nd_dimm);
>> +             handle = adev->handle;
>> +             uuid = nd_acpi_dimm_uuid();
>> +             dimm_name = dev_name(&adev->dev);
>> +     } else {
>> +             if (cmd < ARRAY_SIZE(nfit_acpi_descs))
>> +                     desc = &nfit_acpi_descs[cmd];
>> +             cmd_name = nfit_bus_cmd_name(cmd);
>> +             dsm_mask = nfit_desc->dsm_mask;
>> +             handle = nfit->dev->handle;
>> +             uuid = nd_acpi_bus_uuid();
>> +             dimm_name = "bus";
>> +     }
>> +
>> +     if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
>> +             return -ENOTTY;
>> +
>> +     if (!test_bit(cmd, &dsm_mask))
>> +             return -ENOTTY;
>> +
>> +     in_obj.type = ACPI_TYPE_PACKAGE;
>> +     in_obj.package.count = 1;
>> +     in_obj.package.elements = &in_buf;
>> +     in_buf.type = ACPI_TYPE_BUFFER;
>> +     in_buf.buffer.pointer = buf;
>> +     in_buf.buffer.length = 0;
>> +
>> +     /* double check that the nfit_acpi_cmd_descs table is self consistent */
>> +     if (desc->in_num > NFIT_ACPI_MAX_ELEM) {
>> +             WARN_ON_ONCE(1);
>> +             return -ENXIO;
>> +     }
>> +
>> +     for (i = 0; i < desc->in_num; i++) {
>> +             u32 in_size;
>> +
>> +             in_size = to_cmd_in_size(nd_dimm, cmd, desc, i, buf);
>> +             if (in_size == UINT_MAX) {
>> +                     dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     return -ENXIO;
>> +             }
>> +             in_buf.buffer.length += in_size;
>> +             if (in_buf.buffer.length > buf_len) {
>> +                     dev_err(dev, "%s:%s input underrun cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     return -ENXIO;
>> +             }
>> +     }
>> +
>> +     dev_dbg(dev, "%s:%s cmd: %s input length: %d\n", __func__, dimm_name,
>> +                     cmd_name, in_buf.buffer.length);
>> +     if (IS_ENABLED(CONFIG_NFIT_ACPI_DEBUG))
>> +             print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
>> +                             4, in_buf.buffer.pointer, min_t(u32, 128,
>> +                                     in_buf.buffer.length), true);
>> +
>> +     out_obj = acpi_evaluate_dsm(handle, uuid, 1, cmd, &in_obj);
>> +     if (!out_obj) {
>> +             dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
>> +                             cmd_name);
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (out_obj->package.type != ACPI_TYPE_BUFFER) {
>> +             dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
>> +                             __func__, dimm_name, cmd_name, out_obj->type);
>> +             rc = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__, dimm_name,
>> +                     cmd_name, out_obj->buffer.length);
>> +     if (IS_ENABLED(CONFIG_NFIT_ACPI_DEBUG))
>> +             print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
>> +                             4, out_obj->buffer.pointer, min_t(u32, 128,
>> +                                     out_obj->buffer.length), true);
>> +
>> +     for (i = 0, offset = 0; i < desc->out_num; i++) {
>> +             u32 out_size = to_cmd_out_size(nd_dimm, cmd, desc, i, buf,
>> +                             out_obj->buffer.length, offset);
>> +
>> +             if (out_size == UINT_MAX) {
>> +                     dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     break;
>> +             }
>> +
>> +             if (offset + out_size > out_obj->buffer.length) {
>> +                     dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     break;
>> +             }
>> +
>> +             if (in_buf.buffer.length + offset + out_size > buf_len) {
>> +                     dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
>> +                                     __func__, dimm_name, cmd_name, i);
>> +                     rc = -ENXIO;
>> +                     goto out;
>> +             }
>> +             memcpy(buf + in_buf.buffer.length + offset,
>> +                             out_obj->buffer.pointer + offset, out_size);
>> +             offset += out_size;
>> +     }
>> +     if (offset + in_buf.buffer.length < buf_len) {
>> +             if (i >= 1) {
>> +                     /*
>> +                      * status valid, return the number of bytes left
>> +                      * unfilled in the output buffer
>> +                      */
>> +                     rc = buf_len - offset - in_buf.buffer.length;
>> +             } else {
>> +                     dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
>> +                                     __func__, dimm_name, cmd_name, buf_len, offset);
>> +                     rc = -ENXIO;
>> +             }
>> +     } else
>> +             rc = 0;
>> +
>> + out:
>> +     ACPI_FREE(out_obj);
>> +
>> +     return rc;
>> +}
>> +
>> +static int nd_acpi_add_dimm(struct nfit_bus_descriptor *nfit_desc,
>> +             struct nd_dimm *nd_dimm)
>> +{
>> +     struct acpi_nfit *nfit = to_acpi_nfit(nfit_desc);
>> +     u32 nfit_handle = to_nfit_handle(nd_dimm);
>> +     struct device *dev = &nfit->dev->dev;
>> +     struct acpi_device *acpi_dimm;
>> +     unsigned long dsm_mask = 0;
>> +     u8 *uuid = nd_acpi_dimm_uuid();
>> +     unsigned long long sta;
>> +     int i, rc = -ENODEV;
>> +     acpi_status status;
>> +
>> +     acpi_dimm = acpi_find_child_device(nfit->dev, nfit_handle, false);
>> +     if (!acpi_dimm) {
>> +             dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
>> +                             nfit_handle);
>> +             return -ENODEV;
>> +     }
>> +
>> +     status = acpi_evaluate_integer(acpi_dimm->handle, "_STA", NULL, &sta);
>> +     if (status == AE_NOT_FOUND)
>> +             dev_err(dev, "%s missing _STA, disabling...\n",
>> +                             dev_name(&acpi_dimm->dev));
>
> I do not think it is correct to set a DIMM _ADR object disabled when it
> has no _STA.  ACPI 6.0 spec states the followings:
>
>  - Section 6.3.7 _STA, "If a device object describes a device that is
> not on an enumerable bus and the device object does not have an _STA
> object, then OSPM assumes that the device is present, enabled, shown in
> the UI, and functioning."

Ok, I'll take a look.
[..]
> So, in this case, it should set the DIMM object enabled or look up the
> NFIT table to check the presence.

At this point we've already determined that a dimm device is present
because nd_acpi_add_dimm() is called for each dimm found in the NFIT.
Does that count as "enumerable" and require an _STA?

  reply	other threads:[~2015-04-21 22:05 UTC|newest]

Thread overview: 160+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-18  1:35 [PATCH 00/21] ND: NFIT-Defined / NVDIMM Subsystem Dan Williams
2015-04-18  1:35 ` Dan Williams
2015-04-18  1:35 ` [PATCH 01/21] e820, efi: add ACPI 6.0 persistent memory types Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-18  4:41   ` Andy Lutomirski
2015-04-18  4:41     ` Andy Lutomirski
2015-04-19  7:46   ` Boaz Harrosh
2015-04-19  7:46     ` Boaz Harrosh
2015-04-20 17:08     ` Dan Williams
2015-04-20 17:08       ` Dan Williams
2015-04-28 12:46   ` [Linux-nvdimm] " Christoph Hellwig
2015-04-28 19:20     ` Dan Williams
2015-04-18  1:35 ` [PATCH 02/21] ND NFIT-Defined/NVIDIMM Subsystem Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-20  7:06   ` Ingo Molnar
2015-04-20  7:06     ` Ingo Molnar
2015-04-20  8:14     ` Dan Williams
2015-04-20  8:14       ` Dan Williams
2015-04-20 12:53       ` Christoph Hellwig
2015-04-20 12:53         ` Christoph Hellwig
2015-04-20 15:57         ` Dan Williams
2015-04-20 15:57           ` Dan Williams
2015-04-21 13:38           ` Dan Williams
2015-04-21 13:38             ` Dan Williams
2015-04-28 12:48   ` [Linux-nvdimm] " Christoph Hellwig
2015-04-18  1:35 ` [PATCH 03/21] nd_acpi: initial core implementation and nfit skeleton Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-18 19:41   ` Paul Bolle
2015-04-18 19:41     ` Paul Bolle
2015-04-19 19:12   ` Rafael J. Wysocki
2015-04-19 19:12     ` Rafael J. Wysocki
2015-04-28 12:53   ` [Linux-nvdimm] " Christoph Hellwig
2015-04-28 19:21     ` Dan Williams
2015-04-18  1:35 ` [PATCH 04/21] nd: create an 'nd_bus' from an 'nfit_desc' Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-21 19:35   ` [Linux-nvdimm] " Toshi Kani
2015-04-21 19:35     ` Toshi Kani
2015-04-21 19:58     ` Dan Williams
2015-04-21 19:58       ` Dan Williams
2015-04-21 19:55       ` Toshi Kani
2015-04-21 19:55         ` Toshi Kani
2015-04-21 20:35         ` Dan Williams
2015-04-21 20:35           ` Dan Williams
2015-04-21 20:32           ` Toshi Kani
2015-04-21 20:32             ` Toshi Kani
2015-04-22 16:39           ` Toshi Kani
2015-04-22 16:39             ` Toshi Kani
2015-04-22 17:03             ` Dan Williams
2015-04-22 17:03               ` Dan Williams
2015-04-22 18:00               ` Linda Knippers
2015-04-22 18:00                 ` Linda Knippers
2015-04-22 18:20                 ` Dan Williams
2015-04-22 18:20                   ` Dan Williams
2015-04-22 18:23                   ` Toshi Kani
2015-04-22 18:23                     ` Toshi Kani
2015-04-22 19:28                     ` Dan Williams
2015-04-22 19:28                       ` Dan Williams
2015-04-22 19:38                       ` Toshi Kani
2015-04-22 19:38                         ` Toshi Kani
2015-04-22 20:00                         ` Dan Williams
2015-04-22 20:00                           ` Dan Williams
2015-04-28 16:47                           ` Toshi Kani
2015-04-28 16:47                             ` Toshi Kani
2015-04-28 17:14                             ` Toshi Kani
2015-04-28 17:14                               ` Toshi Kani
2015-04-18  1:35 ` [PATCH 05/21] nfit-test: manufactured NFITs for interface development Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-24 21:47   ` [Linux-nvdimm] " Linda Knippers
2015-04-24 21:47     ` Linda Knippers
2015-04-24 21:50     ` Dan Williams
2015-04-24 21:50       ` Dan Williams
2015-04-24 21:59       ` Linda Knippers
2015-04-24 21:59         ` Linda Knippers
2015-04-24 23:02         ` Dan Williams
2015-04-24 23:02           ` Dan Williams
2015-04-28 12:54   ` Christoph Hellwig
2015-04-28 19:35     ` Dan Williams
2015-04-18  1:35 ` [PATCH 06/21] nd: ndctl class device, and nd bus attributes Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-18  8:07   ` Greg KH
2015-04-18  8:07     ` Greg KH
2015-04-18 20:08     ` Dan Williams
2015-04-18 20:08       ` Dan Williams
2015-04-18  1:35 ` [PATCH 07/21] nd: dimm devices (nfit "memory-devices") Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-18  8:06   ` Greg KH
2015-04-18  8:06     ` Greg KH
2015-04-18 20:12     ` Dan Williams
2015-04-18 20:12       ` Dan Williams
2015-04-18  1:35 ` [PATCH 08/21] nd: ndctl.h, the nd ioctl abi Dan Williams
2015-04-18  1:35   ` Dan Williams
2015-04-21 21:20   ` [Linux-nvdimm] " Toshi Kani
2015-04-21 21:20     ` Toshi Kani
2015-04-21 22:05     ` Dan Williams [this message]
2015-04-21 22:05       ` Dan Williams
2015-04-21 22:16       ` Toshi Kani
2015-04-21 22:16         ` Toshi Kani
2015-04-24 15:56   ` Toshi Kani
2015-04-24 15:56     ` Toshi Kani
2015-04-24 16:09     ` Toshi Kani
2015-04-24 16:09       ` Toshi Kani
2015-04-24 16:31       ` Dan Williams
2015-04-24 16:31         ` Dan Williams
2015-04-24 16:25     ` Dan Williams
2015-04-24 16:25       ` Dan Williams
2015-04-24 17:18       ` Toshi Kani
2015-04-24 17:18         ` Toshi Kani
2015-04-24 17:45         ` Dan Williams
2015-04-24 17:45           ` Dan Williams
2015-04-25  0:35           ` Toshi Kani
2015-04-25  0:35             ` Toshi Kani
2015-04-18  1:36 ` [PATCH 09/21] nd_dimm: dimm driver and base nd-bus device-driver infrastructure Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 10/21] nd: regions (block-data-window, persistent memory, volatile memory) Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 11/21] nd_region: support for legacy nvdimms Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 12/21] nd_pmem: add NFIT support to the pmem driver Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  6:38   ` Christoph Hellwig
2015-04-18  6:38     ` Christoph Hellwig
2015-04-18 19:37     ` Dan Williams
2015-04-18 19:37       ` Dan Williams
2015-04-28 12:56       ` [Linux-nvdimm] " Christoph Hellwig
2015-04-28 19:37         ` Dan Williams
2015-04-18  1:36 ` [PATCH 13/21] nd: add interleave-set state-tracking infrastructure Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 14/21] nd: namespace indices: read and validate Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 15/21] nd: pmem label sets and namespace instantiation Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 16/21] nd: blk labels " Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 17/21] nd: write pmem label set Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 18/21] nd: write blk " Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-18  1:36 ` [PATCH 19/21] nd: infrastructure for btt devices Dan Williams
2015-04-18  1:36   ` Dan Williams
2015-04-22 19:12   ` [Linux-nvdimm] " Elliott, Robert (Server Storage)
2015-04-22 19:12     ` Elliott, Robert (Server Storage)
2015-04-22 19:39     ` Dan Williams
2015-04-22 19:39       ` Dan Williams
2015-04-28 13:01   ` Christoph Hellwig
2015-04-28 15:42     ` Matthew Wilcox
2015-04-18  1:37 ` [PATCH 20/21] nd_btt: atomic sector updates Dan Williams
2015-04-18  1:37   ` Dan Williams
2015-04-18  1:37 ` [PATCH 21/21] nd_blk: nfit blk driver Dan Williams
2015-04-18  1:37   ` Dan Williams
2015-04-18 19:29 ` [PATCH 00/21] ND: NFIT-Defined / NVDIMM Subsystem Dan Williams
2015-04-18 19:29   ` Dan Williams
2015-04-22 19:06 ` [Linux-nvdimm] " Elliott, Robert (Server Storage)
2015-04-22 19:06   ` Elliott, Robert (Server Storage)
2015-04-22 19:06   ` Elliott, Robert (Server Storage)
2015-04-22 19:39   ` Dan Williams
2015-04-22 19:39     ` Dan Williams
2015-04-22 19:39     ` Dan Williams
2015-04-23  5:43   ` Ingo Molnar
2015-04-23  5:43     ` Ingo Molnar
2015-04-23  5:43     ` Ingo Molnar

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='CAPcyv4ifYUQWBxem2w2JXxJ9YHirzuZbmcE8D8=br2sfOk53jw@mail.gmail.com' \
    --to=dan.j.williams@intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nvdimm@lists.01.org \
    --cc=rafael.j.wysocki@intel.com \
    --cc=robert.moore@intel.com \
    --cc=toshi.kani@hp.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.