Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/bus/stm32_firewall.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
4
*/
5
6
#include <linux/bitfield.h>
7
#include <linux/bits.h>
8
#include <linux/bus/stm32_firewall_device.h>
9
#include <linux/device.h>
10
#include <linux/err.h>
11
#include <linux/init.h>
12
#include <linux/io.h>
13
#include <linux/kernel.h>
14
#include <linux/module.h>
15
#include <linux/of.h>
16
#include <linux/of_platform.h>
17
#include <linux/platform_device.h>
18
#include <linux/types.h>
19
#include <linux/slab.h>
20
21
#include "stm32_firewall.h"
22
23
/* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
24
#define STM32_FIREWALL_MAX_ARGS (STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
25
26
static LIST_HEAD(firewall_controller_list);
27
static DEFINE_MUTEX(firewall_controller_list_lock);
28
29
/* Firewall device API */
30
31
int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall,
32
unsigned int nb_firewall)
33
{
34
struct stm32_firewall_controller *ctrl;
35
struct of_phandle_iterator it;
36
unsigned int i, j = 0;
37
int err;
38
39
if (!firewall || !nb_firewall)
40
return -EINVAL;
41
42
/* Parse property with phandle parsed out */
43
of_for_each_phandle(&it, err, np, "access-controllers", "#access-controller-cells", 0) {
44
struct of_phandle_args provider_args;
45
struct device_node *provider = it.node;
46
const char *fw_entry;
47
bool match = false;
48
49
if (err) {
50
pr_err("Unable to get access-controllers property for node %s\n, err: %d",
51
np->full_name, err);
52
of_node_put(provider);
53
return err;
54
}
55
56
if (j >= nb_firewall) {
57
pr_err("Too many firewall controllers");
58
of_node_put(provider);
59
return -EINVAL;
60
}
61
62
provider_args.args_count = of_phandle_iterator_args(&it, provider_args.args,
63
STM32_FIREWALL_MAX_ARGS);
64
65
/* Check if the parsed phandle corresponds to a registered firewall controller */
66
mutex_lock(&firewall_controller_list_lock);
67
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
68
if (ctrl->dev->of_node->phandle == it.phandle) {
69
match = true;
70
firewall[j].firewall_ctrl = ctrl;
71
break;
72
}
73
}
74
mutex_unlock(&firewall_controller_list_lock);
75
76
if (!match) {
77
firewall[j].firewall_ctrl = NULL;
78
pr_err("No firewall controller registered for %s\n", np->full_name);
79
of_node_put(provider);
80
return -ENODEV;
81
}
82
83
err = of_property_read_string_index(np, "access-controller-names", j, &fw_entry);
84
if (err == 0)
85
firewall[j].entry = fw_entry;
86
87
/* Handle the case when there are no arguments given along with the phandle */
88
if (provider_args.args_count < 0 ||
89
provider_args.args_count > STM32_FIREWALL_MAX_ARGS) {
90
of_node_put(provider);
91
return -EINVAL;
92
} else if (provider_args.args_count == 0) {
93
firewall[j].extra_args_size = 0;
94
firewall[j].firewall_id = U32_MAX;
95
j++;
96
continue;
97
}
98
99
/* The firewall ID is always the first argument */
100
firewall[j].firewall_id = provider_args.args[0];
101
102
/* Extra args start at the second argument */
103
for (i = 0; i < provider_args.args_count - 1; i++)
104
firewall[j].extra_args[i] = provider_args.args[i + 1];
105
106
/* Remove the firewall ID arg that is not an extra argument */
107
firewall[j].extra_args_size = provider_args.args_count - 1;
108
109
j++;
110
}
111
112
return 0;
113
}
114
EXPORT_SYMBOL_GPL(stm32_firewall_get_firewall);
115
116
int stm32_firewall_grant_access(struct stm32_firewall *firewall)
117
{
118
struct stm32_firewall_controller *firewall_controller;
119
120
if (!firewall || firewall->firewall_id == U32_MAX)
121
return -EINVAL;
122
123
firewall_controller = firewall->firewall_ctrl;
124
125
if (!firewall_controller)
126
return -ENODEV;
127
128
return firewall_controller->grant_access(firewall_controller, firewall->firewall_id);
129
}
130
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access);
131
132
int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
133
{
134
struct stm32_firewall_controller *firewall_controller;
135
136
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX)
137
return -EINVAL;
138
139
firewall_controller = firewall->firewall_ctrl;
140
141
if (!firewall_controller)
142
return -ENODEV;
143
144
return firewall_controller->grant_access(firewall_controller, subsystem_id);
145
}
146
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access_by_id);
147
148
void stm32_firewall_release_access(struct stm32_firewall *firewall)
149
{
150
struct stm32_firewall_controller *firewall_controller;
151
152
if (!firewall || firewall->firewall_id == U32_MAX) {
153
pr_debug("Incorrect arguments when releasing a firewall access\n");
154
return;
155
}
156
157
firewall_controller = firewall->firewall_ctrl;
158
159
if (!firewall_controller) {
160
pr_debug("No firewall controller to release\n");
161
return;
162
}
163
164
firewall_controller->release_access(firewall_controller, firewall->firewall_id);
165
}
166
EXPORT_SYMBOL_GPL(stm32_firewall_release_access);
167
168
void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
169
{
170
struct stm32_firewall_controller *firewall_controller;
171
172
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX) {
173
pr_debug("Incorrect arguments when releasing a firewall access");
174
return;
175
}
176
177
firewall_controller = firewall->firewall_ctrl;
178
179
if (!firewall_controller) {
180
pr_debug("No firewall controller to release");
181
return;
182
}
183
184
firewall_controller->release_access(firewall_controller, subsystem_id);
185
}
186
EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);
187
188
/* Firewall controller API */
189
190
int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)
191
{
192
struct stm32_firewall_controller *ctrl;
193
194
if (!firewall_controller)
195
return -ENODEV;
196
197
pr_info("Registering %s firewall controller\n", firewall_controller->name);
198
199
mutex_lock(&firewall_controller_list_lock);
200
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
201
if (ctrl == firewall_controller) {
202
pr_debug("%s firewall controller already registered\n",
203
firewall_controller->name);
204
mutex_unlock(&firewall_controller_list_lock);
205
return 0;
206
}
207
}
208
list_add_tail(&firewall_controller->entry, &firewall_controller_list);
209
mutex_unlock(&firewall_controller_list_lock);
210
211
return 0;
212
}
213
EXPORT_SYMBOL_GPL(stm32_firewall_controller_register);
214
215
void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller)
216
{
217
struct stm32_firewall_controller *ctrl;
218
bool controller_removed = false;
219
220
if (!firewall_controller) {
221
pr_debug("Null reference while unregistering firewall controller\n");
222
return;
223
}
224
225
mutex_lock(&firewall_controller_list_lock);
226
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
227
if (ctrl == firewall_controller) {
228
controller_removed = true;
229
list_del_init(&ctrl->entry);
230
break;
231
}
232
}
233
mutex_unlock(&firewall_controller_list_lock);
234
235
if (!controller_removed)
236
pr_debug("There was no firewall controller named %s to unregister\n",
237
firewall_controller->name);
238
}
239
EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);
240
241
int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)
242
{
243
struct stm32_firewall *firewalls;
244
struct device_node *child;
245
struct device *parent;
246
unsigned int i;
247
int len;
248
int err;
249
250
parent = firewall_controller->dev;
251
252
dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));
253
254
for_each_available_child_of_node(dev_of_node(parent), child) {
255
/* The access-controllers property is mandatory for firewall bus devices */
256
len = of_count_phandle_with_args(child, "access-controllers",
257
"#access-controller-cells");
258
if (len <= 0) {
259
of_node_put(child);
260
return -EINVAL;
261
}
262
263
firewalls = kcalloc(len, sizeof(*firewalls), GFP_KERNEL);
264
if (!firewalls) {
265
of_node_put(child);
266
return -ENOMEM;
267
}
268
269
err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);
270
if (err) {
271
kfree(firewalls);
272
of_node_put(child);
273
return err;
274
}
275
276
for (i = 0; i < len; i++) {
277
if (firewall_controller->grant_access(firewall_controller,
278
firewalls[i].firewall_id)) {
279
/*
280
* Peripheral access not allowed or not defined.
281
* Mark the node as populated so platform bus won't probe it
282
*/
283
of_detach_node(child);
284
dev_err(parent, "%s: Device driver will not be probed\n",
285
child->full_name);
286
}
287
}
288
289
kfree(firewalls);
290
}
291
292
return 0;
293
}
294
EXPORT_SYMBOL_GPL(stm32_firewall_populate_bus);
295
296