Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Vaibhav Jain <vaibhav@linux.ibm.com>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200731064153.182203-3-vaibhav@linux.ibm.com

authored by

Vaibhav Jain and committed by
Michael Ellerman
af0870c4 2d02bf83

+58
+9
arch/powerpc/include/uapi/asm/papr_pdsm.h
··· 72 72 #define PAPR_PDSM_DIMM_CRITICAL 2 73 73 #define PAPR_PDSM_DIMM_FATAL 3 74 74 75 + /* struct nd_papr_pdsm_health.extension_flags field flags */ 76 + 77 + /* Indicate that the 'dimm_fuel_gauge' field is valid */ 78 + #define PDSM_DIMM_HEALTH_RUN_GAUGE_VALID 1 79 + 75 80 /* 76 81 * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH 77 82 * Various flags indicate the health status of the dimm. ··· 89 84 * dimm_locked : Contents of the dimm cant be modified until CEC reboot 90 85 * dimm_encrypted : Contents of dimm are encrypted. 91 86 * dimm_health : Dimm health indicator. One of PAPR_PDSM_DIMM_XXXX 87 + * dimm_fuel_gauge : Life remaining of DIMM as a percentage from 0-100 92 88 */ 93 89 struct nd_papr_pdsm_health { 94 90 union { ··· 102 96 __u8 dimm_locked; 103 97 __u8 dimm_encrypted; 104 98 __u16 dimm_health; 99 + 100 + /* Extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID */ 101 + __u16 dimm_fuel_gauge; 105 102 }; 106 103 __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; 107 104 };
+49
arch/powerpc/platforms/pseries/papr_scm.c
··· 518 518 return 0; 519 519 } 520 520 521 + static int papr_pdsm_fuel_gauge(struct papr_scm_priv *p, 522 + union nd_pdsm_payload *payload) 523 + { 524 + int rc, size; 525 + u64 statval; 526 + struct papr_scm_perf_stat *stat; 527 + struct papr_scm_perf_stats *stats; 528 + 529 + /* Silently fail if fetching performance metrics isn't supported */ 530 + if (!p->stat_buffer_len) 531 + return 0; 532 + 533 + /* Allocate request buffer enough to hold single performance stat */ 534 + size = sizeof(struct papr_scm_perf_stats) + 535 + sizeof(struct papr_scm_perf_stat); 536 + 537 + stats = kzalloc(size, GFP_KERNEL); 538 + if (!stats) 539 + return -ENOMEM; 540 + 541 + stat = &stats->scm_statistic[0]; 542 + memcpy(&stat->stat_id, "MemLife ", sizeof(stat->stat_id)); 543 + stat->stat_val = 0; 544 + 545 + /* Fetch the fuel gauge and populate it in payload */ 546 + rc = drc_pmem_query_stats(p, stats, 1); 547 + if (rc < 0) { 548 + dev_dbg(&p->pdev->dev, "Err(%d) fetching fuel gauge\n", rc); 549 + goto free_stats; 550 + } 551 + 552 + statval = be64_to_cpu(stat->stat_val); 553 + dev_dbg(&p->pdev->dev, 554 + "Fetched fuel-gauge %llu", statval); 555 + payload->health.extension_flags |= 556 + PDSM_DIMM_HEALTH_RUN_GAUGE_VALID; 557 + payload->health.dimm_fuel_gauge = statval; 558 + 559 + rc = sizeof(struct nd_papr_pdsm_health); 560 + 561 + free_stats: 562 + kfree(stats); 563 + return rc; 564 + } 565 + 521 566 /* Fetch the DIMM health info and populate it in provided package. */ 522 567 static int papr_pdsm_health(struct papr_scm_priv *p, 523 568 union nd_pdsm_payload *payload) ··· 603 558 604 559 /* struct populated hence can release the mutex now */ 605 560 mutex_unlock(&p->health_mutex); 561 + 562 + /* Populate the fuel gauge meter in the payload */ 563 + papr_pdsm_fuel_gauge(p, payload); 564 + 606 565 rc = sizeof(struct nd_papr_pdsm_health); 607 566 608 567 out: