[PATCH v4 1/1] RISC-V: Create unique identification for SoC PMU

From: Nikita Shubin
Date: Sun Jun 19 2022 - 07:11:36 EST


From: Nikita Shubin <n.shubin@xxxxxxxxx>

Provide RISC-V SBI PMU id to distinguish different cores or SoCs via
"devices/platform/riscv-pmu/id" sysfs entry.

The identification is generated as string of marchid, mimpid, mvendorid
in hex format separated by coma - "0x70032,0x70032,0x0".

The CSRs are detailed in the RISC-V privileged spec [1].
[1] https://github.com/riscv/riscv-isa-manual

Inspired-by: João Mário Domingos <joao.mario@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Nikita Shubin <n.shubin@xxxxxxxxx>
---
v3->v4:
- use string for pmuid
- rename pmu_sbi_id_show to id_show
- fix error print message in id_show
- fix DEVICE_ATTR to use octal permissions
---
arch/riscv/kernel/sbi.c | 3 +++
drivers/perf/riscv_pmu_sbi.c | 41 ++++++++++++++++++++++++++++++++++
include/linux/perf/riscv_pmu.h | 1 +
3 files changed, 45 insertions(+)

diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
index 775d3322b422..50dd9b6ecc9e 100644
--- a/arch/riscv/kernel/sbi.c
+++ b/arch/riscv/kernel/sbi.c
@@ -627,16 +627,19 @@ long sbi_get_mvendorid(void)
{
return __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID);
}
+EXPORT_SYMBOL(sbi_get_mvendorid);

long sbi_get_marchid(void)
{
return __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID);
}
+EXPORT_SYMBOL(sbi_get_marchid);

long sbi_get_mimpid(void)
{
return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID);
}
+EXPORT_SYMBOL(sbi_get_mimpid);

static void sbi_send_cpumask_ipi(const struct cpumask *target)
{
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index dca3537a8dcc..be812f855617 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -693,6 +693,28 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
return 0;
}

+static ssize_t id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int len;
+ struct riscv_pmu *pmu = container_of(dev_get_drvdata(dev), struct riscv_pmu, pmu);
+
+ len = sprintf(buf, "%s\n", pmu->pmuid);
+ if (len <= 0)
+ dev_err(dev, "invalid sprintf len: %d\n", len);
+
+ return len;
+}
+
+static DEVICE_ATTR(id, 0644, id_show, NULL);
+
+static struct attribute *pmu_sbi_attrs[] = {
+ &dev_attr_id.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(pmu_sbi);
+
static int pmu_sbi_device_probe(struct platform_device *pdev)
{
struct riscv_pmu *pmu = NULL;
@@ -714,6 +736,14 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
if (pmu_sbi_get_ctrinfo(num_counters))
goto out_free;

+ /* fill pmuid */
+ pmu->pmuid = kasprintf(GFP_KERNEL, "0x%lx,0x%lx,0x%lx",
+ sbi_get_marchid(),
+ sbi_get_mimpid(),
+ sbi_get_mvendorid());
+ if (!pmu->pmuid)
+ goto out_free_pmuid;
+
ret = pmu_sbi_setup_irqs(pmu, pdev);
if (ret < 0) {
pr_info("Perf sampling/filtering is not supported as sscof extension is not available\n");
@@ -739,8 +769,19 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
return ret;
}

+ ret = sysfs_create_group(&pdev->dev.kobj, &pmu_sbi_group);
+ if (ret) {
+ dev_err(&pdev->dev, "sysfs creation failed\n");
+ return ret;
+ }
+
+ pdev->dev.groups = pmu_sbi_groups;
+ dev_set_drvdata(&pdev->dev, pmu);
+
return 0;

+out_free_pmuid:
+ kfree(pmu->pmuid);
out_free:
kfree(pmu);
return ret;
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index 46f9b6fe306e..cf3557b77fb8 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -42,6 +42,7 @@ struct cpu_hw_events {
struct riscv_pmu {
struct pmu pmu;
char *name;
+ char *pmuid;

irqreturn_t (*handle_irq)(int irq_num, void *dev);

--
2.35.1