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(objp: 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(size: 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, name: "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(dev: &pmu->dev); |
66 | return rc; |
67 | } |
68 | EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL); |
69 | |