10fab1ba6SKajol Jain // SPDX-License-Identifier: GPL-2.0-or-later
20fab1ba6SKajol Jain /*
30fab1ba6SKajol Jain * nd_perf.c: NVDIMM Device Performance Monitoring Unit support
40fab1ba6SKajol Jain *
50fab1ba6SKajol Jain * Perf interface to expose nvdimm performance stats.
60fab1ba6SKajol Jain *
70fab1ba6SKajol Jain * Copyright (C) 2021 IBM Corporation
80fab1ba6SKajol Jain */
90fab1ba6SKajol Jain
100fab1ba6SKajol Jain #define pr_fmt(fmt) "nvdimm_pmu: " fmt
110fab1ba6SKajol Jain
120fab1ba6SKajol Jain #include <linux/nd.h>
13de7a9e94SKajol Jain #include <linux/platform_device.h>
140fab1ba6SKajol Jain
150fab1ba6SKajol Jain #define EVENT(_name, _code) enum{_name = _code}
160fab1ba6SKajol Jain
170fab1ba6SKajol Jain /*
180fab1ba6SKajol Jain * NVDIMM Events codes.
190fab1ba6SKajol Jain */
200fab1ba6SKajol Jain
210fab1ba6SKajol Jain /* Controller Reset Count */
220fab1ba6SKajol Jain EVENT(CTL_RES_CNT, 0x1);
230fab1ba6SKajol Jain /* Controller Reset Elapsed Time */
240fab1ba6SKajol Jain EVENT(CTL_RES_TM, 0x2);
250fab1ba6SKajol Jain /* Power-on Seconds */
260fab1ba6SKajol Jain EVENT(POWERON_SECS, 0x3);
270fab1ba6SKajol Jain /* Life Remaining */
280fab1ba6SKajol Jain EVENT(MEM_LIFE, 0x4);
290fab1ba6SKajol Jain /* Critical Resource Utilization */
300fab1ba6SKajol Jain EVENT(CRI_RES_UTIL, 0x5);
310fab1ba6SKajol Jain /* Host Load Count */
320fab1ba6SKajol Jain EVENT(HOST_L_CNT, 0x6);
330fab1ba6SKajol Jain /* Host Store Count */
340fab1ba6SKajol Jain EVENT(HOST_S_CNT, 0x7);
350fab1ba6SKajol Jain /* Host Store Duration */
360fab1ba6SKajol Jain EVENT(HOST_S_DUR, 0x8);
370fab1ba6SKajol Jain /* Host Load Duration */
380fab1ba6SKajol Jain EVENT(HOST_L_DUR, 0x9);
390fab1ba6SKajol Jain /* Media Read Count */
400fab1ba6SKajol Jain EVENT(MED_R_CNT, 0xa);
410fab1ba6SKajol Jain /* Media Write Count */
420fab1ba6SKajol Jain EVENT(MED_W_CNT, 0xb);
430fab1ba6SKajol Jain /* Media Read Duration */
440fab1ba6SKajol Jain EVENT(MED_R_DUR, 0xc);
450fab1ba6SKajol Jain /* Media Write Duration */
460fab1ba6SKajol Jain EVENT(MED_W_DUR, 0xd);
470fab1ba6SKajol Jain /* Cache Read Hit Count */
480fab1ba6SKajol Jain EVENT(CACHE_RH_CNT, 0xe);
490fab1ba6SKajol Jain /* Cache Write Hit Count */
500fab1ba6SKajol Jain EVENT(CACHE_WH_CNT, 0xf);
510fab1ba6SKajol Jain /* Fast Write Count */
520fab1ba6SKajol Jain EVENT(FAST_W_CNT, 0x10);
530fab1ba6SKajol Jain
540fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(ctl_res_cnt, CTL_RES_CNT);
550fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(ctl_res_tm, CTL_RES_TM);
560fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(poweron_secs, POWERON_SECS);
570fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(mem_life, MEM_LIFE);
580fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(cri_res_util, CRI_RES_UTIL);
590fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(host_l_cnt, HOST_L_CNT);
600fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(host_s_cnt, HOST_S_CNT);
610fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(host_s_dur, HOST_S_DUR);
620fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(host_l_dur, HOST_L_DUR);
630fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(med_r_cnt, MED_R_CNT);
640fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(med_w_cnt, MED_W_CNT);
650fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(med_r_dur, MED_R_DUR);
660fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(med_w_dur, MED_W_DUR);
670fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(cache_rh_cnt, CACHE_RH_CNT);
680fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(cache_wh_cnt, CACHE_WH_CNT);
690fab1ba6SKajol Jain NVDIMM_EVENT_ATTR(fast_w_cnt, FAST_W_CNT);
700fab1ba6SKajol Jain
710fab1ba6SKajol Jain static struct attribute *nvdimm_events_attr[] = {
720fab1ba6SKajol Jain NVDIMM_EVENT_PTR(CTL_RES_CNT),
730fab1ba6SKajol Jain NVDIMM_EVENT_PTR(CTL_RES_TM),
740fab1ba6SKajol Jain NVDIMM_EVENT_PTR(POWERON_SECS),
750fab1ba6SKajol Jain NVDIMM_EVENT_PTR(MEM_LIFE),
760fab1ba6SKajol Jain NVDIMM_EVENT_PTR(CRI_RES_UTIL),
770fab1ba6SKajol Jain NVDIMM_EVENT_PTR(HOST_L_CNT),
780fab1ba6SKajol Jain NVDIMM_EVENT_PTR(HOST_S_CNT),
790fab1ba6SKajol Jain NVDIMM_EVENT_PTR(HOST_S_DUR),
800fab1ba6SKajol Jain NVDIMM_EVENT_PTR(HOST_L_DUR),
810fab1ba6SKajol Jain NVDIMM_EVENT_PTR(MED_R_CNT),
820fab1ba6SKajol Jain NVDIMM_EVENT_PTR(MED_W_CNT),
830fab1ba6SKajol Jain NVDIMM_EVENT_PTR(MED_R_DUR),
840fab1ba6SKajol Jain NVDIMM_EVENT_PTR(MED_W_DUR),
850fab1ba6SKajol Jain NVDIMM_EVENT_PTR(CACHE_RH_CNT),
860fab1ba6SKajol Jain NVDIMM_EVENT_PTR(CACHE_WH_CNT),
870fab1ba6SKajol Jain NVDIMM_EVENT_PTR(FAST_W_CNT),
880fab1ba6SKajol Jain NULL
890fab1ba6SKajol Jain };
900fab1ba6SKajol Jain
910fab1ba6SKajol Jain static struct attribute_group nvdimm_pmu_events_group = {
920fab1ba6SKajol Jain .name = "events",
930fab1ba6SKajol Jain .attrs = nvdimm_events_attr,
940fab1ba6SKajol Jain };
950fab1ba6SKajol Jain
960fab1ba6SKajol Jain PMU_FORMAT_ATTR(event, "config:0-4");
970fab1ba6SKajol Jain
980fab1ba6SKajol Jain static struct attribute *nvdimm_pmu_format_attr[] = {
990fab1ba6SKajol Jain &format_attr_event.attr,
1000fab1ba6SKajol Jain NULL,
1010fab1ba6SKajol Jain };
1020fab1ba6SKajol Jain
1030fab1ba6SKajol Jain static struct attribute_group nvdimm_pmu_format_group = {
1040fab1ba6SKajol Jain .name = "format",
1050fab1ba6SKajol Jain .attrs = nvdimm_pmu_format_attr,
1060fab1ba6SKajol Jain };
1070fab1ba6SKajol Jain
nvdimm_events_sysfs_show(struct device * dev,struct device_attribute * attr,char * page)1080fab1ba6SKajol Jain ssize_t nvdimm_events_sysfs_show(struct device *dev,
1090fab1ba6SKajol Jain struct device_attribute *attr, char *page)
1100fab1ba6SKajol Jain {
1110fab1ba6SKajol Jain struct perf_pmu_events_attr *pmu_attr;
1120fab1ba6SKajol Jain
1130fab1ba6SKajol Jain pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
1140fab1ba6SKajol Jain
1150fab1ba6SKajol Jain return sprintf(page, "event=0x%02llx\n", pmu_attr->id);
1160fab1ba6SKajol Jain }
1170fab1ba6SKajol Jain
nvdimm_pmu_cpumask_show(struct device * dev,struct device_attribute * attr,char * buf)1180fab1ba6SKajol Jain static ssize_t nvdimm_pmu_cpumask_show(struct device *dev,
1190fab1ba6SKajol Jain struct device_attribute *attr, char *buf)
1200fab1ba6SKajol Jain {
1210fab1ba6SKajol Jain struct pmu *pmu = dev_get_drvdata(dev);
1220fab1ba6SKajol Jain struct nvdimm_pmu *nd_pmu;
1230fab1ba6SKajol Jain
1240fab1ba6SKajol Jain nd_pmu = container_of(pmu, struct nvdimm_pmu, pmu);
1250fab1ba6SKajol Jain
1260fab1ba6SKajol Jain return cpumap_print_to_pagebuf(true, buf, cpumask_of(nd_pmu->cpu));
1270fab1ba6SKajol Jain }
1280fab1ba6SKajol Jain
nvdimm_pmu_cpu_offline(unsigned int cpu,struct hlist_node * node)1290fab1ba6SKajol Jain static int nvdimm_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
1300fab1ba6SKajol Jain {
1310fab1ba6SKajol Jain struct nvdimm_pmu *nd_pmu;
1320fab1ba6SKajol Jain u32 target;
1330fab1ba6SKajol Jain int nodeid;
1340fab1ba6SKajol Jain const struct cpumask *cpumask;
1350fab1ba6SKajol Jain
1360fab1ba6SKajol Jain nd_pmu = hlist_entry_safe(node, struct nvdimm_pmu, node);
1370fab1ba6SKajol Jain
1380fab1ba6SKajol Jain /* Clear it, incase given cpu is set in nd_pmu->arch_cpumask */
1390fab1ba6SKajol Jain cpumask_test_and_clear_cpu(cpu, &nd_pmu->arch_cpumask);
1400fab1ba6SKajol Jain
1410fab1ba6SKajol Jain /*
1420fab1ba6SKajol Jain * If given cpu is not same as current designated cpu for
1430fab1ba6SKajol Jain * counter access, just return.
1440fab1ba6SKajol Jain */
1450fab1ba6SKajol Jain if (cpu != nd_pmu->cpu)
1460fab1ba6SKajol Jain return 0;
1470fab1ba6SKajol Jain
1480fab1ba6SKajol Jain /* Check for any active cpu in nd_pmu->arch_cpumask */
1490fab1ba6SKajol Jain target = cpumask_any(&nd_pmu->arch_cpumask);
1500fab1ba6SKajol Jain
1510fab1ba6SKajol Jain /*
1520fab1ba6SKajol Jain * Incase we don't have any active cpu in nd_pmu->arch_cpumask,
1530fab1ba6SKajol Jain * check in given cpu's numa node list.
1540fab1ba6SKajol Jain */
1550fab1ba6SKajol Jain if (target >= nr_cpu_ids) {
1560fab1ba6SKajol Jain nodeid = cpu_to_node(cpu);
1570fab1ba6SKajol Jain cpumask = cpumask_of_node(nodeid);
1580fab1ba6SKajol Jain target = cpumask_any_but(cpumask, cpu);
1590fab1ba6SKajol Jain }
1600fab1ba6SKajol Jain nd_pmu->cpu = target;
1610fab1ba6SKajol Jain
1620fab1ba6SKajol Jain /* Migrate nvdimm pmu events to the new target cpu if valid */
1630fab1ba6SKajol Jain if (target >= 0 && target < nr_cpu_ids)
1640fab1ba6SKajol Jain perf_pmu_migrate_context(&nd_pmu->pmu, cpu, target);
1650fab1ba6SKajol Jain
1660fab1ba6SKajol Jain return 0;
1670fab1ba6SKajol Jain }
1680fab1ba6SKajol Jain
nvdimm_pmu_cpu_online(unsigned int cpu,struct hlist_node * node)1690fab1ba6SKajol Jain static int nvdimm_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
1700fab1ba6SKajol Jain {
1710fab1ba6SKajol Jain struct nvdimm_pmu *nd_pmu;
1720fab1ba6SKajol Jain
1730fab1ba6SKajol Jain nd_pmu = hlist_entry_safe(node, struct nvdimm_pmu, node);
1740fab1ba6SKajol Jain
1750fab1ba6SKajol Jain if (nd_pmu->cpu >= nr_cpu_ids)
1760fab1ba6SKajol Jain nd_pmu->cpu = cpu;
1770fab1ba6SKajol Jain
1780fab1ba6SKajol Jain return 0;
1790fab1ba6SKajol Jain }
1800fab1ba6SKajol Jain
create_cpumask_attr_group(struct nvdimm_pmu * nd_pmu)1810fab1ba6SKajol Jain static int create_cpumask_attr_group(struct nvdimm_pmu *nd_pmu)
1820fab1ba6SKajol Jain {
1830fab1ba6SKajol Jain struct perf_pmu_events_attr *pmu_events_attr;
1840fab1ba6SKajol Jain struct attribute **attrs_group;
1850fab1ba6SKajol Jain struct attribute_group *nvdimm_pmu_cpumask_group;
1860fab1ba6SKajol Jain
1870fab1ba6SKajol Jain pmu_events_attr = kzalloc(sizeof(*pmu_events_attr), GFP_KERNEL);
1880fab1ba6SKajol Jain if (!pmu_events_attr)
1890fab1ba6SKajol Jain return -ENOMEM;
1900fab1ba6SKajol Jain
1910fab1ba6SKajol Jain attrs_group = kzalloc(2 * sizeof(struct attribute *), GFP_KERNEL);
1920fab1ba6SKajol Jain if (!attrs_group) {
1930fab1ba6SKajol Jain kfree(pmu_events_attr);
1940fab1ba6SKajol Jain return -ENOMEM;
1950fab1ba6SKajol Jain }
1960fab1ba6SKajol Jain
1970fab1ba6SKajol Jain /* Allocate memory for cpumask attribute group */
1980fab1ba6SKajol Jain nvdimm_pmu_cpumask_group = kzalloc(sizeof(*nvdimm_pmu_cpumask_group), GFP_KERNEL);
1990fab1ba6SKajol Jain if (!nvdimm_pmu_cpumask_group) {
2000fab1ba6SKajol Jain kfree(pmu_events_attr);
2010fab1ba6SKajol Jain kfree(attrs_group);
2020fab1ba6SKajol Jain return -ENOMEM;
2030fab1ba6SKajol Jain }
2040fab1ba6SKajol Jain
2050fab1ba6SKajol Jain sysfs_attr_init(&pmu_events_attr->attr.attr);
2060fab1ba6SKajol Jain pmu_events_attr->attr.attr.name = "cpumask";
2070fab1ba6SKajol Jain pmu_events_attr->attr.attr.mode = 0444;
2080fab1ba6SKajol Jain pmu_events_attr->attr.show = nvdimm_pmu_cpumask_show;
2090fab1ba6SKajol Jain attrs_group[0] = &pmu_events_attr->attr.attr;
2100fab1ba6SKajol Jain attrs_group[1] = NULL;
2110fab1ba6SKajol Jain
2120fab1ba6SKajol Jain nvdimm_pmu_cpumask_group->attrs = attrs_group;
2130fab1ba6SKajol Jain nd_pmu->pmu.attr_groups[NVDIMM_PMU_CPUMASK_ATTR] = nvdimm_pmu_cpumask_group;
2140fab1ba6SKajol Jain return 0;
2150fab1ba6SKajol Jain }
2160fab1ba6SKajol Jain
nvdimm_pmu_cpu_hotplug_init(struct nvdimm_pmu * nd_pmu)2170fab1ba6SKajol Jain static int nvdimm_pmu_cpu_hotplug_init(struct nvdimm_pmu *nd_pmu)
2180fab1ba6SKajol Jain {
2190fab1ba6SKajol Jain int nodeid, rc;
2200fab1ba6SKajol Jain const struct cpumask *cpumask;
2210fab1ba6SKajol Jain
2220fab1ba6SKajol Jain /*
2230fab1ba6SKajol Jain * Incase of cpu hotplug feature, arch specific code
2240fab1ba6SKajol Jain * can provide required cpumask which can be used
2250fab1ba6SKajol Jain * to get designatd cpu for counter access.
2260fab1ba6SKajol Jain * Check for any active cpu in nd_pmu->arch_cpumask.
2270fab1ba6SKajol Jain */
2280fab1ba6SKajol Jain if (!cpumask_empty(&nd_pmu->arch_cpumask)) {
2290fab1ba6SKajol Jain nd_pmu->cpu = cpumask_any(&nd_pmu->arch_cpumask);
2300fab1ba6SKajol Jain } else {
2310fab1ba6SKajol Jain /* pick active cpu from the cpumask of device numa node. */
2320fab1ba6SKajol Jain nodeid = dev_to_node(nd_pmu->dev);
2330fab1ba6SKajol Jain cpumask = cpumask_of_node(nodeid);
2340fab1ba6SKajol Jain nd_pmu->cpu = cpumask_any(cpumask);
2350fab1ba6SKajol Jain }
2360fab1ba6SKajol Jain
2370fab1ba6SKajol Jain rc = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "perf/nvdimm:online",
2380fab1ba6SKajol Jain nvdimm_pmu_cpu_online, nvdimm_pmu_cpu_offline);
2390fab1ba6SKajol Jain
2400fab1ba6SKajol Jain if (rc < 0)
2410fab1ba6SKajol Jain return rc;
2420fab1ba6SKajol Jain
2430fab1ba6SKajol Jain nd_pmu->cpuhp_state = rc;
2440fab1ba6SKajol Jain
2450fab1ba6SKajol Jain /* Register the pmu instance for cpu hotplug */
2460fab1ba6SKajol Jain rc = cpuhp_state_add_instance_nocalls(nd_pmu->cpuhp_state, &nd_pmu->node);
2470fab1ba6SKajol Jain if (rc) {
2480fab1ba6SKajol Jain cpuhp_remove_multi_state(nd_pmu->cpuhp_state);
2490fab1ba6SKajol Jain return rc;
2500fab1ba6SKajol Jain }
2510fab1ba6SKajol Jain
2520fab1ba6SKajol Jain /* Create cpumask attribute group */
2530fab1ba6SKajol Jain rc = create_cpumask_attr_group(nd_pmu);
2540fab1ba6SKajol Jain if (rc) {
2550fab1ba6SKajol Jain cpuhp_state_remove_instance_nocalls(nd_pmu->cpuhp_state, &nd_pmu->node);
2560fab1ba6SKajol Jain cpuhp_remove_multi_state(nd_pmu->cpuhp_state);
2570fab1ba6SKajol Jain return rc;
2580fab1ba6SKajol Jain }
2590fab1ba6SKajol Jain
2600fab1ba6SKajol Jain return 0;
2610fab1ba6SKajol Jain }
2620fab1ba6SKajol Jain
nvdimm_pmu_free_hotplug_memory(struct nvdimm_pmu * nd_pmu)2630fab1ba6SKajol Jain static void nvdimm_pmu_free_hotplug_memory(struct nvdimm_pmu *nd_pmu)
2640fab1ba6SKajol Jain {
2650fab1ba6SKajol Jain cpuhp_state_remove_instance_nocalls(nd_pmu->cpuhp_state, &nd_pmu->node);
2660fab1ba6SKajol Jain cpuhp_remove_multi_state(nd_pmu->cpuhp_state);
2670fab1ba6SKajol Jain
2680fab1ba6SKajol Jain if (nd_pmu->pmu.attr_groups[NVDIMM_PMU_CPUMASK_ATTR])
2690fab1ba6SKajol Jain kfree(nd_pmu->pmu.attr_groups[NVDIMM_PMU_CPUMASK_ATTR]->attrs);
2700fab1ba6SKajol Jain kfree(nd_pmu->pmu.attr_groups[NVDIMM_PMU_CPUMASK_ATTR]);
2710fab1ba6SKajol Jain }
2720fab1ba6SKajol Jain
register_nvdimm_pmu(struct nvdimm_pmu * nd_pmu,struct platform_device * pdev)2730fab1ba6SKajol Jain int register_nvdimm_pmu(struct nvdimm_pmu *nd_pmu, struct platform_device *pdev)
2740fab1ba6SKajol Jain {
2750fab1ba6SKajol Jain int rc;
2760fab1ba6SKajol Jain
2770fab1ba6SKajol Jain if (!nd_pmu || !pdev)
2780fab1ba6SKajol Jain return -EINVAL;
2790fab1ba6SKajol Jain
2800fab1ba6SKajol Jain /* event functions like add/del/read/event_init and pmu name should not be NULL */
2810fab1ba6SKajol Jain if (WARN_ON_ONCE(!(nd_pmu->pmu.event_init && nd_pmu->pmu.add &&
2820fab1ba6SKajol Jain nd_pmu->pmu.del && nd_pmu->pmu.read && nd_pmu->pmu.name)))
2830fab1ba6SKajol Jain return -EINVAL;
2840fab1ba6SKajol Jain
2850fab1ba6SKajol Jain nd_pmu->pmu.attr_groups = kzalloc((NVDIMM_PMU_NULL_ATTR + 1) *
2860fab1ba6SKajol Jain sizeof(struct attribute_group *), GFP_KERNEL);
2870fab1ba6SKajol Jain if (!nd_pmu->pmu.attr_groups)
2880fab1ba6SKajol Jain return -ENOMEM;
2890fab1ba6SKajol Jain
2900fab1ba6SKajol Jain /*
2910fab1ba6SKajol Jain * Add platform_device->dev pointer to nvdimm_pmu to access
2920fab1ba6SKajol Jain * device data in events functions.
2930fab1ba6SKajol Jain */
2940fab1ba6SKajol Jain nd_pmu->dev = &pdev->dev;
2950fab1ba6SKajol Jain
2960fab1ba6SKajol Jain /* Fill attribute groups for the nvdimm pmu device */
2970fab1ba6SKajol Jain nd_pmu->pmu.attr_groups[NVDIMM_PMU_FORMAT_ATTR] = &nvdimm_pmu_format_group;
2980fab1ba6SKajol Jain nd_pmu->pmu.attr_groups[NVDIMM_PMU_EVENT_ATTR] = &nvdimm_pmu_events_group;
2990fab1ba6SKajol Jain nd_pmu->pmu.attr_groups[NVDIMM_PMU_NULL_ATTR] = NULL;
3000fab1ba6SKajol Jain
3010fab1ba6SKajol Jain /* Fill attribute group for cpumask */
3020fab1ba6SKajol Jain rc = nvdimm_pmu_cpu_hotplug_init(nd_pmu);
3030fab1ba6SKajol Jain if (rc) {
3040fab1ba6SKajol Jain pr_info("cpu hotplug feature failed for device: %s\n", nd_pmu->pmu.name);
3050fab1ba6SKajol Jain kfree(nd_pmu->pmu.attr_groups);
3060fab1ba6SKajol Jain return rc;
3070fab1ba6SKajol Jain }
3080fab1ba6SKajol Jain
3090fab1ba6SKajol Jain rc = perf_pmu_register(&nd_pmu->pmu, nd_pmu->pmu.name, -1);
3100fab1ba6SKajol Jain if (rc) {
3110fab1ba6SKajol Jain nvdimm_pmu_free_hotplug_memory(nd_pmu);
312*08ca6906SKonstantin Meskhidze kfree(nd_pmu->pmu.attr_groups);
3130fab1ba6SKajol Jain return rc;
3140fab1ba6SKajol Jain }
3150fab1ba6SKajol Jain
3160fab1ba6SKajol Jain pr_info("%s NVDIMM performance monitor support registered\n",
3170fab1ba6SKajol Jain nd_pmu->pmu.name);
3180fab1ba6SKajol Jain
3190fab1ba6SKajol Jain return 0;
3200fab1ba6SKajol Jain }
3210fab1ba6SKajol Jain EXPORT_SYMBOL_GPL(register_nvdimm_pmu);
3220fab1ba6SKajol Jain
unregister_nvdimm_pmu(struct nvdimm_pmu * nd_pmu)3230fab1ba6SKajol Jain void unregister_nvdimm_pmu(struct nvdimm_pmu *nd_pmu)
3240fab1ba6SKajol Jain {
3250fab1ba6SKajol Jain perf_pmu_unregister(&nd_pmu->pmu);
3260fab1ba6SKajol Jain nvdimm_pmu_free_hotplug_memory(nd_pmu);
32785ae42c7SKonstantin Meskhidze kfree(nd_pmu->pmu.attr_groups);
3280fab1ba6SKajol Jain kfree(nd_pmu);
3290fab1ba6SKajol Jain }
3300fab1ba6SKajol Jain EXPORT_SYMBOL_GPL(unregister_nvdimm_pmu);
331