Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/acpi/nfit/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 19 kB image not shown  

Quelle  intel.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2018 Intel Corporation. All rights reserved. */
#include <linux/libnvdimm.h>
#include <linux/ndctl.h>
#include <linux/acpi.h>
#include <linux/memregion.h>
#include <asm/smp.h>
#include "intel.h"
#include "nfit.h"

static ssize_t firmware_activate_noidle_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);
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);

 return sprintf(buf, "%s\n", acpi_desc->fwa_noidle ? "Y" : "N");
}

static ssize_t firmware_activate_noidle_store(struct device *dev,
  struct device_attribute *attr, const char *buf, size_t size)
{
 struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 ssize_t rc;
 bool val;

 rc = kstrtobool(buf, &val);
 if (rc)
  return rc;
 if (val != acpi_desc->fwa_noidle)
  acpi_desc->fwa_cap = NVDIMM_FWA_CAP_INVALID;
 acpi_desc->fwa_noidle = val;
 return size;
}
DEVICE_ATTR_RW(firmware_activate_noidle);

bool intel_fwa_supported(struct nvdimm_bus *nvdimm_bus)
{
 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 unsigned long *mask;

 if (!test_bit(NVDIMM_BUS_FAMILY_INTEL, &nd_desc->bus_family_mask))
  return false;

 mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL];
 return *mask == NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK;
}

static unsigned long intel_security_flags(struct nvdimm *nvdimm,
  enum nvdimm_passphrase_type ptype)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 unsigned long security_flags = 0;
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_get_security_state cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_out =
    sizeof(struct nd_intel_get_security_state),
   .nd_fw_size =
    sizeof(struct nd_intel_get_security_state),
  },
 };
 int rc;

 if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
  return 0;

 /*
 * Short circuit the state retrieval while we are doing overwrite.
 * The DSM spec states that the security state is indeterminate
 * until the overwrite DSM completes.
 */

 if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER)
  return BIT(NVDIMM_SECURITY_OVERWRITE);

 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0 || nd_cmd.cmd.status) {
  pr_err("%s: security state retrieval failed (%d:%#x)\n",
    nvdimm_name(nvdimm), rc, nd_cmd.cmd.status);
  return 0;
 }

 /* check and see if security is enabled and locked */
 if (ptype == NVDIMM_MASTER) {
  if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED)
   set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
  else
   set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
  if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT)
   set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
  return security_flags;
 }

 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
  return 0;

 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
  if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
      nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
   set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);

  if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
   set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
  else
   set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
 } else
  set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);

 return security_flags;
}

static int intel_security_freeze(struct nvdimm *nvdimm)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_freeze_lock cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_FREEZE_LOCK,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
  },
 };
 int rc;

 if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask))
  return -ENOTTY;

 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;
 if (nd_cmd.cmd.status)
  return -EIO;
 return 0;
}

static int intel_security_change_key(struct nvdimm *nvdimm,
  const struct nvdimm_key_data *old_data,
  const struct nvdimm_key_data *new_data,
  enum nvdimm_passphrase_type ptype)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 unsigned int cmd = ptype == NVDIMM_MASTER ?
  NVDIMM_INTEL_SET_MASTER_PASSPHRASE :
  NVDIMM_INTEL_SET_PASSPHRASE;
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_set_passphrase cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
   .nd_command = cmd,
  },
 };
 int rc;

 if (!test_bit(cmd, &nfit_mem->dsm_mask))
  return -ENOTTY;

 memcpy(nd_cmd.cmd.old_pass, old_data->data,
   sizeof(nd_cmd.cmd.old_pass));
 memcpy(nd_cmd.cmd.new_pass, new_data->data,
   sizeof(nd_cmd.cmd.new_pass));
 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;

 switch (nd_cmd.cmd.status) {
 case 0:
  return 0;
 case ND_INTEL_STATUS_INVALID_PASS:
  return -EINVAL;
 case ND_INTEL_STATUS_NOT_SUPPORTED:
  return -EOPNOTSUPP;
 case ND_INTEL_STATUS_INVALID_STATE:
 default:
  return -EIO;
 }
}

static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
  const struct nvdimm_key_data *key_data)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_unlock_unit cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
  },
 };
 int rc;

 if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask))
  return -ENOTTY;

 memcpy(nd_cmd.cmd.passphrase, key_data->data,
   sizeof(nd_cmd.cmd.passphrase));
 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;
 switch (nd_cmd.cmd.status) {
 case 0:
  break;
 case ND_INTEL_STATUS_INVALID_PASS:
  return -EINVAL;
 default:
  return -EIO;
 }

 return 0;
}

