diff mbox series

[v2] powerpc/papr_scm: Fix nvdimm event mappings

Message ID 20220711034605.212683-1-kjain@linux.ibm.com (mailing list archive)
State Changes Requested
Headers show
Series [v2] powerpc/papr_scm: Fix nvdimm event mappings | expand

Commit Message

Kajol Jain July 11, 2022, 3:46 a.m. UTC
Commit 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
added performance monitoring support for papr-scm nvdimm devices via
perf interface. Commit also added an array in papr_scm_priv
structure called "nvdimm_events_map", which got filled based on the
result of H_SCM_PERFORMANCE_STATS hcall. 

Currently there is an assumption that the order of events in the
stats buffer, returned by the hypervisor is same. And that order also
matches with the events specified in nvdimm driver code. 
But this assumption is not documented anywhere in Power Architecture
Platform Requirements (PAPR) document. Although the order
of events happens to be same on current systems, but it might
not be true in future generation systems. Fix the issue, by
adding a static mapping for nvdimm events to corresponding stat-id,
and removing the dynamic map from papr_scm_priv structure.

Fixes: 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
Reported-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Kajol Jain <kjain@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/papr_scm.c | 62 ++++++++++-------------
 1 file changed, 28 insertions(+), 34 deletions(-)

---
Changelog:
v1 -> v2
- To avoid accidental reordering, explicitly defined index for all
  the events. Also added valid config check in papr_scm_pmu_event_init
  function as suggested by Michael Ellerman.
- Did minor commit message changes and remove initialization of
  rc variable as suggested by Michael Ellerman  
- Link to the patch v1: https://patchwork.kernel.org/project/linux-nvdimm/patch/20220610133431.410514-1-kjain@linux.ibm.com/
---

Comments

Vaibhav Jain July 12, 2022, 5:15 a.m. UTC | #1
Hi Kajol,

Thanks for the patch. Minor review comment below:

Kajol Jain <kjain@linux.ibm.com> writes:

> Commit 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
> added performance monitoring support for papr-scm nvdimm devices via
> perf interface. Commit also added an array in papr_scm_priv
> structure called "nvdimm_events_map", which got filled based on the
> result of H_SCM_PERFORMANCE_STATS hcall. 
>
> Currently there is an assumption that the order of events in the
> stats buffer, returned by the hypervisor is same. And that order also
> matches with the events specified in nvdimm driver code. 
> But this assumption is not documented anywhere in Power Architecture
> Platform Requirements (PAPR) document. Although the order
> of events happens to be same on current systems, but it might
> not be true in future generation systems. Fix the issue, by
> adding a static mapping for nvdimm events to corresponding stat-id,
> and removing the dynamic map from papr_scm_priv structure.
>
> Fixes: 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
> Reported-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
> Signed-off-by: Kajol Jain <kjain@linux.ibm.com>

<snip>
> @@ -460,10 +480,9 @@ static void papr_scm_pmu_del(struct perf_event *event, int flags)
>  
>  static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu *nd_pmu)
>  {
> -	struct papr_scm_perf_stat *stat;
>  	struct papr_scm_perf_stats *stats;
>  	u32 available_events;
> -	int index, rc = 0;
> +	int rc;
>  
>  	if (!p->stat_buffer_len)
>  		return -ENOENT;
> @@ -476,34 +495,12 @@ static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
>  	/* Allocate the buffer for phyp where stats are written */
>  	stats = kzalloc(p->stat_buffer_len, GFP_KERNEL);
>  	if (!stats) {
> -		rc = -ENOMEM;
> -		return rc;
> +		return -ENOMEM;
>  	}
>  
>  	/* Called to get list of events supported */
>  	rc = drc_pmem_query_stats(p, stats, 0);
> -	if (rc)
> -		goto out;
> -
> -	/*
> -	 * Allocate memory and populate nvdimm_event_map.
> -	 * Allocate an extra element for NULL entry
> -	 */
> -	p->nvdimm_events_map = kcalloc(available_events + 1,
> -				       sizeof(stat->stat_id),
> -				       GFP_KERNEL);
> -	if (!p->nvdimm_events_map) {
> -		rc = -ENOMEM;
> -		goto out;
> -	}
>  
> -	/* Copy all stat_ids to event map */
> -	for (index = 0, stat = stats->scm_statistic;
> -	     index < available_events; index++, ++stat) {
> -		memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
> -		       &stat->stat_id, sizeof(stat->stat_id));
> -	}
> -out:
>  	kfree(stats);
>  	return rc;
>  }

Earlier implementation of papr_scm_pmu_check_events() would copy the
contents of returned stat-ids to struct papr_scm_priv->nvdimm_events_map,
hence it was needed.

With static events map you dont really need to call
drc_pmem_query_stats() as that would have been already being done once
in papr_scm_probe() before papr_scm_pmu_register() is called:


