1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
2 | /* Copyright (C) 2015-2017 Netronome Systems, Inc. */ |
3 | |
4 | /* Authors: David Brunecz <david.brunecz@netronome.com> |
5 | * Jakub Kicinski <jakub.kicinski@netronome.com> |
6 | * Jason Mcmullan <jason.mcmullan@netronome.com> |
7 | */ |
8 | |
9 | #include <linux/bitfield.h> |
10 | #include <linux/ethtool.h> |
11 | #include <linux/if_ether.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> |
14 | |
15 | #include "nfp.h" |
16 | #include "nfp_nsp.h" |
17 | #include "nfp6000/nfp6000.h" |
18 | |
19 | #define NSP_ETH_NBI_PORT_COUNT 24 |
20 | #define NSP_ETH_MAX_COUNT (2 * NSP_ETH_NBI_PORT_COUNT) |
21 | #define NSP_ETH_TABLE_SIZE (NSP_ETH_MAX_COUNT * \ |
22 | sizeof(union eth_table_entry)) |
23 | |
24 | #define NSP_ETH_PORT_LANES GENMASK_ULL(3, 0) |
25 | #define NSP_ETH_PORT_INDEX GENMASK_ULL(15, 8) |
26 | #define NSP_ETH_PORT_LABEL GENMASK_ULL(53, 48) |
27 | #define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54) |
28 | #define NSP_ETH_PORT_FEC_SUPP_BASER BIT_ULL(60) |
29 | #define NSP_ETH_PORT_FEC_SUPP_RS BIT_ULL(61) |
30 | #define NSP_ETH_PORT_SUPP_ANEG BIT_ULL(63) |
31 | |
32 | #define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES) |
33 | |
34 | #define NSP_ETH_STATE_CONFIGURED BIT_ULL(0) |
35 | #define NSP_ETH_STATE_ENABLED BIT_ULL(1) |
36 | #define NSP_ETH_STATE_TX_ENABLED BIT_ULL(2) |
37 | #define NSP_ETH_STATE_RX_ENABLED BIT_ULL(3) |
38 | #define NSP_ETH_STATE_RATE GENMASK_ULL(11, 8) |
39 | #define NSP_ETH_STATE_INTERFACE GENMASK_ULL(19, 12) |
40 | #define NSP_ETH_STATE_MEDIA GENMASK_ULL(21, 20) |
41 | #define NSP_ETH_STATE_OVRD_CHNG BIT_ULL(22) |
42 | #define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23) |
43 | #define NSP_ETH_STATE_FEC GENMASK_ULL(27, 26) |
44 | #define NSP_ETH_STATE_ACT_FEC GENMASK_ULL(29, 28) |
45 | #define NSP_ETH_STATE_TX_PAUSE BIT_ULL(31) |
46 | #define NSP_ETH_STATE_RX_PAUSE BIT_ULL(32) |
47 | |
48 | #define NSP_ETH_CTRL_CONFIGURED BIT_ULL(0) |
49 | #define NSP_ETH_CTRL_ENABLED BIT_ULL(1) |
50 | #define NSP_ETH_CTRL_TX_ENABLED BIT_ULL(2) |
51 | #define NSP_ETH_CTRL_RX_ENABLED BIT_ULL(3) |
52 | #define NSP_ETH_CTRL_SET_RATE BIT_ULL(4) |
53 | #define NSP_ETH_CTRL_SET_LANES BIT_ULL(5) |
54 | #define NSP_ETH_CTRL_SET_ANEG BIT_ULL(6) |
55 | #define NSP_ETH_CTRL_SET_FEC BIT_ULL(7) |
56 | #define NSP_ETH_CTRL_SET_IDMODE BIT_ULL(8) |
57 | #define NSP_ETH_CTRL_SET_TX_PAUSE BIT_ULL(10) |
58 | #define NSP_ETH_CTRL_SET_RX_PAUSE BIT_ULL(11) |
59 | |
60 | enum nfp_eth_raw { |
61 | NSP_ETH_RAW_PORT = 0, |
62 | NSP_ETH_RAW_STATE, |
63 | NSP_ETH_RAW_MAC, |
64 | NSP_ETH_RAW_CONTROL, |
65 | |
66 | NSP_ETH_NUM_RAW |
67 | }; |
68 | |
69 | enum nfp_eth_rate { |
70 | RATE_INVALID = 0, |
71 | RATE_10M, |
72 | RATE_100M, |
73 | RATE_1G, |
74 | RATE_10G, |
75 | RATE_25G, |
76 | }; |
77 | |
78 | union eth_table_entry { |
79 | struct { |
80 | __le64 port; |
81 | __le64 state; |
82 | u8 mac_addr[6]; |
83 | u8 resv[2]; |
84 | __le64 control; |
85 | }; |
86 | __le64 raw[NSP_ETH_NUM_RAW]; |
87 | }; |
88 | |
89 | static const struct { |
90 | enum nfp_eth_rate rate; |
91 | unsigned int speed; |
92 | } nsp_eth_rate_tbl[] = { |
93 | { RATE_INVALID, 0, }, |
94 | { RATE_10M, SPEED_10, }, |
95 | { RATE_100M, SPEED_100, }, |
96 | { RATE_1G, SPEED_1000, }, |
97 | { RATE_10G, SPEED_10000, }, |
98 | { RATE_25G, SPEED_25000, }, |
99 | }; |
100 | |
101 | static unsigned int nfp_eth_rate2speed(enum nfp_eth_rate rate) |
102 | { |
103 | int i; |
104 | |
105 | for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++) |
106 | if (nsp_eth_rate_tbl[i].rate == rate) |
107 | return nsp_eth_rate_tbl[i].speed; |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static unsigned int nfp_eth_speed2rate(unsigned int speed) |
113 | { |
114 | int i; |
115 | |
116 | for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++) |
117 | if (nsp_eth_rate_tbl[i].speed == speed) |
118 | return nsp_eth_rate_tbl[i].rate; |
119 | |
120 | return RATE_INVALID; |
121 | } |
122 | |
123 | static void nfp_eth_copy_mac_reverse(u8 *dst, const u8 *src) |
124 | { |
125 | int i; |
126 | |
127 | for (i = 0; i < ETH_ALEN; i++) |
128 | dst[ETH_ALEN - i - 1] = src[i]; |
129 | } |
130 | |
131 | static void |
132 | nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src, |
133 | unsigned int index, struct nfp_eth_table_port *dst) |
134 | { |
135 | unsigned int rate; |
136 | unsigned int fec; |
137 | u64 port, state; |
138 | |
139 | port = le64_to_cpu(src->port); |
140 | state = le64_to_cpu(src->state); |
141 | |
142 | dst->eth_index = FIELD_GET(NSP_ETH_PORT_INDEX, port); |
143 | dst->index = index; |
144 | dst->nbi = index / NSP_ETH_NBI_PORT_COUNT; |
145 | dst->base = index % NSP_ETH_NBI_PORT_COUNT; |
146 | dst->lanes = FIELD_GET(NSP_ETH_PORT_LANES, port); |
147 | |
148 | dst->enabled = FIELD_GET(NSP_ETH_STATE_ENABLED, state); |
149 | dst->tx_enabled = FIELD_GET(NSP_ETH_STATE_TX_ENABLED, state); |
150 | dst->rx_enabled = FIELD_GET(NSP_ETH_STATE_RX_ENABLED, state); |
151 | |
152 | rate = nfp_eth_rate2speed(FIELD_GET(NSP_ETH_STATE_RATE, state)); |
153 | dst->speed = dst->lanes * rate; |
154 | |
155 | dst->interface = FIELD_GET(NSP_ETH_STATE_INTERFACE, state); |
156 | dst->media = FIELD_GET(NSP_ETH_STATE_MEDIA, state); |
157 | |
158 | nfp_eth_copy_mac_reverse(dst: dst->mac_addr, src: src->mac_addr); |
159 | |
160 | dst->label_port = FIELD_GET(NSP_ETH_PORT_PHYLABEL, port); |
161 | dst->label_subport = FIELD_GET(NSP_ETH_PORT_LABEL, port); |
162 | |
163 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 17) |
164 | return; |
165 | |
166 | dst->override_changed = FIELD_GET(NSP_ETH_STATE_OVRD_CHNG, state); |
167 | dst->aneg = FIELD_GET(NSP_ETH_STATE_ANEG, state); |
168 | |
169 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 22) |
170 | return; |
171 | |
172 | fec = FIELD_GET(NSP_ETH_PORT_FEC_SUPP_BASER, port); |
173 | dst->fec_modes_supported |= fec << NFP_FEC_BASER_BIT; |
174 | fec = FIELD_GET(NSP_ETH_PORT_FEC_SUPP_RS, port); |
175 | dst->fec_modes_supported |= fec << NFP_FEC_REED_SOLOMON_BIT; |
176 | if (dst->fec_modes_supported) |
177 | dst->fec_modes_supported |= NFP_FEC_AUTO | NFP_FEC_DISABLED; |
178 | |
179 | dst->fec = FIELD_GET(NSP_ETH_STATE_FEC, state); |
180 | dst->act_fec = dst->fec; |
181 | |
182 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 33) |
183 | return; |
184 | |
185 | dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state); |
186 | dst->supp_aneg = FIELD_GET(NSP_ETH_PORT_SUPP_ANEG, port); |
187 | |
188 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 37) { |
189 | dst->tx_pause = true; |
190 | dst->rx_pause = true; |
191 | return; |
192 | } |
193 | |
194 | dst->tx_pause = FIELD_GET(NSP_ETH_STATE_TX_PAUSE, state); |
195 | dst->rx_pause = FIELD_GET(NSP_ETH_STATE_RX_PAUSE, state); |
196 | } |
197 | |
198 | static void |
199 | nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table) |
200 | { |
201 | unsigned int i, j; |
202 | |
203 | for (i = 0; i < table->count; i++) { |
204 | table->max_index = max(table->max_index, table->ports[i].index); |
205 | |
206 | for (j = 0; j < table->count; j++) { |
207 | if (table->ports[i].label_port != |
208 | table->ports[j].label_port) |
209 | continue; |
210 | table->ports[i].port_lanes += table->ports[j].lanes; |
211 | |
212 | if (i == j) |
213 | continue; |
214 | if (table->ports[i].label_subport == |
215 | table->ports[j].label_subport) |
216 | nfp_warn(cpp, |
217 | "Port %d subport %d is a duplicate\n" , |
218 | table->ports[i].label_port, |
219 | table->ports[i].label_subport); |
220 | |
221 | table->ports[i].is_split = true; |
222 | } |
223 | } |
224 | } |
225 | |
226 | static void |
227 | nfp_eth_calc_port_type(struct nfp_cpp *cpp, struct nfp_eth_table_port *entry) |
228 | { |
229 | if (entry->interface == NFP_INTERFACE_NONE) { |
230 | entry->port_type = PORT_NONE; |
231 | return; |
232 | } else if (entry->interface == NFP_INTERFACE_RJ45) { |
233 | entry->port_type = PORT_TP; |
234 | return; |
235 | } |
236 | |
237 | if (entry->media == NFP_MEDIA_FIBRE) |
238 | entry->port_type = PORT_FIBRE; |
239 | else |
240 | entry->port_type = PORT_DA; |
241 | } |
242 | |
243 | static void |
244 | nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_nsp *nsp, struct nfp_eth_table_port *entry) |
245 | { |
246 | struct nfp_eth_media_buf ethm = { |
247 | .eth_index = entry->eth_index, |
248 | }; |
249 | unsigned int i; |
250 | int ret; |
251 | |
252 | if (!nfp_nsp_has_read_media(state: nsp)) |
253 | return; |
254 | |
255 | ret = nfp_nsp_read_media(state: nsp, buf: ðm, size: sizeof(ethm)); |
256 | if (ret) { |
257 | nfp_err(cpp, "Reading media link modes failed: %d\n" , ret); |
258 | return; |
259 | } |
260 | |
261 | for (i = 0; i < 2; i++) { |
262 | entry->link_modes_supp[i] = le64_to_cpu(ethm.supported_modes[i]); |
263 | entry->link_modes_ad[i] = le64_to_cpu(ethm.advertised_modes[i]); |
264 | } |
265 | } |
266 | |
267 | /** |
268 | * nfp_eth_read_ports() - retrieve port information |
269 | * @cpp: NFP CPP handle |
270 | * |
271 | * Read the port information from the device. Returned structure should |
272 | * be freed with kfree() once no longer needed. |
273 | * |
274 | * Return: populated ETH table or NULL on error. |
275 | */ |
276 | struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp) |
277 | { |
278 | struct nfp_eth_table *ret; |
279 | struct nfp_nsp *nsp; |
280 | |
281 | nsp = nfp_nsp_open(cpp); |
282 | if (IS_ERR(ptr: nsp)) |
283 | return NULL; |
284 | |
285 | ret = __nfp_eth_read_ports(cpp, nsp); |
286 | nfp_nsp_close(state: nsp); |
287 | |
288 | return ret; |
289 | } |
290 | |
291 | struct nfp_eth_table * |
292 | __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp) |
293 | { |
294 | union eth_table_entry *entries; |
295 | struct nfp_eth_table *table; |
296 | int i, j, ret, cnt = 0; |
297 | |
298 | entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL); |
299 | if (!entries) |
300 | return NULL; |
301 | |
302 | ret = nfp_nsp_read_eth_table(state: nsp, buf: entries, NSP_ETH_TABLE_SIZE); |
303 | if (ret < 0) { |
304 | nfp_err(cpp, "reading port table failed %d\n" , ret); |
305 | goto err; |
306 | } |
307 | |
308 | for (i = 0; i < NSP_ETH_MAX_COUNT; i++) |
309 | if (entries[i].port & NSP_ETH_PORT_LANES_MASK) |
310 | cnt++; |
311 | |
312 | /* Some versions of flash will give us 0 instead of port count. |
313 | * For those that give a port count, verify it against the value |
314 | * calculated above. |
315 | */ |
316 | if (ret && ret != cnt) { |
317 | nfp_err(cpp, "table entry count reported (%d) does not match entries present (%d)\n" , |
318 | ret, cnt); |
319 | goto err; |
320 | } |
321 | |
322 | table = kzalloc(struct_size(table, ports, cnt), GFP_KERNEL); |
323 | if (!table) |
324 | goto err; |
325 | |
326 | table->count = cnt; |
327 | for (i = 0, j = 0; i < NSP_ETH_MAX_COUNT; i++) |
328 | if (entries[i].port & NSP_ETH_PORT_LANES_MASK) |
329 | nfp_eth_port_translate(nsp, src: &entries[i], index: i, |
330 | dst: &table->ports[j++]); |
331 | |
332 | nfp_eth_calc_port_geometry(cpp, table); |
333 | for (i = 0; i < table->count; i++) { |
334 | nfp_eth_calc_port_type(cpp, entry: &table->ports[i]); |
335 | nfp_eth_read_media(cpp, nsp, entry: &table->ports[i]); |
336 | } |
337 | |
338 | kfree(objp: entries); |
339 | |
340 | return table; |
341 | |
342 | err: |
343 | kfree(objp: entries); |
344 | return NULL; |
345 | } |
346 | |
347 | struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx) |
348 | { |
349 | union eth_table_entry *entries; |
350 | struct nfp_nsp *nsp; |
351 | int ret; |
352 | |
353 | entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL); |
354 | if (!entries) |
355 | return ERR_PTR(error: -ENOMEM); |
356 | |
357 | nsp = nfp_nsp_open(cpp); |
358 | if (IS_ERR(ptr: nsp)) { |
359 | kfree(objp: entries); |
360 | return nsp; |
361 | } |
362 | |
363 | ret = nfp_nsp_read_eth_table(state: nsp, buf: entries, NSP_ETH_TABLE_SIZE); |
364 | if (ret < 0) { |
365 | nfp_err(cpp, "reading port table failed %d\n" , ret); |
366 | goto err; |
367 | } |
368 | |
369 | if (!(entries[idx].port & NSP_ETH_PORT_LANES_MASK)) { |
370 | nfp_warn(cpp, "trying to set port state on disabled port %d\n" , |
371 | idx); |
372 | goto err; |
373 | } |
374 | |
375 | nfp_nsp_config_set_state(state: nsp, entries, idx); |
376 | return nsp; |
377 | |
378 | err: |
379 | nfp_nsp_close(state: nsp); |
380 | kfree(objp: entries); |
381 | return ERR_PTR(error: -EIO); |
382 | } |
383 | |
384 | void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp) |
385 | { |
386 | union eth_table_entry *entries = nfp_nsp_config_entries(state: nsp); |
387 | |
388 | nfp_nsp_config_set_modified(state: nsp, modified: false); |
389 | nfp_nsp_config_clear_state(state: nsp); |
390 | nfp_nsp_close(state: nsp); |
391 | kfree(objp: entries); |
392 | } |
393 | |
394 | /** |
395 | * nfp_eth_config_commit_end() - perform recorded configuration changes |
396 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
397 | * |
398 | * Perform the configuration which was requested with __nfp_eth_set_*() |
399 | * helpers and recorded in @nsp state. If device was already configured |
400 | * as requested or no __nfp_eth_set_*() operations were made no NSP command |
401 | * will be performed. |
402 | * |
403 | * Return: |
404 | * 0 - configuration successful; |
405 | * 1 - no changes were needed; |
406 | * -ERRNO - configuration failed. |
407 | */ |
408 | int nfp_eth_config_commit_end(struct nfp_nsp *nsp) |
409 | { |
410 | union eth_table_entry *entries = nfp_nsp_config_entries(state: nsp); |
411 | int ret = 1; |
412 | |
413 | if (nfp_nsp_config_modified(state: nsp)) { |
414 | ret = nfp_nsp_write_eth_table(state: nsp, buf: entries, NSP_ETH_TABLE_SIZE); |
415 | ret = ret < 0 ? ret : 0; |
416 | } |
417 | |
418 | nfp_eth_config_cleanup_end(nsp); |
419 | |
420 | return ret; |
421 | } |
422 | |
423 | /** |
424 | * nfp_eth_set_mod_enable() - set PHY module enable control bit |
425 | * @cpp: NFP CPP handle |
426 | * @idx: NFP chip-wide port index |
427 | * @enable: Desired state |
428 | * |
429 | * Enable or disable PHY module (this usually means setting the TX lanes |
430 | * disable bits). |
431 | * |
432 | * Return: |
433 | * 0 - configuration successful; |
434 | * 1 - no changes were needed; |
435 | * -ERRNO - configuration failed. |
436 | */ |
437 | int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable) |
438 | { |
439 | union eth_table_entry *entries; |
440 | struct nfp_nsp *nsp; |
441 | u64 reg; |
442 | |
443 | nsp = nfp_eth_config_start(cpp, idx); |
444 | if (IS_ERR(ptr: nsp)) |
445 | return PTR_ERR(ptr: nsp); |
446 | |
447 | entries = nfp_nsp_config_entries(state: nsp); |
448 | |
449 | /* Check if we are already in requested state */ |
450 | reg = le64_to_cpu(entries[idx].state); |
451 | if (enable != FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) { |
452 | reg = le64_to_cpu(entries[idx].control); |
453 | reg &= ~NSP_ETH_CTRL_ENABLED; |
454 | reg |= FIELD_PREP(NSP_ETH_CTRL_ENABLED, enable); |
455 | entries[idx].control = cpu_to_le64(reg); |
456 | |
457 | nfp_nsp_config_set_modified(state: nsp, modified: true); |
458 | } |
459 | |
460 | return nfp_eth_config_commit_end(nsp); |
461 | } |
462 | |
463 | /** |
464 | * nfp_eth_set_configured() - set PHY module configured control bit |
465 | * @cpp: NFP CPP handle |
466 | * @idx: NFP chip-wide port index |
467 | * @configed: Desired state |
468 | * |
469 | * Set the ifup/ifdown state on the PHY. |
470 | * |
471 | * Return: |
472 | * 0 - configuration successful; |
473 | * 1 - no changes were needed; |
474 | * -ERRNO - configuration failed. |
475 | */ |
476 | int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed) |
477 | { |
478 | union eth_table_entry *entries; |
479 | struct nfp_nsp *nsp; |
480 | u64 reg; |
481 | |
482 | nsp = nfp_eth_config_start(cpp, idx); |
483 | if (IS_ERR(ptr: nsp)) |
484 | return PTR_ERR(ptr: nsp); |
485 | |
486 | /* Older ABI versions did support this feature, however this has only |
487 | * been reliable since ABI 20. |
488 | */ |
489 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 20) { |
490 | nfp_eth_config_cleanup_end(nsp); |
491 | return -EOPNOTSUPP; |
492 | } |
493 | |
494 | entries = nfp_nsp_config_entries(state: nsp); |
495 | |
496 | /* Check if we are already in requested state */ |
497 | reg = le64_to_cpu(entries[idx].state); |
498 | if (configed != FIELD_GET(NSP_ETH_STATE_CONFIGURED, reg)) { |
499 | reg = le64_to_cpu(entries[idx].control); |
500 | reg &= ~NSP_ETH_CTRL_CONFIGURED; |
501 | reg |= FIELD_PREP(NSP_ETH_CTRL_CONFIGURED, configed); |
502 | entries[idx].control = cpu_to_le64(reg); |
503 | |
504 | nfp_nsp_config_set_modified(state: nsp, modified: true); |
505 | } |
506 | |
507 | return nfp_eth_config_commit_end(nsp); |
508 | } |
509 | |
510 | static int |
511 | nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx, |
512 | const u64 mask, const unsigned int shift, |
513 | u64 val, const u64 ctrl_bit) |
514 | { |
515 | union eth_table_entry *entries = nfp_nsp_config_entries(state: nsp); |
516 | unsigned int idx = nfp_nsp_config_idx(state: nsp); |
517 | u64 reg; |
518 | |
519 | /* Note: set features were added in ABI 0.14 but the error |
520 | * codes were initially not populated correctly. |
521 | */ |
522 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 17) { |
523 | nfp_err(nfp_nsp_cpp(nsp), |
524 | "set operations not supported, please update flash\n" ); |
525 | return -EOPNOTSUPP; |
526 | } |
527 | |
528 | /* Check if we are already in requested state */ |
529 | reg = le64_to_cpu(entries[idx].raw[raw_idx]); |
530 | if (val == (reg & mask) >> shift) |
531 | return 0; |
532 | |
533 | reg &= ~mask; |
534 | reg |= (val << shift) & mask; |
535 | entries[idx].raw[raw_idx] = cpu_to_le64(reg); |
536 | |
537 | entries[idx].control |= cpu_to_le64(ctrl_bit); |
538 | |
539 | nfp_nsp_config_set_modified(state: nsp, modified: true); |
540 | |
541 | return 0; |
542 | } |
543 | |
544 | int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state) |
545 | { |
546 | union eth_table_entry *entries; |
547 | struct nfp_nsp *nsp; |
548 | u64 reg; |
549 | |
550 | nsp = nfp_eth_config_start(cpp, idx); |
551 | if (IS_ERR(ptr: nsp)) |
552 | return PTR_ERR(ptr: nsp); |
553 | |
554 | /* Set this features were added in ABI 0.32 */ |
555 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 32) { |
556 | nfp_err(nfp_nsp_cpp(nsp), |
557 | "set id mode operation not supported, please update flash\n" ); |
558 | nfp_eth_config_cleanup_end(nsp); |
559 | return -EOPNOTSUPP; |
560 | } |
561 | |
562 | entries = nfp_nsp_config_entries(state: nsp); |
563 | |
564 | reg = le64_to_cpu(entries[idx].control); |
565 | reg &= ~NSP_ETH_CTRL_SET_IDMODE; |
566 | reg |= FIELD_PREP(NSP_ETH_CTRL_SET_IDMODE, state); |
567 | entries[idx].control = cpu_to_le64(reg); |
568 | |
569 | nfp_nsp_config_set_modified(state: nsp, modified: true); |
570 | |
571 | return nfp_eth_config_commit_end(nsp); |
572 | } |
573 | |
574 | #define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \ |
575 | ({ \ |
576 | __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \ |
577 | nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \ |
578 | val, ctrl_bit); \ |
579 | }) |
580 | |
581 | /** |
582 | * __nfp_eth_set_aneg() - set PHY autonegotiation control bit |
583 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
584 | * @mode: Desired autonegotiation mode |
585 | * |
586 | * Allow/disallow PHY module to advertise/perform autonegotiation. |
587 | * Will write to hwinfo overrides in the flash (persistent config). |
588 | * |
589 | * Return: 0 or -ERRNO. |
590 | */ |
591 | int __nfp_eth_set_aneg(struct nfp_nsp *nsp, enum nfp_eth_aneg mode) |
592 | { |
593 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, |
594 | NSP_ETH_STATE_ANEG, mode, |
595 | NSP_ETH_CTRL_SET_ANEG); |
596 | } |
597 | |
598 | /** |
599 | * __nfp_eth_set_fec() - set PHY forward error correction control bit |
600 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
601 | * @mode: Desired fec mode |
602 | * |
603 | * Set the PHY module forward error correction mode. |
604 | * Will write to hwinfo overrides in the flash (persistent config). |
605 | * |
606 | * Return: 0 or -ERRNO. |
607 | */ |
608 | static int __nfp_eth_set_fec(struct nfp_nsp *nsp, enum nfp_eth_fec mode) |
609 | { |
610 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, |
611 | NSP_ETH_STATE_FEC, mode, |
612 | NSP_ETH_CTRL_SET_FEC); |
613 | } |
614 | |
615 | /** |
616 | * nfp_eth_set_fec() - set PHY forward error correction control mode |
617 | * @cpp: NFP CPP handle |
618 | * @idx: NFP chip-wide port index |
619 | * @mode: Desired fec mode |
620 | * |
621 | * Return: |
622 | * 0 - configuration successful; |
623 | * 1 - no changes were needed; |
624 | * -ERRNO - configuration failed. |
625 | */ |
626 | int |
627 | nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode) |
628 | { |
629 | struct nfp_nsp *nsp; |
630 | int err; |
631 | |
632 | nsp = nfp_eth_config_start(cpp, idx); |
633 | if (IS_ERR(ptr: nsp)) |
634 | return PTR_ERR(ptr: nsp); |
635 | |
636 | err = __nfp_eth_set_fec(nsp, mode); |
637 | if (err) { |
638 | nfp_eth_config_cleanup_end(nsp); |
639 | return err; |
640 | } |
641 | |
642 | return nfp_eth_config_commit_end(nsp); |
643 | } |
644 | |
645 | /** |
646 | * __nfp_eth_set_txpause() - set tx pause control bit |
647 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
648 | * @tx_pause: TX pause switch |
649 | * |
650 | * Set TX pause switch. |
651 | * |
652 | * Return: 0 or -ERRNO. |
653 | */ |
654 | static int __nfp_eth_set_txpause(struct nfp_nsp *nsp, unsigned int tx_pause) |
655 | { |
656 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_TX_PAUSE, |
657 | tx_pause, NSP_ETH_CTRL_SET_TX_PAUSE); |
658 | } |
659 | |
660 | /** |
661 | * __nfp_eth_set_rxpause() - set rx pause control bit |
662 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
663 | * @rx_pause: RX pause switch |
664 | * |
665 | * Set RX pause switch. |
666 | * |
667 | * Return: 0 or -ERRNO. |
668 | */ |
669 | static int __nfp_eth_set_rxpause(struct nfp_nsp *nsp, unsigned int rx_pause) |
670 | { |
671 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_RX_PAUSE, |
672 | rx_pause, NSP_ETH_CTRL_SET_RX_PAUSE); |
673 | } |
674 | |
675 | /** |
676 | * nfp_eth_set_pauseparam() - Set TX/RX pause switch. |
677 | * @cpp: NFP CPP handle |
678 | * @idx: NFP chip-wide port index |
679 | * @tx_pause: TX pause switch |
680 | * @rx_pause: RX pause switch |
681 | * |
682 | * Return: |
683 | * 0 - configuration successful; |
684 | * 1 - no changes were needed; |
685 | * -ERRNO - configuration failed. |
686 | */ |
687 | int |
688 | nfp_eth_set_pauseparam(struct nfp_cpp *cpp, unsigned int idx, |
689 | unsigned int tx_pause, unsigned int rx_pause) |
690 | { |
691 | struct nfp_nsp *nsp; |
692 | int err; |
693 | |
694 | nsp = nfp_eth_config_start(cpp, idx); |
695 | if (IS_ERR(ptr: nsp)) |
696 | return PTR_ERR(ptr: nsp); |
697 | |
698 | if (nfp_nsp_get_abi_ver_minor(state: nsp) < 37) { |
699 | nfp_err(nfp_nsp_cpp(nsp), |
700 | "set pause parameter operation not supported, please update flash\n" ); |
701 | nfp_eth_config_cleanup_end(nsp); |
702 | return -EOPNOTSUPP; |
703 | } |
704 | |
705 | err = __nfp_eth_set_txpause(nsp, tx_pause); |
706 | if (err) { |
707 | nfp_eth_config_cleanup_end(nsp); |
708 | return err; |
709 | } |
710 | |
711 | err = __nfp_eth_set_rxpause(nsp, rx_pause); |
712 | if (err) { |
713 | nfp_eth_config_cleanup_end(nsp); |
714 | return err; |
715 | } |
716 | |
717 | return nfp_eth_config_commit_end(nsp); |
718 | } |
719 | |
720 | /** |
721 | * __nfp_eth_set_speed() - set interface speed/rate |
722 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
723 | * @speed: Desired speed (per lane) |
724 | * |
725 | * Set lane speed. Provided @speed value should be subport speed divided |
726 | * by number of lanes this subport is spanning (i.e. 10000 for 40G, 25000 for |
727 | * 50G, etc.) |
728 | * Will write to hwinfo overrides in the flash (persistent config). |
729 | * |
730 | * Return: 0 or -ERRNO. |
731 | */ |
732 | int __nfp_eth_set_speed(struct nfp_nsp *nsp, unsigned int speed) |
733 | { |
734 | enum nfp_eth_rate rate; |
735 | |
736 | rate = nfp_eth_speed2rate(speed); |
737 | if (rate == RATE_INVALID) { |
738 | nfp_warn(nfp_nsp_cpp(nsp), |
739 | "could not find matching lane rate for speed %u\n" , |
740 | speed); |
741 | return -EINVAL; |
742 | } |
743 | |
744 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, |
745 | NSP_ETH_STATE_RATE, rate, |
746 | NSP_ETH_CTRL_SET_RATE); |
747 | } |
748 | |
749 | /** |
750 | * __nfp_eth_set_split() - set interface lane split |
751 | * @nsp: NFP NSP handle returned from nfp_eth_config_start() |
752 | * @lanes: Desired lanes per port |
753 | * |
754 | * Set number of lanes in the port. |
755 | * Will write to hwinfo overrides in the flash (persistent config). |
756 | * |
757 | * Return: 0 or -ERRNO. |
758 | */ |
759 | int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes) |
760 | { |
761 | return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES, |
762 | lanes, NSP_ETH_CTRL_SET_LANES); |
763 | } |
764 | |