xref: /linux/drivers/resctrl/mpam_devices.c (revision f04046f2577a5c76167333ca99d3903ee5331ba0)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2025 Arm Ltd.
3 
4 #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
5 
6 #include <linux/acpi.h>
7 #include <linux/arm_mpam.h>
8 #include <linux/cacheinfo.h>
9 #include <linux/cpumask.h>
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/gfp.h>
13 #include <linux/list.h>
14 #include <linux/lockdep.h>
15 #include <linux/mutex.h>
16 #include <linux/platform_device.h>
17 #include <linux/printk.h>
18 #include <linux/srcu.h>
19 #include <linux/types.h>
20 
21 #include "mpam_internal.h"
22 
23 /*
24  * mpam_list_lock protects the SRCU lists when writing. Once the
25  * mpam_enabled key is enabled these lists are read-only,
26  * unless the error interrupt disables the driver.
27  */
28 static DEFINE_MUTEX(mpam_list_lock);
29 static LIST_HEAD(mpam_all_msc);
30 
31 struct srcu_struct mpam_srcu;
32 
33 /*
34  * Number of MSCs that have been probed. Once all MSCs have been probed MPAM
35  * can be enabled.
36  */
37 static atomic_t mpam_num_msc;
38 
39 /*
40  * An MSC can control traffic from a set of CPUs, but may only be accessible
41  * from a (hopefully wider) set of CPUs. The common reason for this is power
42  * management. If all the CPUs in a cluster are in PSCI:CPU_SUSPEND, the
43  * corresponding cache may also be powered off. By making accesses from
44  * one of those CPUs, we ensure we don't access a cache that's powered off.
45  */
46 static void update_msc_accessibility(struct mpam_msc *msc)
47 {
48 	u32 affinity_id;
49 	int err;
50 
51 	err = device_property_read_u32(&msc->pdev->dev, "cpu_affinity",
52 				       &affinity_id);
53 	if (err)
54 		cpumask_copy(&msc->accessibility, cpu_possible_mask);
55 	else
56 		acpi_pptt_get_cpus_from_container(affinity_id, &msc->accessibility);
57 }
58 
59 static void mpam_msc_destroy(struct mpam_msc *msc)
60 {
61 	struct platform_device *pdev = msc->pdev;
62 
63 	lockdep_assert_held(&mpam_list_lock);
64 
65 	list_del_rcu(&msc->all_msc_list);
66 	platform_set_drvdata(pdev, NULL);
67 }
68 
69 static void mpam_msc_drv_remove(struct platform_device *pdev)
70 {
71 	struct mpam_msc *msc = platform_get_drvdata(pdev);
72 
73 	mutex_lock(&mpam_list_lock);
74 	mpam_msc_destroy(msc);
75 	mutex_unlock(&mpam_list_lock);
76 
77 	synchronize_srcu(&mpam_srcu);
78 }
79 
80 static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
81 {
82 	int err;
83 	u32 tmp;
84 	struct mpam_msc *msc;
85 	struct resource *msc_res;
86 	struct device *dev = &pdev->dev;
87 
88 	lockdep_assert_held(&mpam_list_lock);
89 
90 	msc = devm_kzalloc(&pdev->dev, sizeof(*msc), GFP_KERNEL);
91 	if (!msc)
92 		return ERR_PTR(-ENOMEM);
93 
94 	err = devm_mutex_init(dev, &msc->probe_lock);
95 	if (err)
96 		return ERR_PTR(err);
97 
98 	err = devm_mutex_init(dev, &msc->part_sel_lock);
99 	if (err)
100 		return ERR_PTR(err);
101 
102 	msc->id = pdev->id;
103 	msc->pdev = pdev;
104 	INIT_LIST_HEAD_RCU(&msc->all_msc_list);
105 	INIT_LIST_HEAD_RCU(&msc->ris);
106 
107 	update_msc_accessibility(msc);
108 	if (cpumask_empty(&msc->accessibility)) {
109 		dev_err_once(dev, "MSC is not accessible from any CPU!");
110 		return ERR_PTR(-EINVAL);
111 	}
112 
113 	if (device_property_read_u32(&pdev->dev, "pcc-channel", &tmp))
114 		msc->iface = MPAM_IFACE_MMIO;
115 	else
116 		msc->iface = MPAM_IFACE_PCC;
117 
118 	if (msc->iface == MPAM_IFACE_MMIO) {
119 		void __iomem *io;
120 
121 		io = devm_platform_get_and_ioremap_resource(pdev, 0,
122 							    &msc_res);
123 		if (IS_ERR(io)) {
124 			dev_err_once(dev, "Failed to map MSC base address\n");
125 			return ERR_CAST(io);
126 		}
127 		msc->mapped_hwpage_sz = msc_res->end - msc_res->start;
128 		msc->mapped_hwpage = io;
129 	} else {
130 		return ERR_PTR(-EINVAL);
131 	}
132 
133 	list_add_rcu(&msc->all_msc_list, &mpam_all_msc);
134 	platform_set_drvdata(pdev, msc);
135 
136 	return msc;
137 }
138 
139 static int fw_num_msc;
140 
141 static int mpam_msc_drv_probe(struct platform_device *pdev)
142 {
143 	int err;
144 	struct mpam_msc *msc = NULL;
145 	void *plat_data = pdev->dev.platform_data;
146 
147 	mutex_lock(&mpam_list_lock);
148 	msc = do_mpam_msc_drv_probe(pdev);
149 	mutex_unlock(&mpam_list_lock);
150 
151 	if (IS_ERR(msc))
152 		return PTR_ERR(msc);
153 
154 	/* Create RIS entries described by firmware */
155 	err = acpi_mpam_parse_resources(msc, plat_data);
156 	if (err) {
157 		mpam_msc_drv_remove(pdev);
158 		return err;
159 	}
160 
161 	if (atomic_add_return(1, &mpam_num_msc) == fw_num_msc)
162 		pr_info("Discovered all MSCs\n");
163 
164 	return 0;
165 }
166 
167 static struct platform_driver mpam_msc_driver = {
168 	.driver = {
169 		.name = "mpam_msc",
170 	},
171 	.probe = mpam_msc_drv_probe,
172 	.remove = mpam_msc_drv_remove,
173 };
174 
175 static int __init mpam_msc_driver_init(void)
176 {
177 	if (!system_supports_mpam())
178 		return -EOPNOTSUPP;
179 
180 	init_srcu_struct(&mpam_srcu);
181 
182 	fw_num_msc = acpi_mpam_count_msc();
183 	if (fw_num_msc <= 0) {
184 		pr_err("No MSC devices found in firmware\n");
185 		return -EINVAL;
186 	}
187 
188 	return platform_driver_register(&mpam_msc_driver);
189 }
190 subsys_initcall(mpam_msc_driver_init);
191