xref: /linux/drivers/cxl/core/pmu.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
11ad3f701SJonathan Cameron // SPDX-License-Identifier: GPL-2.0-only
21ad3f701SJonathan Cameron /* Copyright(c) 2023 Huawei. All rights reserved. */
31ad3f701SJonathan Cameron 
41ad3f701SJonathan Cameron #include <linux/device.h>
51ad3f701SJonathan Cameron #include <linux/slab.h>
61ad3f701SJonathan Cameron #include <linux/idr.h>
71ad3f701SJonathan Cameron #include <cxlmem.h>
81ad3f701SJonathan Cameron #include <pmu.h>
91ad3f701SJonathan Cameron #include <cxl.h>
101ad3f701SJonathan Cameron #include "core.h"
111ad3f701SJonathan Cameron 
cxl_pmu_release(struct device * dev)121ad3f701SJonathan Cameron static void cxl_pmu_release(struct device *dev)
131ad3f701SJonathan Cameron {
141ad3f701SJonathan Cameron 	struct cxl_pmu *pmu = to_cxl_pmu(dev);
151ad3f701SJonathan Cameron 
161ad3f701SJonathan Cameron 	kfree(pmu);
171ad3f701SJonathan Cameron }
181ad3f701SJonathan Cameron 
191ad3f701SJonathan Cameron const struct device_type cxl_pmu_type = {
201ad3f701SJonathan Cameron 	.name = "cxl_pmu",
211ad3f701SJonathan Cameron 	.release = cxl_pmu_release,
221ad3f701SJonathan Cameron };
231ad3f701SJonathan Cameron 
remove_dev(void * dev)241ad3f701SJonathan Cameron static void remove_dev(void *dev)
251ad3f701SJonathan Cameron {
26*ef3d5cf9SIra Weiny 	device_unregister(dev);
271ad3f701SJonathan Cameron }
281ad3f701SJonathan Cameron 
devm_cxl_pmu_add(struct device * parent,struct cxl_pmu_regs * regs,int assoc_id,int index,enum cxl_pmu_type type)291ad3f701SJonathan Cameron int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,
301ad3f701SJonathan Cameron 		     int assoc_id, int index, enum cxl_pmu_type type)
311ad3f701SJonathan Cameron {
321ad3f701SJonathan Cameron 	struct cxl_pmu *pmu;
331ad3f701SJonathan Cameron 	struct device *dev;
341ad3f701SJonathan Cameron 	int rc;
351ad3f701SJonathan Cameron 
361ad3f701SJonathan Cameron 	pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
371ad3f701SJonathan Cameron 	if (!pmu)
381ad3f701SJonathan Cameron 		return -ENOMEM;
391ad3f701SJonathan Cameron 
401ad3f701SJonathan Cameron 	pmu->assoc_id = assoc_id;
411ad3f701SJonathan Cameron 	pmu->index = index;
421ad3f701SJonathan Cameron 	pmu->type = type;
431ad3f701SJonathan Cameron 	pmu->base = regs->pmu;
441ad3f701SJonathan Cameron 	dev = &pmu->dev;
451ad3f701SJonathan Cameron 	device_initialize(dev);
461ad3f701SJonathan Cameron 	device_set_pm_not_required(dev);
471ad3f701SJonathan Cameron 	dev->parent = parent;
481ad3f701SJonathan Cameron 	dev->bus = &cxl_bus_type;
491ad3f701SJonathan Cameron 	dev->type = &cxl_pmu_type;
501ad3f701SJonathan Cameron 	switch (pmu->type) {
511ad3f701SJonathan Cameron 	case CXL_PMU_MEMDEV:
521ad3f701SJonathan Cameron 		rc = dev_set_name(dev, "pmu_mem%d.%d", assoc_id, index);
531ad3f701SJonathan Cameron 		break;
541ad3f701SJonathan Cameron 	}
551ad3f701SJonathan Cameron 	if (rc)
561ad3f701SJonathan Cameron 		goto err;
571ad3f701SJonathan Cameron 
581ad3f701SJonathan Cameron 	rc = device_add(dev);
591ad3f701SJonathan Cameron 	if (rc)
601ad3f701SJonathan Cameron 		goto err;
611ad3f701SJonathan Cameron 
621ad3f701SJonathan Cameron 	return devm_add_action_or_reset(parent, remove_dev, dev);
631ad3f701SJonathan Cameron 
641ad3f701SJonathan Cameron err:
651ad3f701SJonathan Cameron 	put_device(&pmu->dev);
661ad3f701SJonathan Cameron 	return rc;
671ad3f701SJonathan Cameron }
681ad3f701SJonathan Cameron EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL);
69