Re: [PATCH v4 2/2] powerpc/papr_scm: Add support for fetching nvdimm 'fuel-gauge' metric

Aneesh Kumar K.V
2020-07-31T07:15:05Z

Vaibhav Jain <vaibhav@linux.ibm.com> writes:

> 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'
>

Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>

> Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
> ---
> Changelog:
>
> v4:
> * Moved a hunk from this patch to previous patch in the series.
> [ Aneesh ]
>
> v3:
> * Updated papr_pdsm_fuel_guage() to use the updated
> drc_pmem_query_stats() function.
>
> Resend:
> None
>
> v2:
> * Restructure code in papr_pdsm_fuel_gauge() to handle error case
> first [ Ira ]
> * Ignore the return value of papr_pdsm_fuel_gauge() in
> papr_psdm_health() [ Ira ]
> ---
> arch/powerpc/include/uapi/asm/papr_pdsm.h | 9 +++++
> arch/powerpc/platforms/pseries/papr_scm.c | 49 +++++++++++++++++++++++
> 2 files changed, 58 insertions(+)
>
> diff --git a/arch/powerpc/include/uapi/asm/papr_pdsm.h b/arch/powerpc/include/uapi/asm/papr_pdsm.h
> index 9ccecc1d6840..50ef95e2f5b1 100644
> --- a/arch/powerpc/include/uapi/asm/papr_pdsm.h
> +++ b/arch/powerpc/include/uapi/asm/papr_pdsm.h
> @@ -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];
> };
> diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c
> index f37f3f70007d..f439f0dfea7d 100644
> --- a/arch/powerpc/platforms/pseries/papr_scm.c
> +++ b/arch/powerpc/platforms/pseries/papr_scm.c
> @@ -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:
> --
> 2.26.2