Commit af0870c4 authored by Vaibhav Jain's avatar Vaibhav Jain Committed by Michael Ellerman
Browse files

powerpc/papr_scm: Add support for fetching nvdimm 'fuel-gauge' metric



We add support for reporting 'fuel-gauge' NVDIMM metric via
PAPR_PDSM_HEALTH pdsm payload. 'fuel-gauge' metric indicates the usage
life remaining of a papr-scm compatible NVDIMM. PHYP exposes this
metric via the H_SCM_PERFORMANCE_STATS.

The metric value is returned from the pdsm by extending the return
payload 'struct nd_papr_pdsm_health' without breaking the ABI. A new
field 'dimm_fuel_gauge' to hold the metric value is introduced at the
end of the payload struct and its presence is indicated by by
extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID.

The patch introduces a new function papr_pdsm_fuel_gauge() that is
called from papr_pdsm_health(). If fetching NVDIMM performance stats
is supported then 'papr_pdsm_fuel_gauge()' allocated an output buffer
large enough to hold the performance stat and passes it to
drc_pmem_query_stats() that issues the HCALL to PHYP. The return value
of the stat is then populated in the 'struct
nd_papr_pdsm_health.dimm_fuel_gauge' field with extension flag
'PDSM_DIMM_HEALTH_RUN_GAUGE_VALID' set in 'struct
nd_papr_pdsm_health.extension_flags'

Signed-off-by: default avatarVaibhav Jain <vaibhav@linux.ibm.com>
Reviewed-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200731064153.182203-3-vaibhav@linux.ibm.com
parent 2d02bf83
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -72,6 +72,11 @@
#define PAPR_PDSM_DIMM_CRITICAL      2
#define PAPR_PDSM_DIMM_FATAL         3

/* struct nd_papr_pdsm_health.extension_flags field flags */

/* Indicate that the 'dimm_fuel_gauge' field is valid */
#define PDSM_DIMM_HEALTH_RUN_GAUGE_VALID 1

/*
 * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH
 * Various flags indicate the health status of the dimm.
@@ -84,6 +89,7 @@
 * dimm_locked		: Contents of the dimm cant be modified until CEC reboot
 * dimm_encrypted	: Contents of dimm are encrypted.
 * dimm_health		: Dimm health indicator. One of PAPR_PDSM_DIMM_XXXX
 * dimm_fuel_gauge	: Life remaining of DIMM as a percentage from 0-100
 */
struct nd_papr_pdsm_health {
	union {
@@ -96,6 +102,9 @@ struct nd_papr_pdsm_health {
			__u8 dimm_locked;
			__u8 dimm_encrypted;
			__u16 dimm_health;

			/* Extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID */
			__u16 dimm_fuel_gauge;
		};
		__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];
	};
+49 −0
Original line number Diff line number Diff line
@@ -518,6 +518,51 @@ static int is_cmd_valid(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
	return 0;
}

static int papr_pdsm_fuel_gauge(struct papr_scm_priv *p,
				union nd_pdsm_payload *payload)
{
	int rc, size;
	u64 statval;
	struct papr_scm_perf_stat *stat;
	struct papr_scm_perf_stats *stats;

	/* Silently fail if fetching performance metrics isn't  supported */
	if (!p->stat_buffer_len)
		return 0;

	/* Allocate request buffer enough to hold single performance stat */
	size = sizeof(struct papr_scm_perf_stats) +
		sizeof(struct papr_scm_perf_stat);

	stats = kzalloc(size, GFP_KERNEL);
	if (!stats)
		return -ENOMEM;

	stat = &stats->scm_statistic[0];
	memcpy(&stat->stat_id, "MemLife ", sizeof(stat->stat_id));
	stat->stat_val = 0;

	/* Fetch the fuel gauge and populate it in payload */
	rc = drc_pmem_query_stats(p, stats, 1);
	if (rc < 0) {
		dev_dbg(&p->pdev->dev, "Err(%d) fetching fuel gauge\n", rc);
		goto free_stats;
	}

	statval = be64_to_cpu(stat->stat_val);
	dev_dbg(&p->pdev->dev,
		"Fetched fuel-gauge %llu", statval);
	payload->health.extension_flags |=
		PDSM_DIMM_HEALTH_RUN_GAUGE_VALID;
	payload->health.dimm_fuel_gauge = statval;

	rc = sizeof(struct nd_papr_pdsm_health);

free_stats:
	kfree(stats);
	return rc;
}

/* Fetch the DIMM health info and populate it in provided package. */
static int papr_pdsm_health(struct papr_scm_priv *p,
			    union nd_pdsm_payload *payload)
@@ -558,6 +603,10 @@ static int papr_pdsm_health(struct papr_scm_priv *p,

	/* struct populated hence can release the mutex now */
	mutex_unlock(&p->health_mutex);

	/* Populate the fuel gauge meter in the payload */
	papr_pdsm_fuel_gauge(p, payload);

	rc = sizeof(struct nd_papr_pdsm_health);

out: