-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsbl_module.c
372 lines (319 loc) · 9.99 KB
/
sbl_module.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2019-2024 Hewlett Packard Enterprise Development LP */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include "sbl_kconfig.h"
#include "sbl.h"
#include <linux/of.h>
#include "sbl_internal.h"
#include "sbl_serdes_map.h"
#define DEVICE_NAME "sbl"
static struct class *sbl_cls;
static struct device *sbl_dev;
static dev_t sbl_devt;
struct sbl_switch_info *sbl_switch_info;
#define tostr(x) #x
#define version_str(a, b, c) tostr(a.b.c)
#define SBL_VERSION_STR version_str(SBL_VERSION_MAJOR, \
SBL_VERSION_MINOR, \
SBL_VERSION_INC)
static int update_sbl_ports_info_from_dt(struct device_node *starting_node,
struct sbl_switch_info *sbl_ports_info)
{
struct device_node *port, *lane;
int val, ret, port_index, lane_index;
char port_buffer[10], lane_buffer[10];
if (!starting_node || !sbl_ports_info) {
pr_err("%s : starting_node is %s sbl_ports_info is %s\n", module_name(THIS_MODULE),
starting_node ? "Non Null" : "Null",
sbl_ports_info ? "Non Null" : "Null");
goto out;
}
ret = of_property_read_u32(starting_node, "num_ports", &val);
if (!ret) {
sbl_ports_info->num_ports = val;
} else {
pr_err("%s : Unable to get num_ports\n", module_name(THIS_MODULE));
goto out;
}
ret = of_property_read_u32(starting_node, "num_serdes", &val);
if (!ret) {
sbl_ports_info->num_serdes = val;
} else {
pr_err("%s : Unable to get num_serdes\n", module_name(THIS_MODULE));
goto out;
}
ret = of_property_read_u32(starting_node, "num_sbus_rings", &val);
if (!ret) {
sbl_ports_info->num_sbus_rings = val;
} else {
pr_err("%s : Unable to get num_sbus_rings\n", module_name(THIS_MODULE));
goto out;
}
for (port_index = 0; port_index < sbl_ports_info->num_ports; port_index++) {
snprintf(port_buffer, 10, "port%d", port_index);
port = of_find_node_by_name(starting_node, port_buffer);
if (port) {
ret = of_property_read_u32(port, "rx_an_swizzle", &val);
if (!ret) {
sbl_ports_info->ports[port_index].rx_an_swizzle = val;
} else {
pr_err("%s : Unable to get port%d rx_an_swizzle\n", module_name(THIS_MODULE), port_index);
goto out_1;
}
ret = of_property_read_u32(port, "tx_an_swizzle", &val);
if (!ret) {
sbl_ports_info->ports[port_index].tx_an_swizzle = val;
} else {
pr_err("%s : Unable to get port%d tx_an_swizzle\n", module_name(THIS_MODULE), port_index);
goto out_1;
}
for (lane_index = 0; lane_index < sbl_ports_info->num_serdes; lane_index++) {
snprintf(lane_buffer, 10, "lane%d", lane_index);
lane = of_find_node_by_name(port, lane_buffer);
if (lane) {
ret = of_property_read_u32(lane, "device", &val);
if (!ret) {
sbl_ports_info->ports[port_index].serdes[lane_index].device = val;
} else {
pr_err("%s : Unable to get port%d lane%d device\n", module_name(THIS_MODULE),
port_index, lane_index);
goto out_2;
}
ret = of_property_read_u32(lane, "sbus_ring", &val);
if (!ret) {
sbl_ports_info->ports[port_index].serdes[lane_index].sbus_ring = val;
} else {
pr_err("%s : Unable to get port%d lane%d sbus_ring\n",
module_name(THIS_MODULE), port_index, lane_index);
goto out_2;
}
ret = of_property_read_u32(lane, "rx_addr", &val);
if (!ret) {
sbl_ports_info->ports[port_index].serdes[lane_index].rx_addr = val;
} else {
pr_err("%s : Unable to get port%d lane%d rx_addr\n",
module_name(THIS_MODULE), port_index, lane_index);
goto out_2;
}
ret = of_property_read_u32(lane, "tx_lane_source", &val);
if (!ret) {
sbl_ports_info->ports[port_index].serdes[lane_index].tx_lane_source = val;
} else {
pr_err("%s : Unable to get port%d lane%d tx_lane_source\n",
module_name(THIS_MODULE), port_index, lane_index);
goto out_2;
}
ret = of_property_read_u32(lane, "rx_lane_source", &val);
if (!ret) {
sbl_ports_info->ports[port_index].serdes[lane_index].rx_lane_source = val;
} else {
pr_err("%s : Unable to get port%d lane%d rx_lane_source\n",
module_name(THIS_MODULE), port_index, lane_index);
goto out_2;
}
ret = of_property_read_bool(lane, "txinv");
sbl_ports_info->ports[port_index].serdes[lane_index].txinv = ret;
ret = of_property_read_bool(lane, "rxinv");
sbl_ports_info->ports[port_index].serdes[lane_index].rxinv = ret;
of_node_put(lane);
} else {
pr_err("%s : Unable to get port%d lane%d by of_find_node_by_name\n",
module_name(THIS_MODULE), port_index, lane_index);
goto out_1;
}
}
of_node_put(port);
} else {
pr_err("%s : Unable to get port%d by of_find_node_by_name\n",
module_name(THIS_MODULE), port_index);
goto out;
}
}
return 0;
out_2:
of_node_put(lane);
out_1:
of_node_put(port);
out:
return -1;
}
static int update_sbl_switch_info_from_dt(void)
{
struct device_node *switch_node, *node;
int val, switch_index;
int ret, num_of_rosetta;
char switch_buffer[20];
struct sbl_switch_info *rosetta_switch_info = NULL;
node = of_find_node_by_name(NULL, "rosettas");
if (node) {
ret = of_property_read_u32(node, "num_rosetta", &val);
if (!ret) {
num_of_rosetta = val;
} else {
pr_err("%s : Unable to get num_of_rosetta\n", module_name(THIS_MODULE));
goto out_1;
}
} else {
pr_debug("%s : Not a switch node\n", module_name(THIS_MODULE));
goto out;
}
rosetta_switch_info = kzalloc(num_of_rosetta * sizeof(struct sbl_switch_info), GFP_KERNEL);
if (!rosetta_switch_info)
goto out_1;
for (switch_index = 0; switch_index < num_of_rosetta; switch_index++) {
snprintf(switch_buffer, 20, "rosetta%d", switch_index);
switch_node = of_find_node_by_name(node, switch_buffer);
if (switch_node) {
ret = update_sbl_ports_info_from_dt(switch_node, &rosetta_switch_info[switch_index]);
if (ret) {
/* Error already logged */
goto out_2;
}
of_node_put(switch_node);
} else {
pr_err("%s : Unable to get switch node by of_find_node_by_name\n",
module_name(THIS_MODULE));
goto out_1;
}
}
of_node_put(node);
sbl_switch_info = rosetta_switch_info;
return 0;
out_2:
of_node_put(switch_node);
out_1:
of_node_put(node);
out:
kfree(rosetta_switch_info);
rosetta_switch_info = NULL;
return -1;
}
/*
* module init function
*
* The char device is only used for fw loading and printing to the console
* For now multiple instances all share the same device
*/
//#define __init
static int __init sbl_init(void)
{
int err;
pr_info("%s : v" SBL_VERSION_STR " loading (" CONFIG_SBL_BUILD_NAME " build)\n", module_name(THIS_MODULE));
/*
* create a device
*/
err = alloc_chrdev_region(&sbl_devt, 0, 1, DEVICE_NAME);
if (err) {
pr_err("%s : failed to get dev region [%d]\n",
module_name(THIS_MODULE), err);
goto out;
}
#if (defined(RHEL_MAJOR) && (RHEL_MAJOR >= 9) && defined(RHEL_MINOR) && (RHEL_MINOR >= 4)) || (KERNEL_VERSION(6, 4, 0) <= LINUX_VERSION_CODE)
sbl_cls = class_create(DEVICE_NAME);
#else
sbl_cls = class_create(THIS_MODULE, DEVICE_NAME);
#endif
if (IS_ERR(sbl_cls)) {
pr_err("%s : class create failed [%ld]\n",
module_name(THIS_MODULE), PTR_ERR(sbl_cls));
err = PTR_ERR(sbl_cls);
goto out_region;
}
sbl_dev = device_create(sbl_cls, NULL, sbl_devt, NULL,
module_name(THIS_MODULE));
if (IS_ERR(sbl_dev)) {
err = PTR_ERR(sbl_dev);
pr_err("%s : failed to add dev [%d]\n",
module_name(THIS_MODULE), err);
goto out_class;
}
update_sbl_switch_info_from_dt();
return 0;
out_class:
class_destroy(sbl_cls);
out_region:
unregister_chrdev_region(sbl_devt, 1);
out:
return err;
}
module_init(sbl_init);
struct device *sbl_get_device(void)
{
return sbl_dev;
}
struct sbl_switch_info *sbl_get_switch_info(int *size)
{
if (size != NULL) {
if (sbl_switch_info != NULL)
*size = sizeof(struct sbl_switch_info);
else
*size = 0;
}
return sbl_switch_info;
}
EXPORT_SYMBOL(sbl_get_switch_info);
/*
* module exit function
*/
//#define __exit
static void __exit sbl_exit(void)
{
pr_info("%s : module unloading\n", module_name(THIS_MODULE));
device_destroy(sbl_cls, sbl_devt);
class_destroy(sbl_cls);
unregister_chrdev_region(sbl_devt, 1);
}
module_exit(sbl_exit);
static int llr_cap_set(const char *val, const struct kernel_param *kp)
{
int err;
unsigned long data;
err = kstrtoul(val, 0, &data);
if (err || (data > 0x800))
return -EINVAL;
return param_set_ulong(val, kp);
}
static const struct kernel_param_ops llr_cap_ops = {
.set = llr_cap_set,
.get = param_get_ulong,
};
static unsigned long llr_edge_cap_data_max = 0x320;
module_param_cb(llr_edge_cap_data_max, &llr_cap_ops, &llr_edge_cap_data_max, 0664);
MODULE_PARM_DESC(llr_edge_cap_data_max, "LLR data capacity max for edge link");
u64 sbl_llr_edge_cap_data_max_get(void)
{
return llr_edge_cap_data_max;
}
static unsigned long llr_edge_cap_seq_max = 0x160;
module_param_cb(llr_edge_cap_seq_max, &llr_cap_ops, &llr_edge_cap_seq_max, 0664);
MODULE_PARM_DESC(llr_edge_cap_seq_max, "LLR sequence num capacity max for edge link");
u64 sbl_llr_edge_cap_seq_max_get(void)
{
return llr_edge_cap_seq_max;
}
#if defined(CONFIG_SBL_PLATFORM_ROS_HW)
static unsigned long llr_fabric_cap_data_max = 0x800; /* HW reset value */
module_param_cb(llr_fabric_cap_data_max, &llr_cap_ops, &llr_fabric_cap_data_max, 0664);
MODULE_PARM_DESC(llr_fabric_cap_data_max, "LLR data capacity max for fabric link");
u64 sbl_llr_fabric_cap_data_max_get(void)
{
return llr_fabric_cap_data_max;
}
static unsigned long llr_fabric_cap_seq_max = 0x800; /* HW reset value */
module_param_cb(llr_fabric_cap_seq_max, &llr_cap_ops, &llr_fabric_cap_seq_max, 0664);
MODULE_PARM_DESC(llr_fabric_cap_seq_max, "LLR sequence num capacity max for fabric link");
u64 sbl_llr_fabric_cap_seq_max_get(void)
{
return llr_fabric_cap_seq_max;
}
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HPE Slingshot <support@hpe.com>");
MODULE_DESCRIPTION("Slingshot Base Link module");
MODULE_VERSION(SBL_VERSION_STR);