static int intel_security_disable(struct nvdimm *nvdimm,
  const struct nvdimm_key_data *key_data)
{
 int rc;
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_disable_passphrase cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
  },
 };

 if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask))
  return -ENOTTY;

 memcpy(nd_cmd.cmd.passphrase, key_data->data,
   sizeof(nd_cmd.cmd.passphrase));
 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;

 switch (nd_cmd.cmd.status) {
 case 0:
  break;
 case ND_INTEL_STATUS_INVALID_PASS:
  return -EINVAL;
 case ND_INTEL_STATUS_INVALID_STATE:
 default:
  return -ENXIO;
 }

 return 0;
}

static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
  const struct nvdimm_key_data *key,
  enum nvdimm_passphrase_type ptype)
{
 int rc;
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 unsigned int cmd = ptype == NVDIMM_MASTER ?
  NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE;
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_secure_erase cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
   .nd_command = cmd,
  },
 };

 if (!test_bit(cmd, &nfit_mem->dsm_mask))
  return -ENOTTY;

 memcpy(nd_cmd.cmd.passphrase, key->data,
   sizeof(nd_cmd.cmd.passphrase));
 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;

 switch (nd_cmd.cmd.status) {
 case 0:
  break;
 case ND_INTEL_STATUS_NOT_SUPPORTED:
  return -EOPNOTSUPP;
 case ND_INTEL_STATUS_INVALID_PASS:
  return -EINVAL;
 case ND_INTEL_STATUS_INVALID_STATE:
 default:
  return -ENXIO;
 }

 return 0;
}

static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
{
 int rc;
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_query_overwrite cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_QUERY_OVERWRITE,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
  },
 };

 if (!test_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &nfit_mem->dsm_mask))
  return -ENOTTY;

 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;

 switch (nd_cmd.cmd.status) {
 case 0:
  break;
 case ND_INTEL_STATUS_OQUERY_INPROGRESS:
  return -EBUSY;
 default:
  return -ENXIO;
 }

 return 0;
}

static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
  const struct nvdimm_key_data *nkey)
{
 int rc;
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_overwrite cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_OVERWRITE,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
   .nd_size_out = ND_INTEL_STATUS_SIZE,
   .nd_fw_size = ND_INTEL_STATUS_SIZE,
  },
 };

 if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask))
  return -ENOTTY;

 memcpy(nd_cmd.cmd.passphrase, nkey->data,
   sizeof(nd_cmd.cmd.passphrase));
 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 if (rc < 0)
  return rc;

 switch (nd_cmd.cmd.status) {
 case 0:
  return 0;
 case ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED:
  return -ENOTSUPP;
 case ND_INTEL_STATUS_INVALID_PASS:
  return -EINVAL;
 case ND_INTEL_STATUS_INVALID_STATE:
 default:
  return -ENXIO;
 }
}

static const struct nvdimm_security_ops __intel_security_ops = {
 .get_flags = intel_security_flags,
 .freeze = intel_security_freeze,
 .change_key = intel_security_change_key,
 .disable = intel_security_disable,
#ifdef CONFIG_X86
 .unlock = intel_security_unlock,
 .erase = intel_security_erase,
 .overwrite = intel_security_overwrite,
 .query_overwrite = intel_security_query_overwrite,
#endif
};

const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;

static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc,
  struct nd_intel_bus_fw_activate_businfo *info)
{
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_bus_fw_activate_businfo cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
   .nd_family = NVDIMM_BUS_FAMILY_INTEL,
   .nd_size_out =
    sizeof(struct nd_intel_bus_fw_activate_businfo),
   .nd_fw_size =
    sizeof(struct nd_intel_bus_fw_activate_businfo),
  },
 };
 int rc;

 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd),
   NULL);
 *info = nd_cmd.cmd;
 return rc;
}

/* The fw_ops expect to be called with the nvdimm_bus_lock() held */
static enum nvdimm_fwa_state intel_bus_fwa_state(
  struct nvdimm_bus_descriptor *nd_desc)
{
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 struct nd_intel_bus_fw_activate_businfo info;
 struct device *dev = acpi_desc->dev;
 enum nvdimm_fwa_state state;
 int rc;

 /*
 * It should not be possible for platform firmware to return
 * busy because activate is a synchronous operation. Treat it
 * similar to invalid, i.e. always refresh / poll the status.
 */

