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#include <linux/bitfield.h>
40#include <linux/ethtool.h>
41#include <linux/if_ether.h>
42#include <linux/kernel.h>
43#include <linux/module.h>
44
45#include "nfp.h"
46#include "nfp_nsp.h"
47#include "nfp6000/nfp6000.h"
48
49#define NSP_ETH_NBI_PORT_COUNT 24
50#define NSP_ETH_MAX_COUNT (2 * NSP_ETH_NBI_PORT_COUNT)
51#define NSP_ETH_TABLE_SIZE (NSP_ETH_MAX_COUNT * \
52 sizeof(union eth_table_entry))
53
54#define NSP_ETH_PORT_LANES GENMASK_ULL(3, 0)
55#define NSP_ETH_PORT_INDEX GENMASK_ULL(15, 8)
56#define NSP_ETH_PORT_LABEL GENMASK_ULL(53, 48)
57#define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54)
58
59#define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES)
60
61#define NSP_ETH_STATE_CONFIGURED BIT_ULL(0)
62#define NSP_ETH_STATE_ENABLED BIT_ULL(1)
63#define NSP_ETH_STATE_TX_ENABLED BIT_ULL(2)
64#define NSP_ETH_STATE_RX_ENABLED BIT_ULL(3)
65#define NSP_ETH_STATE_RATE GENMASK_ULL(11, 8)
66#define NSP_ETH_STATE_INTERFACE GENMASK_ULL(19, 12)
67#define NSP_ETH_STATE_MEDIA GENMASK_ULL(21, 20)
68#define NSP_ETH_STATE_OVRD_CHNG BIT_ULL(22)
69#define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23)
70
71#define NSP_ETH_CTRL_CONFIGURED BIT_ULL(0)
72#define NSP_ETH_CTRL_ENABLED BIT_ULL(1)
73#define NSP_ETH_CTRL_TX_ENABLED BIT_ULL(2)
74#define NSP_ETH_CTRL_RX_ENABLED BIT_ULL(3)
75#define NSP_ETH_CTRL_SET_RATE BIT_ULL(4)
76#define NSP_ETH_CTRL_SET_LANES BIT_ULL(5)
77#define NSP_ETH_CTRL_SET_ANEG BIT_ULL(6)
78
79enum nfp_eth_raw {
80 NSP_ETH_RAW_PORT = 0,
81 NSP_ETH_RAW_STATE,
82 NSP_ETH_RAW_MAC,
83 NSP_ETH_RAW_CONTROL,
84
85 NSP_ETH_NUM_RAW
86};
87
88enum nfp_eth_rate {
89 RATE_INVALID = 0,
90 RATE_10M,
91 RATE_100M,
92 RATE_1G,
93 RATE_10G,
94 RATE_25G,
95};
96
97union eth_table_entry {
98 struct {
99 __le64 port;
100 __le64 state;
101 u8 mac_addr[6];
102 u8 resv[2];
103 __le64 control;
104 };
105 __le64 raw[NSP_ETH_NUM_RAW];
106};
107
108static const struct {
109 enum nfp_eth_rate rate;
110 unsigned int speed;
111} nsp_eth_rate_tbl[] = {
112 { RATE_INVALID, 0, },
113 { RATE_10M, SPEED_10, },
114 { RATE_100M, SPEED_100, },
115 { RATE_1G, SPEED_1000, },
116 { RATE_10G, SPEED_10000, },
117 { RATE_25G, SPEED_25000, },
118};
119
120static unsigned int nfp_eth_rate2speed(enum nfp_eth_rate rate)
121{
122 int i;
123
124 for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
125 if (nsp_eth_rate_tbl[i].rate == rate)
126 return nsp_eth_rate_tbl[i].speed;
127
128 return 0;
129}
130
131static unsigned int nfp_eth_speed2rate(unsigned int speed)
132{
133 int i;
134
135 for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
136 if (nsp_eth_rate_tbl[i].speed == speed)
137 return nsp_eth_rate_tbl[i].rate;
138
139 return RATE_INVALID;
140}
141
142static void nfp_eth_copy_mac_reverse(u8 *dst, const u8 *src)
143{
144 int i;
145
146 for (i = 0; i < ETH_ALEN; i++)
147 dst[ETH_ALEN - i - 1] = src[i];
148}
149
150static void
151nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
152 unsigned int index, struct nfp_eth_table_port *dst)
153{
154 unsigned int rate;
155 u64 port, state;
156
157 port = le64_to_cpu(src->port);
158 state = le64_to_cpu(src->state);
159
160 dst->eth_index = FIELD_GET(NSP_ETH_PORT_INDEX, port);
161 dst->index = index;
162 dst->nbi = index / NSP_ETH_NBI_PORT_COUNT;
163 dst->base = index % NSP_ETH_NBI_PORT_COUNT;
164 dst->lanes = FIELD_GET(NSP_ETH_PORT_LANES, port);
165
166 dst->enabled = FIELD_GET(NSP_ETH_STATE_ENABLED, state);
167 dst->tx_enabled = FIELD_GET(NSP_ETH_STATE_TX_ENABLED, state);
168 dst->rx_enabled = FIELD_GET(NSP_ETH_STATE_RX_ENABLED, state);
169
170 rate = nfp_eth_rate2speed(FIELD_GET(NSP_ETH_STATE_RATE, state));
171 dst->speed = dst->lanes * rate;
172
173 dst->interface = FIELD_GET(NSP_ETH_STATE_INTERFACE, state);
174 dst->media = FIELD_GET(NSP_ETH_STATE_MEDIA, state);
175
176 nfp_eth_copy_mac_reverse(dst->mac_addr, src->mac_addr);
177
178 dst->label_port = FIELD_GET(NSP_ETH_PORT_PHYLABEL, port);
179 dst->label_subport = FIELD_GET(NSP_ETH_PORT_LABEL, port);
180
181 if (nfp_nsp_get_abi_ver_minor(nsp) < 17)
182 return;
183
184 dst->override_changed = FIELD_GET(NSP_ETH_STATE_OVRD_CHNG, state);
185 dst->aneg = FIELD_GET(NSP_ETH_STATE_ANEG, state);
186}
187
188static void
189nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table)
190{
191 unsigned int i, j;
192
193 for (i = 0; i < table->count; i++)
194 for (j = 0; j < table->count; j++) {
195 if (i == j)
196 continue;
197 if (table->ports[i].label_port !=
198 table->ports[j].label_port)
199 continue;
200 if (table->ports[i].label_subport ==
201 table->ports[j].label_subport)
202 nfp_warn(cpp,
203 "Port %d subport %d is a duplicate\n",
204 table->ports[i].label_port,
205 table->ports[i].label_subport);
206
207 table->ports[i].is_split = true;
208 break;
209 }
210}
211
212static void
213nfp_eth_calc_port_type(struct nfp_cpp *cpp, struct nfp_eth_table_port *entry)
214{
215 if (entry->interface == NFP_INTERFACE_NONE) {
216 entry->port_type = PORT_NONE;
217 return;
218 }
219
220 if (entry->media == NFP_MEDIA_FIBRE)
221 entry->port_type = PORT_FIBRE;
222 else
223 entry->port_type = PORT_DA;
224}
225
226
227
228
229
230
231
232
233
234
235struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp)
236{
237 struct nfp_eth_table *ret;
238 struct nfp_nsp *nsp;
239
240 nsp = nfp_nsp_open(cpp);
241 if (IS_ERR(nsp))
242 return NULL;
243
244 ret = __nfp_eth_read_ports(cpp, nsp);
245 nfp_nsp_close(nsp);
246
247 return ret;
248}
249
250struct nfp_eth_table *
251__nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp)
252{
253 union eth_table_entry *entries;
254 struct nfp_eth_table *table;
255 int i, j, ret, cnt = 0;
256
257 entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
258 if (!entries)
259 return NULL;
260
261 ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
262 if (ret < 0) {
263 nfp_err(cpp, "reading port table failed %d\n", ret);
264 goto err;
265 }
266
267 for (i = 0; i < NSP_ETH_MAX_COUNT; i++)
268 if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
269 cnt++;
270
271
272
273
274
275 if (ret && ret != cnt) {
276 nfp_err(cpp, "table entry count reported (%d) does not match entries present (%d)\n",
277 ret, cnt);
278 goto err;
279 }
280
281 table = kzalloc(sizeof(*table) +
282 sizeof(struct nfp_eth_table_port) * cnt, GFP_KERNEL);
283 if (!table)
284 goto err;
285
286 table->count = cnt;
287 for (i = 0, j = 0; i < NSP_ETH_MAX_COUNT; i++)
288 if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
289 nfp_eth_port_translate(nsp, &entries[i], i,
290 &table->ports[j++]);
291
292 nfp_eth_mark_split_ports(cpp, table);
293 for (i = 0; i < table->count; i++)
294 nfp_eth_calc_port_type(cpp, &table->ports[i]);
295
296 kfree(entries);
297
298 return table;
299
300err:
301 kfree(entries);
302 return NULL;
303}
304
305struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx)
306{
307 union eth_table_entry *entries;
308 struct nfp_nsp *nsp;
309 int ret;
310
311 entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
312 if (!entries)
313 return ERR_PTR(-ENOMEM);
314
315 nsp = nfp_nsp_open(cpp);
316 if (IS_ERR(nsp)) {
317 kfree(entries);
318 return nsp;
319 }
320
321 ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
322 if (ret < 0) {
323 nfp_err(cpp, "reading port table failed %d\n", ret);
324 goto err;
325 }
326
327 if (!(entries[idx].port & NSP_ETH_PORT_LANES_MASK)) {
328 nfp_warn(cpp, "trying to set port state on disabled port %d\n",
329 idx);
330 goto err;
331 }
332
333 nfp_nsp_config_set_state(nsp, entries, idx);
334 return nsp;
335
336err:
337 nfp_nsp_close(nsp);
338 kfree(entries);
339 return ERR_PTR(-EIO);
340}
341
342void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp)
343{
344 union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
345
346 nfp_nsp_config_set_modified(nsp, false);
347 nfp_nsp_config_clear_state(nsp);
348 nfp_nsp_close(nsp);
349 kfree(entries);
350}
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366int nfp_eth_config_commit_end(struct nfp_nsp *nsp)
367{
368 union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
369 int ret = 1;
370
371 if (nfp_nsp_config_modified(nsp)) {
372 ret = nfp_nsp_write_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
373 ret = ret < 0 ? ret : 0;
374 }
375
376 nfp_eth_config_cleanup_end(nsp);
377
378 return ret;
379}
380
381
382
383
384
385
386
387
388
389
390
391
392int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
393{
394 union eth_table_entry *entries;
395 struct nfp_nsp *nsp;
396 u64 reg;
397
398 nsp = nfp_eth_config_start(cpp, idx);
399 if (IS_ERR(nsp))
400 return PTR_ERR(nsp);
401
402 entries = nfp_nsp_config_entries(nsp);
403
404
405 reg = le64_to_cpu(entries[idx].state);
406 if (enable != FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) {
407 reg = le64_to_cpu(entries[idx].control);
408 reg &= ~NSP_ETH_CTRL_ENABLED;
409 reg |= FIELD_PREP(NSP_ETH_CTRL_ENABLED, enable);
410 entries[idx].control = cpu_to_le64(reg);
411
412 nfp_nsp_config_set_modified(nsp, true);
413 }
414
415 return nfp_eth_config_commit_end(nsp);
416}
417
418
419
420
421
422
423
424
425
426
427
428int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
429{
430 union eth_table_entry *entries;
431 struct nfp_nsp *nsp;
432 u64 reg;
433
434 nsp = nfp_eth_config_start(cpp, idx);
435 if (IS_ERR(nsp))
436 return PTR_ERR(nsp);
437
438 entries = nfp_nsp_config_entries(nsp);
439
440
441 reg = le64_to_cpu(entries[idx].state);
442 if (configed != FIELD_GET(NSP_ETH_STATE_CONFIGURED, reg)) {
443 reg = le64_to_cpu(entries[idx].control);
444 reg &= ~NSP_ETH_CTRL_CONFIGURED;
445 reg |= FIELD_PREP(NSP_ETH_CTRL_CONFIGURED, configed);
446 entries[idx].control = cpu_to_le64(reg);
447
448 nfp_nsp_config_set_modified(nsp, true);
449 }
450
451 return nfp_eth_config_commit_end(nsp);
452}
453
454
455static __always_inline int
456nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
457 const u64 mask, unsigned int val, const u64 ctrl_bit)
458{
459 union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
460 unsigned int idx = nfp_nsp_config_idx(nsp);
461 u64 reg;
462
463
464
465
466 if (nfp_nsp_get_abi_ver_minor(nsp) < 17) {
467 nfp_err(nfp_nsp_cpp(nsp),
468 "set operations not supported, please update flash\n");
469 return -EOPNOTSUPP;
470 }
471
472
473 reg = le64_to_cpu(entries[idx].raw[raw_idx]);
474 if (val == FIELD_GET(mask, reg))
475 return 0;
476
477 reg &= ~mask;
478 reg |= FIELD_PREP(mask, val);
479 entries[idx].raw[raw_idx] = cpu_to_le64(reg);
480
481 entries[idx].control |= cpu_to_le64(ctrl_bit);
482
483 nfp_nsp_config_set_modified(nsp, true);
484
485 return 0;
486}
487
488
489
490
491
492
493
494
495
496
497
498int __nfp_eth_set_aneg(struct nfp_nsp *nsp, enum nfp_eth_aneg mode)
499{
500 return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_STATE,
501 NSP_ETH_STATE_ANEG, mode,
502 NSP_ETH_CTRL_SET_ANEG);
503}
504
505
506
507
508
509
510
511
512
513
514
515
516
517int __nfp_eth_set_speed(struct nfp_nsp *nsp, unsigned int speed)
518{
519 enum nfp_eth_rate rate;
520
521 rate = nfp_eth_speed2rate(speed);
522 if (rate == RATE_INVALID) {
523 nfp_warn(nfp_nsp_cpp(nsp),
524 "could not find matching lane rate for speed %u\n",
525 speed);
526 return -EINVAL;
527 }
528
529 return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_STATE,
530 NSP_ETH_STATE_RATE, rate,
531 NSP_ETH_CTRL_SET_RATE);
532}
533
534
535
536
537
538
539
540
541
542
543
544int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes)
545{
546 return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES,
547 lanes, NSP_ETH_CTRL_SET_LANES);
548}
549