aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnish Bhatt <anish@chelsio.com>2014-06-20 00:37:12 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-23 00:13:33 -0400
commit76bcb31efc0685574fb123f7aaa92f8a50c14fd9 (patch)
treeeab1d1896378fb25b7347df8c0fa9d40f164d2a1
parent989594e2f28df8ec83a41cd08c5ce5dc1072e251 (diff)
cxgb4 : Add DCBx support codebase and dcbnl_ops
Signed-off-by: Anish Bhatt <anish@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c980
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h141
2 files changed, 1121 insertions, 0 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
new file mode 100644
index 000000000000..39b4a85fceae
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
@@ -0,0 +1,980 @@
1/*
2 * Copyright (C) 2013-2014 Chelsio Communications. All rights reserved.
3 *
4 * Written by Anish Bhatt (anish@chelsio.com)
5 * Casey Leedom (leedom@chelsio.com)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * The full GNU General Public License is included in this distribution in
17 * the file called "COPYING".
18 *
19 */
20
21#include "cxgb4.h"
22
23/* Initialize a port's Data Center Bridging state. Typically used after a
24 * Link Down event.
25 */
26void cxgb4_dcb_state_init(struct net_device *dev)
27{
28 struct port_info *pi = netdev2pinfo(dev);
29 struct port_dcb_info *dcb = &pi->dcb;
30
31 memset(dcb, 0, sizeof(struct port_dcb_info));
32 dcb->state = CXGB4_DCB_STATE_START;
33}
34
35/* Finite State machine for Data Center Bridging.
36 */
37void cxgb4_dcb_state_fsm(struct net_device *dev,
38 enum cxgb4_dcb_state_input input)
39{
40 struct port_info *pi = netdev2pinfo(dev);
41 struct port_dcb_info *dcb = &pi->dcb;
42 struct adapter *adap = pi->adapter;
43
44 switch (input) {
45 case CXGB4_DCB_INPUT_FW_DISABLED: {
46 /* Firmware tells us it's not doing DCB */
47 switch (dcb->state) {
48 case CXGB4_DCB_STATE_START: {
49 /* we're going to use Host DCB */
50 dcb->state = CXGB4_DCB_STATE_HOST;
51 dcb->supported = CXGB4_DCBX_HOST_SUPPORT;
52 dcb->enabled = 1;
53 break;
54 }
55
56 case CXGB4_DCB_STATE_HOST: {
57 /* we're alreaady in Host DCB mode */
58 break;
59 }
60
61 default:
62 goto bad_state_transition;
63 }
64 break;
65 }
66
67 case CXGB4_DCB_INPUT_FW_ENABLED: {
68 /* Firmware tells us that it is doing DCB */
69 switch (dcb->state) {
70 case CXGB4_DCB_STATE_START: {
71 /* we're going to use Firmware DCB */
72 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
73 dcb->supported = CXGB4_DCBX_FW_SUPPORT;
74 break;
75 }
76
77 case CXGB4_DCB_STATE_FW_INCOMPLETE:
78 case CXGB4_DCB_STATE_FW_ALLSYNCED: {
79 /* we're alreaady in firmware DCB mode */
80 break;
81 }
82
83 default:
84 goto bad_state_transition;
85 }
86 break;
87 }
88
89 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {
90 /* Firmware tells us that its DCB state is incomplete */
91 switch (dcb->state) {
92 case CXGB4_DCB_STATE_FW_INCOMPLETE: {
93 /* we're already incomplete */
94 break;
95 }
96
97 case CXGB4_DCB_STATE_FW_ALLSYNCED: {
98 /* We were successfully running with firmware DCB but
99 * now it's telling us that it's in an "incomplete
100 * state. We need to reset back to a ground state
101 * of incomplete.
102 */
103 cxgb4_dcb_state_init(dev);
104 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
105 dcb->supported = CXGB4_DCBX_FW_SUPPORT;
106 linkwatch_fire_event(dev);
107 break;
108 }
109
110 default:
111 goto bad_state_transition;
112 }
113 break;
114 }
115
116 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {
117 /* Firmware tells us that its DCB state is complete */
118 switch (dcb->state) {
119 case CXGB4_DCB_STATE_FW_INCOMPLETE: {
120 dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED;
121 dcb->enabled = 1;
122 linkwatch_fire_event(dev);
123 break;
124 }
125
126 case CXGB4_DCB_STATE_FW_ALLSYNCED: {
127 /* we're already all sync'ed */
128 break;
129 }
130
131 default:
132 goto bad_state_transition;
133 }
134 break;
135 }
136
137 default:
138 goto bad_state_input;
139 }
140 return;
141
142bad_state_input:
143 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: illegal input symbol %d\n",
144 input);
145 return;
146
147bad_state_transition:
148 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: bad state transition, state = %d, input = %d\n",
149 dcb->state, input);
150}
151
152/* Handle a DCB/DCBX update message from the firmware.
153 */
154void cxgb4_dcb_handle_fw_update(struct adapter *adap,
155 const struct fw_port_cmd *pcmd)
156{
157 const union fw_port_dcb *fwdcb = &pcmd->u.dcb;
158 int port = FW_PORT_CMD_PORTID_GET(be32_to_cpu(pcmd->op_to_portid));
159 struct net_device *dev = adap->port[port];
160 struct port_info *pi = netdev_priv(dev);
161 struct port_dcb_info *dcb = &pi->dcb;
162 int dcb_type = pcmd->u.dcb.pgid.type;
163
164 /* Handle Firmware DCB Control messages separately since they drive
165 * our state machine.
166 */
167 if (dcb_type == FW_PORT_DCB_TYPE_CONTROL) {
168 enum cxgb4_dcb_state_input input =
169 ((pcmd->u.dcb.control.all_syncd_pkd &
170 FW_PORT_CMD_ALL_SYNCD)
171 ? CXGB4_DCB_STATE_FW_ALLSYNCED
172 : CXGB4_DCB_STATE_FW_INCOMPLETE);
173
174 cxgb4_dcb_state_fsm(dev, input);
175 return;
176 }
177
178 /* It's weird, and almost certainly an error, to get Firmware DCB
179 * messages when we either haven't been told whether we're going to be
180 * doing Host or Firmware DCB; and even worse when we've been told
181 * that we're doing Host DCB!
182 */
183 if (dcb->state == CXGB4_DCB_STATE_START ||
184 dcb->state == CXGB4_DCB_STATE_HOST) {
185 dev_err(adap->pdev_dev, "Receiving Firmware DCB messages in State %d\n",
186 dcb->state);
187 return;
188 }
189
190 /* Now handle the general Firmware DCB update messages ...
191 */
192 switch (dcb_type) {
193 case FW_PORT_DCB_TYPE_PGID:
194 dcb->pgid = be32_to_cpu(fwdcb->pgid.pgid);
195 dcb->msgs |= CXGB4_DCB_FW_PGID;
196 break;
197
198 case FW_PORT_DCB_TYPE_PGRATE:
199 dcb->pg_num_tcs_supported = fwdcb->pgrate.num_tcs_supported;
200 memcpy(dcb->pgrate, &fwdcb->pgrate.pgrate,
201 sizeof(dcb->pgrate));
202 dcb->msgs |= CXGB4_DCB_FW_PGRATE;
203 break;
204
205 case FW_PORT_DCB_TYPE_PRIORATE:
206 memcpy(dcb->priorate, &fwdcb->priorate.strict_priorate,
207 sizeof(dcb->priorate));
208 dcb->msgs |= CXGB4_DCB_FW_PRIORATE;
209 break;
210
211 case FW_PORT_DCB_TYPE_PFC:
212 dcb->pfcen = fwdcb->pfc.pfcen;
213 dcb->pfc_num_tcs_supported = fwdcb->pfc.max_pfc_tcs;
214 dcb->msgs |= CXGB4_DCB_FW_PFC;
215 break;
216
217 case FW_PORT_DCB_TYPE_APP_ID: {
218 const struct fw_port_app_priority *fwap = &fwdcb->app_priority;
219 int idx = fwap->idx;
220 struct app_priority *ap = &dcb->app_priority[idx];
221
222 struct dcb_app app = {
223 .selector = fwap->sel_field,
224 .protocol = be16_to_cpu(fwap->protocolid),
225 .priority = fwap->user_prio_map,
226 };
227 int err;
228
229 err = dcb_setapp(dev, &app);
230 if (err)
231 dev_err(adap->pdev_dev,
232 "Failed DCB Set Application Priority: sel=%d, prot=%d, prio=%d, err=%d\n",
233 app.selector, app.protocol, app.priority, -err);
234
235 ap->user_prio_map = fwap->user_prio_map;
236 ap->sel_field = fwap->sel_field;
237 ap->protocolid = be16_to_cpu(fwap->protocolid);
238 dcb->msgs |= CXGB4_DCB_FW_APP_ID;
239 break;
240 }
241
242 default:
243 dev_err(adap->pdev_dev, "Unknown DCB update type received %x\n",
244 dcb_type);
245 break;
246 }
247}
248
249/* Data Center Bridging netlink operations.
250 */
251
252
253/* Get current DCB enabled/disabled state.
254 */
255static u8 cxgb4_getstate(struct net_device *dev)
256{
257 struct port_info *pi = netdev2pinfo(dev);
258
259 return pi->dcb.enabled;
260}
261
262/* Set DCB enabled/disabled.
263 */
264static u8 cxgb4_setstate(struct net_device *dev, u8 enabled)
265{
266 struct port_info *pi = netdev2pinfo(dev);
267
268 /* Firmware doesn't provide any mechanism to control the DCB state.
269 */
270 if (enabled != (pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED))
271 return 1;
272
273 return 0;
274}
275
276static void cxgb4_getpgtccfg(struct net_device *dev, int tc,
277 u8 *prio_type, u8 *pgid, u8 *bw_per,
278 u8 *up_tc_map, int local)
279{
280 struct fw_port_cmd pcmd;
281 struct port_info *pi = netdev2pinfo(dev);
282 struct adapter *adap = pi->adapter;
283 int err;
284
285 *prio_type = *pgid = *bw_per = *up_tc_map = 0;
286
287 if (local)
288 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
289 else
290 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
291
292 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
293 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
294 if (err != FW_PORT_DCB_CFG_SUCCESS) {
295 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
296 return;
297 }
298 *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf;
299
300 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
301 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
302 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
303 if (err != FW_PORT_DCB_CFG_SUCCESS) {
304 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
305 -err);
306 return;
307 }
308
309 *bw_per = pcmd.u.dcb.pgrate.pgrate[*pgid];
310 *up_tc_map = (1 << tc);
311
312 /* prio_type is link strict */
313 *prio_type = 0x2;
314}
315
316static void cxgb4_getpgtccfg_tx(struct net_device *dev, int tc,
317 u8 *prio_type, u8 *pgid, u8 *bw_per,
318 u8 *up_tc_map)
319{
320 return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 1);
321}
322
323
324static void cxgb4_getpgtccfg_rx(struct net_device *dev, int tc,
325 u8 *prio_type, u8 *pgid, u8 *bw_per,
326 u8 *up_tc_map)
327{
328 return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 0);
329}
330
331static void cxgb4_setpgtccfg_tx(struct net_device *dev, int tc,
332 u8 prio_type, u8 pgid, u8 bw_per,
333 u8 up_tc_map)
334{
335 struct fw_port_cmd pcmd;
336 struct port_info *pi = netdev2pinfo(dev);
337 struct adapter *adap = pi->adapter;
338 u32 _pgid;
339 int err;
340
341 if (pgid == DCB_ATTR_VALUE_UNDEFINED)
342 return;
343 if (bw_per == DCB_ATTR_VALUE_UNDEFINED)
344 return;
345
346 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
347 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
348
349 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
350 if (err != FW_PORT_DCB_CFG_SUCCESS) {
351 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
352 return;
353 }
354
355 _pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
356 _pgid &= ~(0xF << (tc * 4));
357 _pgid |= pgid << (tc * 4);
358 pcmd.u.dcb.pgid.pgid = cpu_to_be32(_pgid);
359
360 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
361
362 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
363 if (err != FW_PORT_DCB_CFG_SUCCESS) {
364 dev_err(adap->pdev_dev, "DCB write PGID failed with %d\n",
365 -err);
366 return;
367 }
368
369 memset(&pcmd, 0, sizeof(struct fw_port_cmd));
370
371 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
372 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
373
374 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
375 if (err != FW_PORT_DCB_CFG_SUCCESS) {
376 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
377 -err);
378 return;
379 }
380
381 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;
382
383 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
384 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
385 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
386
387 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
388 if (err != FW_PORT_DCB_CFG_SUCCESS)
389 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",
390 -err);
391}
392
393static void cxgb4_getpgbwgcfg(struct net_device *dev, int pgid, u8 *bw_per,
394 int local)
395{
396 struct fw_port_cmd pcmd;
397 struct port_info *pi = netdev2pinfo(dev);
398 struct adapter *adap = pi->adapter;
399 int err;
400
401 if (local)
402 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
403 else
404 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
405
406 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
407 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
408 if (err != FW_PORT_DCB_CFG_SUCCESS) {
409 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
410 -err);
411 } else {
412 *bw_per = pcmd.u.dcb.pgrate.pgrate[pgid];
413 }
414}
415
416static void cxgb4_getpgbwgcfg_tx(struct net_device *dev, int pgid, u8 *bw_per)
417{
418 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 1);
419}
420
421static void cxgb4_getpgbwgcfg_rx(struct net_device *dev, int pgid, u8 *bw_per)
422{
423 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 0);
424}
425
426static void cxgb4_setpgbwgcfg_tx(struct net_device *dev, int pgid,
427 u8 bw_per)
428{
429 struct fw_port_cmd pcmd;
430 struct port_info *pi = netdev2pinfo(dev);
431 struct adapter *adap = pi->adapter;
432 int err;
433
434 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
435 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
436
437 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
438 if (err != FW_PORT_DCB_CFG_SUCCESS) {
439 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
440 -err);
441 return;
442 }
443
444 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;
445
446 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
447 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
448 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
449
450 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
451
452 if (err != FW_PORT_DCB_CFG_SUCCESS)
453 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",
454 -err);
455}
456
457/* Return whether the specified Traffic Class Priority has Priority Pause
458 * Frames enabled.
459 */
460static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg)
461{
462 struct port_info *pi = netdev2pinfo(dev);
463 struct port_dcb_info *dcb = &pi->dcb;
464
465 if (dcb->state != CXGB4_DCB_STATE_FW_ALLSYNCED ||
466 priority >= CXGB4_MAX_PRIORITY)
467 *pfccfg = 0;
468 else
469 *pfccfg = (pi->dcb.pfcen >> priority) & 1;
470}
471
472/* Enable/disable Priority Pause Frames for the specified Traffic Class
473 * Priority.
474 */
475static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg)
476{
477 struct fw_port_cmd pcmd;
478 struct port_info *pi = netdev2pinfo(dev);
479 struct adapter *adap = pi->adapter;
480 int err;
481
482 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED ||
483 priority >= CXGB4_MAX_PRIORITY)
484 return;
485
486 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
487 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
488 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
489
490 pcmd.u.dcb.pfc.type = FW_PORT_DCB_TYPE_PFC;
491 pcmd.u.dcb.pfc.pfcen = cpu_to_be16(pi->dcb.pfcen);
492
493 if (pfccfg)
494 pcmd.u.dcb.pfc.pfcen |= cpu_to_be16(1 << priority);
495 else
496 pcmd.u.dcb.pfc.pfcen &= cpu_to_be16(~(1 << priority));
497
498 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
499 if (err != FW_PORT_DCB_CFG_SUCCESS) {
500 dev_err(adap->pdev_dev, "DCB PFC write failed with %d\n", -err);
501 return;
502 }
503
504 pi->dcb.pfcen = be16_to_cpu(pcmd.u.dcb.pfc.pfcen);
505}
506
507static u8 cxgb4_setall(struct net_device *dev)
508{
509 return 0;
510}
511
512/* Return DCB capabilities.
513 */
514static u8 cxgb4_getcap(struct net_device *dev, int cap_id, u8 *caps)
515{
516 struct port_info *pi = netdev2pinfo(dev);
517
518 switch (cap_id) {
519 case DCB_CAP_ATTR_PG:
520 case DCB_CAP_ATTR_PFC:
521 *caps = true;
522 break;
523
524 case DCB_CAP_ATTR_PG_TCS:
525 /* 8 priorities for PG represented by bitmap */
526 *caps = 0x80;
527 break;
528
529 case DCB_CAP_ATTR_PFC_TCS:
530 /* 8 priorities for PFC represented by bitmap */
531 *caps = 0x80;
532 break;
533
534 case DCB_CAP_ATTR_GSP:
535 *caps = true;
536 break;
537
538 case DCB_CAP_ATTR_UP2TC:
539 case DCB_CAP_ATTR_BCN:
540 *caps = false;
541 break;
542
543 case DCB_CAP_ATTR_DCBX:
544 *caps = pi->dcb.supported;
545 break;
546
547 default:
548 *caps = false;
549 }
550
551 return 0;
552}
553
554/* Return the number of Traffic Classes for the indicated Traffic Class ID.
555 */
556static int cxgb4_getnumtcs(struct net_device *dev, int tcs_id, u8 *num)
557{
558 struct port_info *pi = netdev2pinfo(dev);
559
560 switch (tcs_id) {
561 case DCB_NUMTCS_ATTR_PG:
562 if (pi->dcb.msgs & CXGB4_DCB_FW_PGRATE)
563 *num = pi->dcb.pg_num_tcs_supported;
564 else
565 *num = 0x8;
566 break;
567
568 case DCB_NUMTCS_ATTR_PFC:
569 *num = 0x8;
570 break;
571
572 default:
573 return -EINVAL;
574 }
575
576 return 0;
577}
578
579/* Set the number of Traffic Classes supported for the indicated Traffic Class
580 * ID.
581 */
582static int cxgb4_setnumtcs(struct net_device *dev, int tcs_id, u8 num)
583{
584 /* Setting the number of Traffic Classes isn't supported.
585 */
586 return -ENOSYS;
587}
588
589/* Return whether Priority Flow Control is enabled. */
590static u8 cxgb4_getpfcstate(struct net_device *dev)
591{
592 struct port_info *pi = netdev2pinfo(dev);
593
594 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
595 return false;
596
597 return pi->dcb.pfcen != 0;
598}
599
600/* Enable/disable Priority Flow Control. */
601static void cxgb4_setpfcstate(struct net_device *dev, u8 state)
602{
603 /* We can't enable/disable Priority Flow Control but we also can't
604 * return an error ...
605 */
606}
607
608/* Return the Application User Priority Map associated with the specified
609 * Application ID.
610 */
611static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id,
612 int peer)
613{
614 struct port_info *pi = netdev2pinfo(dev);
615 struct adapter *adap = pi->adapter;
616 int i;
617
618 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
619 return 0;
620
621 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
622 struct fw_port_cmd pcmd;
623 int err;
624
625 if (peer)
626 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
627 else
628 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
629
630 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
631 pcmd.u.dcb.app_priority.idx = i;
632
633 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
634 if (err != FW_PORT_DCB_CFG_SUCCESS) {
635 dev_err(adap->pdev_dev, "DCB APP read failed with %d\n",
636 -err);
637 return err;
638 }
639 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id)
640 return pcmd.u.dcb.app_priority.user_prio_map;
641
642 /* exhausted app list */
643 if (!pcmd.u.dcb.app_priority.protocolid)
644 break;
645 }
646
647 return -EEXIST;
648}
649
650/* Return the Application User Priority Map associated with the specified
651 * Application ID. Since this routine is prototyped to return "u8" we can't
652 * return errors ...
653 */
654static u8 cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id)
655{
656 int result = __cxgb4_getapp(dev, app_idtype, app_id, 0);
657
658 if (result < 0)
659 result = 0;
660
661 return result;
662}
663
664/* Write a new Application User Priority Map for the specified Application ID.
665 * This routine is prototyped to return "u8" but other instantiations of the
666 * DCB NetLink Operations "setapp" routines return negative errnos for errors.
667 * We follow their lead.
668 */
669static u8 cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id,
670 u8 app_prio)
671{
672 struct fw_port_cmd pcmd;
673 struct port_info *pi = netdev2pinfo(dev);
674 struct adapter *adap = pi->adapter;
675 int i, err;
676
677
678 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
679 return -EINVAL;
680
681 /* DCB info gets thrown away on link up */
682 if (!netif_carrier_ok(dev))
683 return -ENOLINK;
684
685 if (app_idtype != DCB_APP_IDTYPE_ETHTYPE &&
686 app_idtype != DCB_APP_IDTYPE_PORTNUM)
687 return -EINVAL;
688
689 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
690 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
691 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
692 pcmd.u.dcb.app_priority.idx = i;
693 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
694
695 if (err != FW_PORT_DCB_CFG_SUCCESS) {
696 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
697 -err);
698 return err;
699 }
700 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id) {
701 /* overwrite existing app table */
702 pcmd.u.dcb.app_priority.protocolid = 0;
703 break;
704 }
705 /* find first empty slot */
706 if (!pcmd.u.dcb.app_priority.protocolid)
707 break;
708 }
709
710 if (i == CXGB4_MAX_DCBX_APP_SUPPORTED) {
711 /* no empty slots available */
712 dev_err(adap->pdev_dev, "DCB app table full\n");
713 return -EBUSY;
714 }
715
716 /* write out new app table entry */
717 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
718 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
719 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
720
721 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
722 pcmd.u.dcb.app_priority.protocolid = cpu_to_be16(app_id);
723 pcmd.u.dcb.app_priority.sel_field = app_idtype;
724 pcmd.u.dcb.app_priority.user_prio_map = app_prio;
725 pcmd.u.dcb.app_priority.idx = i;
726
727 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
728 if (err != FW_PORT_DCB_CFG_SUCCESS) {
729 dev_err(adap->pdev_dev, "DCB app table write failed with %d\n",
730 -err);
731 return err;
732 }
733
734 return 0;
735}
736
737/* Return whether IEEE Data Center Bridging has been negotiated.
738 */
739static inline int cxgb4_ieee_negotiation_complete(struct net_device *dev)
740{
741 struct port_info *pi = netdev2pinfo(dev);
742 struct port_dcb_info *dcb = &pi->dcb;
743
744 return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED &&
745 (dcb->supported & DCB_CAP_DCBX_VER_IEEE));
746}
747
748/* Fill in the Application User Priority Map associated with the
749 * specified Application.
750 */
751static int cxgb4_ieee_getapp(struct net_device *dev, struct dcb_app *app)
752{
753 int prio;
754
755 if (!cxgb4_ieee_negotiation_complete(dev))
756 return -EINVAL;
757 if (!(app->selector && app->protocol))
758 return -EINVAL;
759
760 prio = dcb_getapp(dev, app);
761 if (prio == 0) {
762 /* If app doesn't exist in dcb_app table, try firmware
763 * directly.
764 */
765 prio = __cxgb4_getapp(dev, app->selector, app->protocol, 0);
766 }
767
768 app->priority = prio;
769 return 0;
770}
771
772/* Write a new Application User Priority Map for the specified App id. */
773static int cxgb4_ieee_setapp(struct net_device *dev, struct dcb_app *app)
774{
775 if (!cxgb4_ieee_negotiation_complete(dev))
776 return -EINVAL;
777 if (!(app->selector && app->protocol && app->priority))
778 return -EINVAL;
779
780 cxgb4_setapp(dev, app->selector, app->protocol, app->priority);
781 return dcb_setapp(dev, app);
782}
783
784/* Return our DCBX parameters.
785 */
786static u8 cxgb4_getdcbx(struct net_device *dev)
787{
788 struct port_info *pi = netdev2pinfo(dev);
789
790 /* This is already set by cxgb4_set_dcb_caps, so just return it */
791 return pi->dcb.supported;
792}
793
794/* Set our DCBX parameters.
795 */
796static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request)
797{
798 struct port_info *pi = netdev2pinfo(dev);
799
800 /* Filter out requests which exceed our capabilities.
801 */
802 if ((dcb_request & (CXGB4_DCBX_FW_SUPPORT | CXGB4_DCBX_HOST_SUPPORT))
803 != dcb_request)
804 return 1;
805
806 /* Can't set DCBX capabilities if DCBX isn't enabled. */
807 if (!pi->dcb.state)
808 return 1;
809
810 /* There's currently no mechanism to allow for the firmware DCBX
811 * negotiation to be changed from the Host Driver. If the caller
812 * requests exactly the same parameters that we already have then
813 * we'll allow them to be successfully "set" ...
814 */
815 if (dcb_request != pi->dcb.supported)
816 return 1;
817
818 pi->dcb.supported = dcb_request;
819 return 0;
820}
821
822static int cxgb4_getpeer_app(struct net_device *dev,
823 struct dcb_peer_app_info *info, u16 *app_count)
824{
825 struct fw_port_cmd pcmd;
826 struct port_info *pi = netdev2pinfo(dev);
827 struct adapter *adap = pi->adapter;
828 int i, err = 0;
829
830 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
831 return 1;
832
833 info->willing = 0;
834 info->error = 0;
835
836 *app_count = 0;
837 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
838 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
839 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
840 pcmd.u.dcb.app_priority.idx = *app_count;
841 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
842
843 if (err != FW_PORT_DCB_CFG_SUCCESS) {
844 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
845 -err);
846 return err;
847 }
848
849 /* find first empty slot */
850 if (!pcmd.u.dcb.app_priority.protocolid)
851 break;
852 }
853 *app_count = i;
854 return err;
855}
856
857static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table)
858{
859 struct fw_port_cmd pcmd;
860 struct port_info *pi = netdev2pinfo(dev);
861 struct adapter *adap = pi->adapter;
862 int i, err = 0;
863
864 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
865 return 1;
866
867 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
868 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
869 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
870 pcmd.u.dcb.app_priority.idx = i;
871 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
872
873 if (err != FW_PORT_DCB_CFG_SUCCESS) {
874 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
875 -err);
876 return err;
877 }
878
879 /* find first empty slot */
880 if (!pcmd.u.dcb.app_priority.protocolid)
881 break;
882
883 table[i].selector = pcmd.u.dcb.app_priority.sel_field;
884 table[i].protocol =
885 be16_to_cpu(pcmd.u.dcb.app_priority.protocolid);
886 table[i].priority = pcmd.u.dcb.app_priority.user_prio_map;
887 }
888 return err;
889}
890
891/* Return Priority Group information.
892 */
893static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg)
894{
895 struct fw_port_cmd pcmd;
896 struct port_info *pi = netdev2pinfo(dev);
897 struct adapter *adap = pi->adapter;
898 u32 pgid;
899 int i, err;
900
901 /* We're always "willing" -- the Switch Fabric always dictates the
902 * DCBX parameters to us.
903 */
904 pg->willing = true;
905
906 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
907 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
908 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
909 if (err != FW_PORT_DCB_CFG_SUCCESS) {
910 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
911 return err;
912 }
913 pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
914
915 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
916 pg->prio_pg[i] = (pgid >> (i * 4)) & 0xF;
917
918 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
919 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
920 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
921 if (err != FW_PORT_DCB_CFG_SUCCESS) {
922 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
923 -err);
924 return err;
925 }
926
927 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
928 pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i];
929
930 return 0;
931}
932
933/* Return Priority Flow Control information.
934 */
935static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc)
936{
937 struct port_info *pi = netdev2pinfo(dev);
938
939 cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported));
940 pfc->pfc_en = pi->dcb.pfcen;
941
942 return 0;
943}
944
945const struct dcbnl_rtnl_ops cxgb4_dcb_ops = {
946 .ieee_getapp = cxgb4_ieee_getapp,
947 .ieee_setapp = cxgb4_ieee_setapp,
948
949 /* CEE std */
950 .getstate = cxgb4_getstate,
951 .setstate = cxgb4_setstate,
952 .getpgtccfgtx = cxgb4_getpgtccfg_tx,
953 .getpgbwgcfgtx = cxgb4_getpgbwgcfg_tx,
954 .getpgtccfgrx = cxgb4_getpgtccfg_rx,
955 .getpgbwgcfgrx = cxgb4_getpgbwgcfg_rx,
956 .setpgtccfgtx = cxgb4_setpgtccfg_tx,
957 .setpgbwgcfgtx = cxgb4_setpgbwgcfg_tx,
958 .setpfccfg = cxgb4_setpfccfg,
959 .getpfccfg = cxgb4_getpfccfg,
960 .setall = cxgb4_setall,
961 .getcap = cxgb4_getcap,
962 .getnumtcs = cxgb4_getnumtcs,
963 .setnumtcs = cxgb4_setnumtcs,
964 .getpfcstate = cxgb4_getpfcstate,
965 .setpfcstate = cxgb4_setpfcstate,
966 .getapp = cxgb4_getapp,
967 .setapp = cxgb4_setapp,
968
969 /* DCBX configuration */
970 .getdcbx = cxgb4_getdcbx,
971 .setdcbx = cxgb4_setdcbx,
972
973 /* peer apps */
974 .peer_getappinfo = cxgb4_getpeer_app,
975 .peer_getapptable = cxgb4_getpeerapp_tbl,
976
977 /* CEE peer */
978 .cee_peer_getpg = cxgb4_cee_peer_getpg,
979 .cee_peer_getpfc = cxgb4_cee_peer_getpfc,
980};
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
new file mode 100644
index 000000000000..1ec1d834e257
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
@@ -0,0 +1,141 @@
1/*
2 * Copyright (C) 2013-2014 Chelsio Communications. All rights reserved.
3 *
4 * Written by Anish Bhatt (anish@chelsio.com)
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 */
19
20#ifndef __CXGB4_DCB_H
21#define __CXGB4_DCB_H
22
23#include <linux/netdevice.h>
24#include <linux/dcbnl.h>
25#include <net/dcbnl.h>
26
27#ifdef CONFIG_CHELSIO_T4_DCB
28
29#define CXGB4_DCBX_FW_SUPPORT \
30 (DCB_CAP_DCBX_VER_CEE | \
31 DCB_CAP_DCBX_VER_IEEE | \
32 DCB_CAP_DCBX_LLD_MANAGED)
33#define CXGB4_DCBX_HOST_SUPPORT \
34 (DCB_CAP_DCBX_VER_CEE | \
35 DCB_CAP_DCBX_VER_IEEE | \
36 DCB_CAP_DCBX_HOST)
37
38#define CXGB4_MAX_PRIORITY CXGB4_MAX_DCBX_APP_SUPPORTED
39#define CXGB4_MAX_TCS CXGB4_MAX_DCBX_APP_SUPPORTED
40
41#define INIT_PORT_DCB_CMD(__pcmd, __port, __op, __action) \
42 do { \
43 memset(&(__pcmd), 0, sizeof(__pcmd)); \
44 (__pcmd).op_to_portid = \
45 cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | \
46 FW_CMD_REQUEST | \
47 FW_CMD_##__op | \
48 FW_PORT_CMD_PORTID(__port)); \
49 (__pcmd).action_to_len16 = \
50 cpu_to_be32(FW_PORT_CMD_ACTION(__action) | \
51 FW_LEN16(pcmd)); \
52 } while (0)
53
54#define INIT_PORT_DCB_READ_PEER_CMD(__pcmd, __port) \
55 INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_RECV)
56
57#define INIT_PORT_DCB_READ_LOCAL_CMD(__pcmd, __port) \
58 INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_TRANS)
59
60#define INIT_PORT_DCB_READ_SYNC_CMD(__pcmd, __port) \
61 INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_DET)
62
63#define INIT_PORT_DCB_WRITE_CMD(__pcmd, __port) \
64 INIT_PORT_DCB_CMD(__pcmd, __port, EXEC, FW_PORT_ACTION_L2_DCB_CFG)
65
66/* States we can be in for a port's Data Center Bridging.
67 */
68enum cxgb4_dcb_state {
69 CXGB4_DCB_STATE_START, /* initial unknown state */
70 CXGB4_DCB_STATE_HOST, /* we're using Host DCB (if at all) */
71 CXGB4_DCB_STATE_FW_INCOMPLETE, /* using firmware DCB, incomplete */
72 CXGB4_DCB_STATE_FW_ALLSYNCED, /* using firmware DCB, all sync'ed */
73};
74
75/* Data Center Bridging state input for the Finite State Machine.
76 */
77enum cxgb4_dcb_state_input {
78 /* Input from the firmware.
79 */
80 CXGB4_DCB_INPUT_FW_DISABLED, /* firmware DCB disabled */
81 CXGB4_DCB_INPUT_FW_ENABLED, /* firmware DCB enabled */
82 CXGB4_DCB_INPUT_FW_INCOMPLETE, /* firmware reports incomplete DCB */
83 CXGB4_DCB_INPUT_FW_ALLSYNCED, /* firmware reports all sync'ed */
84
85};
86
87/* Firmware DCB messages that we've received so far ...
88 */
89enum cxgb4_dcb_fw_msgs {
90 CXGB4_DCB_FW_PGID = 0x01,
91 CXGB4_DCB_FW_PGRATE = 0x02,
92 CXGB4_DCB_FW_PRIORATE = 0x04,
93 CXGB4_DCB_FW_PFC = 0x08,
94 CXGB4_DCB_FW_APP_ID = 0x10,
95};
96
97#define CXGB4_MAX_DCBX_APP_SUPPORTED 8
98
99/* Data Center Bridging support;
100 */
101struct port_dcb_info {
102 enum cxgb4_dcb_state state; /* DCB State Machine */
103 enum cxgb4_dcb_fw_msgs msgs; /* DCB Firmware messages received */
104 unsigned int supported; /* OS DCB capabilities supported */
105 bool enabled; /* OS Enabled state */
106
107 /* Cached copies of DCB information sent by the firmware (in Host
108 * Native Endian format).
109 */
110 u32 pgid; /* Priority Group[0..7] */
111 u8 pfcen; /* Priority Flow Control[0..7] */
112 u8 pg_num_tcs_supported; /* max PG Traffic Classes */
113 u8 pfc_num_tcs_supported; /* max PFC Traffic Classes */
114 u8 pgrate[8]; /* Priority Group Rate[0..7] */
115 u8 priorate[8]; /* Priority Rate[0..7] */
116 struct app_priority { /* Application Information */
117 u8 user_prio_map; /* Priority Map bitfield */
118 u8 sel_field; /* Protocol ID interpretation */
119 u16 protocolid; /* Protocol ID */
120 } app_priority[CXGB4_MAX_DCBX_APP_SUPPORTED];
121};
122
123void cxgb4_dcb_state_init(struct net_device *);
124void cxgb4_dcb_state_fsm(struct net_device *, enum cxgb4_dcb_state_input);
125void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *);
126void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *);
127extern const struct dcbnl_rtnl_ops cxgb4_dcb_ops;
128
129#define CXGB4_DCB_ENABLED true
130
131#else /* !CONFIG_CHELSIO_T4_DCB */
132
133static inline void cxgb4_dcb_state_init(struct net_device *dev)
134{
135}
136
137#define CXGB4_DCB_ENABLED false
138
139#endif /* !CONFIG_CHELSIO_T4_DCB */
140
141#endif /* __CXGB4_DCB_H */