papr_scm_probe()
{
...
	/* Try retrieving the stat buffer and see if its supported */
	stat_size = drc_pmem_query_stats(p, NULL, 0);
...
        papr_scm_pmu_register(p);
...
}

I would suggest replacing single callsite of papr_scm_pmu_check_events()
with the check

     if (!p->stat_buffer_len)
		goto pmu_check_events_err;

<snip>
Kajol Jain July 13, 2022, 6:02 a.m. UTC | #2
On 7/12/22 10:45, Vaibhav Jain wrote:
> Hi Kajol,
> 
> Thanks for the patch. Minor review comment below:
> 
> Kajol Jain <kjain@linux.ibm.com> writes:
> 
>> Commit 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
>> added performance monitoring support for papr-scm nvdimm devices via
>> perf interface. Commit also added an array in papr_scm_priv
>> structure called "nvdimm_events_map", which got filled based on the
>> result of H_SCM_PERFORMANCE_STATS hcall. 
>>
>> Currently there is an assumption that the order of events in the
>> stats buffer, returned by the hypervisor is same. And that order also
>> matches with the events specified in nvdimm driver code. 
>> But this assumption is not documented anywhere in Power Architecture
>> Platform Requirements (PAPR) document. Although the order
>> of events happens to be same on current systems, but it might
>> not be true in future generation systems. Fix the issue, by
>> adding a static mapping for nvdimm events to corresponding stat-id,
>> and removing the dynamic map from papr_scm_priv structure.
>>
>> Fixes: 4c08d4bbc089 ("powerpc/papr_scm: Add perf interface support")
>> Reported-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
>> Signed-off-by: Kajol Jain <kjain@linux.ibm.com>
> 
> <snip>
>> @@ -460,10 +480,9 @@ static void papr_scm_pmu_del(struct perf_event *event, int flags)
>>  
>>  static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu *nd_pmu)
>>  {
>> -	struct papr_scm_perf_stat *stat;
>>  	struct papr_scm_perf_stats *stats;
>>  	u32 available_events;
>> -	int index, rc = 0;
>> +	int rc;
>>  
>>  	if (!p->stat_buffer_len)
>>  		return -ENOENT;
>> @@ -476,34 +495,12 @@ static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
>>  	/* Allocate the buffer for phyp where stats are written */
>>  	stats = kzalloc(p->stat_buffer_len, GFP_KERNEL);
>>  	if (!stats) {
>> -		rc = -ENOMEM;
>> -		return rc;
>> +		return -ENOMEM;
>>  	}
>>  
>>  	/* Called to get list of events supported */
>>  	rc = drc_pmem_query_stats(p, stats, 0);
>> -	if (rc)
>> -		goto out;
>> -
>> -	/*
>> -	 * Allocate memory and populate nvdimm_event_map.
>> -	 * Allocate an extra element for NULL entry
>> -	 */
>> -	p->nvdimm_events_map = kcalloc(available_events + 1,
>> -				       sizeof(stat->stat_id),
>> -				       GFP_KERNEL);
>> -	if (!p->nvdimm_events_map) {
>> -		rc = -ENOMEM;
>> -		goto out;
>> -	}
>>  
>> -	/* Copy all stat_ids to event map */
>> -	for (index = 0, stat = stats->scm_statistic;
>> -	     index < available_events; index++, ++stat) {
>> -		memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
>> -		       &stat->stat_id, sizeof(stat->stat_id));
>> -	}
>> -out:
>>  	kfree(stats);
>>  	return rc;
>>  }
> 
> Earlier implementation of papr_scm_pmu_check_events() would copy the
> contents of returned stat-ids to struct papr_scm_priv->nvdimm_events_map,
> hence it was needed.
> 
> With static events map you dont really need to call
> drc_pmem_query_stats() as that would have been already being done once
> in papr_scm_probe() before papr_scm_pmu_register() is called:
> 
> 

Hi Vaibhav,
    Thanks for reviewing the patch. Yes it make sense, as mainly we want
to make sure, in case stat buffer is empty we will not register the
nvdimm pmu. I will do the change and send next version of the patch.

Thanks,
Kajol Jain