 switch (acpi_desc->fwa_state) {
 case NVDIMM_FWA_INVALID:
 case NVDIMM_FWA_BUSY:
  break;
 default:
  /* check if capability needs to be refreshed */
  if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID)
   break;
  return acpi_desc->fwa_state;
 }

 /* Refresh with platform firmware */
 rc = intel_bus_fwa_businfo(nd_desc, &info);
 if (rc)
  return NVDIMM_FWA_INVALID;

 switch (info.state) {
 case ND_INTEL_FWA_IDLE:
  state = NVDIMM_FWA_IDLE;
  break;
 case ND_INTEL_FWA_BUSY:
  state = NVDIMM_FWA_BUSY;
  break;
 case ND_INTEL_FWA_ARMED:
  if (info.activate_tmo > info.max_quiesce_tmo)
   state = NVDIMM_FWA_ARM_OVERFLOW;
  else
   state = NVDIMM_FWA_ARMED;
  break;
 default:
  dev_err_once(dev, "invalid firmware activate state %d\n",
    info.state);
  return NVDIMM_FWA_INVALID;
 }

 /*
 * Capability data is available in the same payload as state. It
 * is expected to be static.
 */

 if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID) {
  if (info.capability & ND_INTEL_BUS_FWA_CAP_FWQUIESCE)
   acpi_desc->fwa_cap = NVDIMM_FWA_CAP_QUIESCE;
  else if (info.capability & ND_INTEL_BUS_FWA_CAP_OSQUIESCE) {
   /*
 * Skip hibernate cycle by default if platform
 * indicates that it does not need devices to be
 * quiesced.
 */

   acpi_desc->fwa_cap = NVDIMM_FWA_CAP_LIVE;
  } else
   acpi_desc->fwa_cap = NVDIMM_FWA_CAP_NONE;
 }

 acpi_desc->fwa_state = state;

 return state;
}

static enum nvdimm_fwa_capability intel_bus_fwa_capability(
  struct nvdimm_bus_descriptor *nd_desc)
{
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);

 if (acpi_desc->fwa_cap > NVDIMM_FWA_CAP_INVALID)
  return acpi_desc->fwa_cap;

 if (intel_bus_fwa_state(nd_desc) > NVDIMM_FWA_INVALID)
  return acpi_desc->fwa_cap;

 return NVDIMM_FWA_CAP_INVALID;
}

static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc)
{
 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_bus_fw_activate cmd;
 ) nd_cmd;
 int rc;

 nd_cmd.pkg = (struct nd_cmd_pkg) {
  .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE,
  .nd_family = NVDIMM_BUS_FAMILY_INTEL,
  .nd_size_in = sizeof(nd_cmd.cmd.iodev_state),
  .nd_size_out =
   sizeof(struct nd_intel_bus_fw_activate),
  .nd_fw_size =
   sizeof(struct nd_intel_bus_fw_activate),
 };
 nd_cmd.cmd = (struct nd_intel_bus_fw_activate) {
  /*
 * Even though activate is run from a suspended context,
 * for safety, still ask platform firmware to force
 * quiesce devices by default. Let a module
 * parameter override that policy.
 */

  .iodev_state = acpi_desc->fwa_noidle
   ? ND_INTEL_BUS_FWA_IODEV_OS_IDLE
   : ND_INTEL_BUS_FWA_IODEV_FORCE_IDLE,
 };
 switch (intel_bus_fwa_state(nd_desc)) {
 case NVDIMM_FWA_ARMED:
 case NVDIMM_FWA_ARM_OVERFLOW:
  break;
 default:
  return -ENXIO;
 }

 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd),
   NULL);

 /*
 * Whether the command succeeded, or failed, the agent checking
 * for the result needs to query the DIMMs individually.
 * Increment the activation count to invalidate all the DIMM
 * states at once (it's otherwise not possible to take
 * acpi_desc->init_mutex in this context)
 */

 acpi_desc->fwa_state = NVDIMM_FWA_INVALID;
 acpi_desc->fwa_count++;

 dev_dbg(acpi_desc->dev, "result: %d\n", rc);

 return rc;
}

static const struct nvdimm_bus_fw_ops __intel_bus_fw_ops = {
 .activate_state = intel_bus_fwa_state,
 .capability = intel_bus_fwa_capability,
 .activate = intel_bus_fwa_activate,
};

const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops;

static int intel_fwa_dimminfo(struct nvdimm *nvdimm,
  struct nd_intel_fw_activate_dimminfo *info)
{
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_fw_activate_dimminfo cmd;
 ) nd_cmd = {
  .pkg = {
   .nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO,
   .nd_family = NVDIMM_FAMILY_INTEL,
   .nd_size_out =
    sizeof(struct nd_intel_fw_activate_dimminfo),
   .nd_fw_size =
    sizeof(struct nd_intel_fw_activate_dimminfo),
  },
 };
 int rc;

 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
 *info = nd_cmd.cmd;
 return rc;
}

