xref: /linux/drivers/cxl/core/pmu.c (revision 76f623d2d4283cc36a9c8a5b585df74638f1efa5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2023 Huawei. All rights reserved. */
3 
4 #include <linux/device.h>
5 #include <linux/slab.h>
6 #include <linux/idr.h>
7 #include <cxlmem.h>
8 #include <pmu.h>
9 #include <cxl.h>
10 #include "core.h"
11 
12 static void cxl_pmu_release(struct device *dev)
13 {
14 	struct cxl_pmu *pmu = to_cxl_pmu(dev);
15 
16 	kfree(pmu);
17 }
18 
19 const struct device_type cxl_pmu_type = {
20 	.name = "cxl_pmu",
21 	.release = cxl_pmu_release,
22 };
23 
24 static void remove_dev(void *dev)
25 {
26 	device_unregister(dev);
27 }
28 
29 int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,
30 		     int assoc_id, int index, enum cxl_pmu_type type)
31 {
32 	struct cxl_pmu *pmu;
33 	struct device *dev;
34 	int rc;
35 
36 	pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
37 	if (!pmu)
38 		return -ENOMEM;
39 
40 	pmu->assoc_id = assoc_id;
41 	pmu->index = index;
42 	pmu->type = type;
43 	pmu->base = regs->pmu;
44 	dev = &pmu->dev;
45 	device_initialize(dev);
46 	device_set_pm_not_required(dev);
47 	dev->parent = parent;
48 	dev->bus = &cxl_bus_type;
49 	dev->type = &cxl_pmu_type;
50 	switch (pmu->type) {
51 	case CXL_PMU_MEMDEV:
52 		rc = dev_set_name(dev, "pmu_mem%d.%d", assoc_id, index);
53 		break;
54 	}
55 	if (rc)
56 		goto err;
57 
58 	rc = device_add(dev);
59 	if (rc)
60 		goto err;
61 
62 	return devm_add_action_or_reset(parent, remove_dev, dev);
63 
64 err:
65 	put_device(&pmu->dev);
66 	return rc;
67 }
68 EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL);
69