> papr_scm_probe()
> {
> ...
> 	/* Try retrieving the stat buffer and see if its supported */
> 	stat_size = drc_pmem_query_stats(p, NULL, 0);
> ...
>         papr_scm_pmu_register(p);
> ...
> }
> 
> I would suggest replacing single callsite of papr_scm_pmu_check_events()
> with the check
> 
>      if (!p->stat_buffer_len)
> 		goto pmu_check_events_err;
> 
> <snip>
>
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c
index 82cae08976bc..139e243c3f49 100644
--- a/arch/powerpc/platforms/pseries/papr_scm.c
+++ b/arch/powerpc/platforms/pseries/papr_scm.c
@@ -124,9 +124,6 @@  struct papr_scm_priv {
 
 	/* The bits which needs to be overridden */
 	u64 health_bitmap_inject_mask;
-
-	/* array to have event_code and stat_id mappings */
-	u8 *nvdimm_events_map;
 };
 
 static int papr_scm_pmem_flush(struct nd_region *nd_region,
@@ -350,6 +347,25 @@  static ssize_t drc_pmem_query_stats(struct papr_scm_priv *p,
 #ifdef CONFIG_PERF_EVENTS
 #define to_nvdimm_pmu(_pmu)	container_of(_pmu, struct nvdimm_pmu, pmu)
 
+static const char * const nvdimm_events_map[] = {
+	[1] = "CtlResCt",
+	[2] = "CtlResTm",
+	[3] = "PonSecs ",
+	[4] = "MemLife ",
+	[5] = "CritRscU",
+	[6] = "HostLCnt",
+	[7] = "HostSCnt",
+	[8] = "HostSDur",
+	[9] = "HostLDur",
+	[10] = "MedRCnt ",
+	[11] = "MedWCnt ",
+	[12] = "MedRDur ",
+	[13] = "MedWDur ",
+	[14] = "CchRHCnt",
+	[15] = "CchWHCnt",
+	[16] = "FastWCnt",
+};
+
 static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev, u64 *count)
 {
 	struct papr_scm_perf_stat *stat;
@@ -357,11 +373,15 @@  static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev,
 	struct papr_scm_priv *p = (struct papr_scm_priv *)dev->driver_data;
 	int rc, size;
 
+	/* Invalid eventcode */
+	if (event->attr.config == 0 || event->attr.config >= ARRAY_SIZE(nvdimm_events_map))
+		return -EINVAL;
+
 	/* Allocate request buffer enough to hold single performance stat */
 	size = sizeof(struct papr_scm_perf_stats) +
 		sizeof(struct papr_scm_perf_stat);
 
-	if (!p || !p->nvdimm_events_map)
+	if (!p)
 		return -EINVAL;
 
 	stats = kzalloc(size, GFP_KERNEL);
@@ -370,7 +390,7 @@  static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev,
 
 	stat = &stats->scm_statistic[0];
 	memcpy(&stat->stat_id,
-	       &p->nvdimm_events_map[event->attr.config * sizeof(stat->stat_id)],
+	       nvdimm_events_map[event->attr.config],
 		sizeof(stat->stat_id));
 	stat->stat_val = 0;
 
@@ -460,10 +480,9 @@  static void papr_scm_pmu_del(struct perf_event *event, int flags)
 
 static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu *nd_pmu)
 {
-	struct papr_scm_perf_stat *stat;
 	struct papr_scm_perf_stats *stats;
 	u32 available_events;
-	int index, rc = 0;
+	int rc;
 
 	if (!p->stat_buffer_len)
 		return -ENOENT;
@@ -476,34 +495,12 @@  static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
 	/* Allocate the buffer for phyp where stats are written */
 	stats = kzalloc(p->stat_buffer_len, GFP_KERNEL);
 	if (!stats) {
-		rc = -ENOMEM;
-		return rc;
+		return -ENOMEM;
 	}
 
 	/* Called to get list of events supported */
 	rc = drc_pmem_query_stats(p, stats, 0);
-	if (rc)
-		goto out;
-
-	/*
-	 * Allocate memory and populate nvdimm_event_map.
-	 * Allocate an extra element for NULL entry
-	 */
-	p->nvdimm_events_map = kcalloc(available_events + 1,
-				       sizeof(stat->stat_id),
-				       GFP_KERNEL);
-	if (!p->nvdimm_events_map) {
-		rc = -ENOMEM;
-		goto out;
-	}
 
-	/* Copy all stat_ids to event map */
-	for (index = 0, stat = stats->scm_statistic;
-	     index < available_events; index++, ++stat) {
-		memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
-		       &stat->stat_id, sizeof(stat->stat_id));
-	}
-out:
 	kfree(stats);
 	return rc;
 }
@@ -539,7 +536,7 @@  static void papr_scm_pmu_register(struct papr_scm_priv *p)
 
 	rc = register_nvdimm_pmu(nd_pmu, p->pdev);
 	if (rc)
-		goto pmu_register_err;
+		goto pmu_check_events_err;
 
 	/*
 	 * Set archdata.priv value to nvdimm_pmu structure, to handle the
@@ -548,8 +545,6 @@  static void papr_scm_pmu_register(struct papr_scm_priv *p)
 	p->pdev->archdata.priv = nd_pmu;
 	return;
 
-pmu_register_err:
-	kfree(p->nvdimm_events_map);
 pmu_check_events_err:
 	kfree(nd_pmu);
 pmu_err_print:
@@ -1560,7 +1555,6 @@  static int papr_scm_remove(struct platform_device *pdev)
 		unregister_nvdimm_pmu(pdev->archdata.priv);
 
 	pdev->archdata.priv = NULL;
-	kfree(p->nvdimm_events_map);
 	kfree(p->bus_desc.provider_name);
 	kfree(p);