static enum nvdimm_fwa_state intel_fwa_state(struct nvdimm *nvdimm)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
 struct nd_intel_fw_activate_dimminfo info;
 int rc;

 /*
 * Similar to the bus state, since activate is synchronous the
 * busy state should resolve within the context of 'activate'.
 */

 switch (nfit_mem->fwa_state) {
 case NVDIMM_FWA_INVALID:
 case NVDIMM_FWA_BUSY:
  break;
 default:
  /* If no activations occurred the old state is still valid */
  if (nfit_mem->fwa_count == acpi_desc->fwa_count)
   return nfit_mem->fwa_state;
 }

 rc = intel_fwa_dimminfo(nvdimm, &info);
 if (rc)
  return NVDIMM_FWA_INVALID;

 switch (info.state) {
 case ND_INTEL_FWA_IDLE:
  nfit_mem->fwa_state = NVDIMM_FWA_IDLE;
  break;
 case ND_INTEL_FWA_BUSY:
  nfit_mem->fwa_state = NVDIMM_FWA_BUSY;
  break;
 case ND_INTEL_FWA_ARMED:
  nfit_mem->fwa_state = NVDIMM_FWA_ARMED;
  break;
 default:
  nfit_mem->fwa_state = NVDIMM_FWA_INVALID;
  break;
 }

 switch (info.result) {
 case ND_INTEL_DIMM_FWA_NONE:
  nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NONE;
  break;
 case ND_INTEL_DIMM_FWA_SUCCESS:
  nfit_mem->fwa_result = NVDIMM_FWA_RESULT_SUCCESS;
  break;
 case ND_INTEL_DIMM_FWA_NOTSTAGED:
  nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NOTSTAGED;
  break;
 case ND_INTEL_DIMM_FWA_NEEDRESET:
  nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NEEDRESET;
  break;
 case ND_INTEL_DIMM_FWA_MEDIAFAILED:
 case ND_INTEL_DIMM_FWA_ABORT:
 case ND_INTEL_DIMM_FWA_NOTSUPP:
 case ND_INTEL_DIMM_FWA_ERROR:
 default:
  nfit_mem->fwa_result = NVDIMM_FWA_RESULT_FAIL;
  break;
 }

 nfit_mem->fwa_count = acpi_desc->fwa_count;

 return nfit_mem->fwa_state;
}

static enum nvdimm_fwa_result intel_fwa_result(struct nvdimm *nvdimm)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;

 if (nfit_mem->fwa_count == acpi_desc->fwa_count
   && nfit_mem->fwa_result > NVDIMM_FWA_RESULT_INVALID)
  return nfit_mem->fwa_result;

 if (intel_fwa_state(nvdimm) > NVDIMM_FWA_INVALID)
  return nfit_mem->fwa_result;

 return NVDIMM_FWA_RESULT_INVALID;
}

static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm)
{
 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
 TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
  struct nd_intel_fw_activate_arm cmd;
 ) nd_cmd;
 int rc;

 nd_cmd.pkg = (struct nd_cmd_pkg) {
  .nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM,
  .nd_family = NVDIMM_FAMILY_INTEL,
  .nd_size_in = sizeof(nd_cmd.cmd.activate_arm),
  .nd_size_out = sizeof(struct nd_intel_fw_activate_arm),
  .nd_fw_size = sizeof(struct nd_intel_fw_activate_arm),
 };
 nd_cmd.cmd = (struct nd_intel_fw_activate_arm) {
  .activate_arm = arm == NVDIMM_FWA_ARM ?
     ND_INTEL_DIMM_FWA_ARM :
     ND_INTEL_DIMM_FWA_DISARM,
 };

 switch (intel_fwa_state(nvdimm)) {
 case NVDIMM_FWA_INVALID:
  return -ENXIO;
 case NVDIMM_FWA_BUSY:
  return -EBUSY;
 case NVDIMM_FWA_IDLE:
  if (arm == NVDIMM_FWA_DISARM)
   return 0;
  break;
 case NVDIMM_FWA_ARMED:
  if (arm == NVDIMM_FWA_ARM)
   return 0;
  break;
 default:
  return -ENXIO;
 }

 /*
 * Invalidate the bus-level state, now that we're committed to
 * changing the 'arm' state.
 */

 acpi_desc->fwa_state = NVDIMM_FWA_INVALID;
 nfit_mem->fwa_state = NVDIMM_FWA_INVALID;

 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);

 dev_dbg(acpi_desc->dev, "%s result: %d\n", arm == NVDIMM_FWA_ARM
   ? "arm" : "disarm", rc);
 return rc;
}

static const struct nvdimm_fw_ops __intel_fw_ops = {
 .activate_state = intel_fwa_state,
 .activate_result = intel_fwa_result,
 .arm = intel_fwa_arm,
};

const struct nvdimm_fw_ops *intel_fw_ops = &__intel_fw_ops;

Messung V0.5
C=95 H=86 G=90

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.