blob: 8edf0f5bd679bf24b366887ff973a5d454c3af73 [file] [log] [blame]
Anish Bhatt76bcb312014-06-19 21:37:12 -07001/*
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
Anish Bhatt10b00462014-08-07 16:14:03 -070023/* DCBx version control
24 */
25char *dcb_ver_array[] = {
26 "Unknown",
27 "DCBx-CIN",
28 "DCBx-CEE 1.01",
29 "DCBx-IEEE",
30 "", "", "",
31 "Auto Negotiated"
32};
33
Anish Bhatt76bcb312014-06-19 21:37:12 -070034/* Initialize a port's Data Center Bridging state. Typically used after a
35 * Link Down event.
36 */
37void cxgb4_dcb_state_init(struct net_device *dev)
38{
39 struct port_info *pi = netdev2pinfo(dev);
40 struct port_dcb_info *dcb = &pi->dcb;
Anish Bhatt10b00462014-08-07 16:14:03 -070041 int version_temp = dcb->dcb_version;
Anish Bhatt76bcb312014-06-19 21:37:12 -070042
43 memset(dcb, 0, sizeof(struct port_dcb_info));
44 dcb->state = CXGB4_DCB_STATE_START;
Anish Bhatt10b00462014-08-07 16:14:03 -070045 if (version_temp)
46 dcb->dcb_version = version_temp;
47
48 netdev_dbg(dev, "%s: Initializing DCB state for port[%d]\n",
49 __func__, pi->port_id);
50}
51
52void cxgb4_dcb_version_init(struct net_device *dev)
53{
54 struct port_info *pi = netdev2pinfo(dev);
55 struct port_dcb_info *dcb = &pi->dcb;
56
57 /* Any writes here are only done on kernels that exlicitly need
58 * a specific version, say < 2.6.38 which only support CEE
59 */
60 dcb->dcb_version = FW_PORT_DCB_VER_AUTO;
Anish Bhatt76bcb312014-06-19 21:37:12 -070061}
62
63/* Finite State machine for Data Center Bridging.
64 */
65void cxgb4_dcb_state_fsm(struct net_device *dev,
Anish Bhatt10b00462014-08-07 16:14:03 -070066 enum cxgb4_dcb_state_input transition_to)
Anish Bhatt76bcb312014-06-19 21:37:12 -070067{
68 struct port_info *pi = netdev2pinfo(dev);
69 struct port_dcb_info *dcb = &pi->dcb;
70 struct adapter *adap = pi->adapter;
Anish Bhatt10b00462014-08-07 16:14:03 -070071 enum cxgb4_dcb_state current_state = dcb->state;
Anish Bhatt76bcb312014-06-19 21:37:12 -070072
Anish Bhatt10b00462014-08-07 16:14:03 -070073 netdev_dbg(dev, "%s: State change from %d to %d for %s\n",
74 __func__, dcb->state, transition_to, dev->name);
75
76 switch (current_state) {
77 case CXGB4_DCB_STATE_START: {
78 switch (transition_to) {
79 case CXGB4_DCB_INPUT_FW_DISABLED: {
Anish Bhatt76bcb312014-06-19 21:37:12 -070080 /* we're going to use Host DCB */
81 dcb->state = CXGB4_DCB_STATE_HOST;
82 dcb->supported = CXGB4_DCBX_HOST_SUPPORT;
83 dcb->enabled = 1;
84 break;
85 }
86
Anish Bhatt10b00462014-08-07 16:14:03 -070087 case CXGB4_DCB_INPUT_FW_ENABLED: {
Anish Bhatt76bcb312014-06-19 21:37:12 -070088 /* we're going to use Firmware DCB */
89 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
90 dcb->supported = CXGB4_DCBX_FW_SUPPORT;
91 break;
92 }
93
Anish Bhatt10b00462014-08-07 16:14:03 -070094 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {
95 /* expected transition */
96 break;
97 }
98
99 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {
100 dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700101 break;
102 }
103
104 default:
Anish Bhatt10b00462014-08-07 16:14:03 -0700105 goto bad_state_input;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700106 }
107 break;
108 }
109
Anish Bhatt10b00462014-08-07 16:14:03 -0700110 case CXGB4_DCB_STATE_FW_INCOMPLETE: {
111 switch (transition_to) {
112 case CXGB4_DCB_INPUT_FW_ENABLED: {
113 /* we're alreaady in firmware DCB mode */
114 break;
115 }
116
117 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {
Anish Bhatt76bcb312014-06-19 21:37:12 -0700118 /* we're already incomplete */
119 break;
120 }
121
Anish Bhatt10b00462014-08-07 16:14:03 -0700122 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {
123 dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED;
124 dcb->enabled = 1;
125 linkwatch_fire_event(dev);
126 break;
127 }
128
129 default:
130 goto bad_state_input;
131 }
132 break;
133 }
134
135 case CXGB4_DCB_STATE_FW_ALLSYNCED: {
136 switch (transition_to) {
137 case CXGB4_DCB_INPUT_FW_ENABLED: {
138 /* we're alreaady in firmware DCB mode */
139 break;
140 }
141
142 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {
Anish Bhatt76bcb312014-06-19 21:37:12 -0700143 /* We were successfully running with firmware DCB but
144 * now it's telling us that it's in an "incomplete
145 * state. We need to reset back to a ground state
146 * of incomplete.
147 */
148 cxgb4_dcb_state_init(dev);
149 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
150 dcb->supported = CXGB4_DCBX_FW_SUPPORT;
151 linkwatch_fire_event(dev);
152 break;
153 }
154
Anish Bhatt10b00462014-08-07 16:14:03 -0700155 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {
156 /* we're already all sync'ed
157 * this is only applicable for IEEE or
158 * when another VI already completed negotiaton
159 */
Anish Bhatt76bcb312014-06-19 21:37:12 -0700160 dcb->enabled = 1;
161 linkwatch_fire_event(dev);
162 break;
163 }
164
Anish Bhatt10b00462014-08-07 16:14:03 -0700165 default:
166 goto bad_state_input;
167 }
168 break;
169 }
170
171 case CXGB4_DCB_STATE_HOST: {
172 switch (transition_to) {
173 case CXGB4_DCB_INPUT_FW_DISABLED: {
174 /* we're alreaady in Host DCB mode */
Anish Bhatt76bcb312014-06-19 21:37:12 -0700175 break;
176 }
177
178 default:
Anish Bhatt10b00462014-08-07 16:14:03 -0700179 goto bad_state_input;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700180 }
181 break;
182 }
183
184 default:
Anish Bhatt10b00462014-08-07 16:14:03 -0700185 goto bad_state_transition;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700186 }
187 return;
188
189bad_state_input:
190 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: illegal input symbol %d\n",
Anish Bhatt10b00462014-08-07 16:14:03 -0700191 transition_to);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700192 return;
193
194bad_state_transition:
195 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: bad state transition, state = %d, input = %d\n",
Anish Bhatt10b00462014-08-07 16:14:03 -0700196 current_state, transition_to);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700197}
198
199/* Handle a DCB/DCBX update message from the firmware.
200 */
201void cxgb4_dcb_handle_fw_update(struct adapter *adap,
202 const struct fw_port_cmd *pcmd)
203{
204 const union fw_port_dcb *fwdcb = &pcmd->u.dcb;
205 int port = FW_PORT_CMD_PORTID_GET(be32_to_cpu(pcmd->op_to_portid));
206 struct net_device *dev = adap->port[port];
207 struct port_info *pi = netdev_priv(dev);
208 struct port_dcb_info *dcb = &pi->dcb;
209 int dcb_type = pcmd->u.dcb.pgid.type;
Anish Bhatt10b00462014-08-07 16:14:03 -0700210 int dcb_running_version;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700211
212 /* Handle Firmware DCB Control messages separately since they drive
213 * our state machine.
214 */
215 if (dcb_type == FW_PORT_DCB_TYPE_CONTROL) {
216 enum cxgb4_dcb_state_input input =
217 ((pcmd->u.dcb.control.all_syncd_pkd &
218 FW_PORT_CMD_ALL_SYNCD)
219 ? CXGB4_DCB_STATE_FW_ALLSYNCED
220 : CXGB4_DCB_STATE_FW_INCOMPLETE);
221
Anish Bhatt10b00462014-08-07 16:14:03 -0700222 if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) {
223 dcb_running_version = FW_PORT_CMD_DCB_VERSION_GET(
224 be16_to_cpu(
225 pcmd->u.dcb.control.dcb_version_to_app_state));
226 if (dcb_running_version == FW_PORT_DCB_VER_CEE1D01 ||
227 dcb_running_version == FW_PORT_DCB_VER_IEEE) {
228 dcb->dcb_version = dcb_running_version;
229 dev_warn(adap->pdev_dev, "Interface %s is running %s\n",
230 dev->name,
231 dcb_ver_array[dcb->dcb_version]);
232 } else {
233 dev_warn(adap->pdev_dev,
234 "Something screwed up, requested firmware for %s, but firmware returned %s instead\n",
235 dcb_ver_array[dcb->dcb_version],
236 dcb_ver_array[dcb_running_version]);
237 dcb->dcb_version = FW_PORT_DCB_VER_UNKNOWN;
238 }
239 }
240
Anish Bhatt76bcb312014-06-19 21:37:12 -0700241 cxgb4_dcb_state_fsm(dev, input);
242 return;
243 }
244
245 /* It's weird, and almost certainly an error, to get Firmware DCB
246 * messages when we either haven't been told whether we're going to be
247 * doing Host or Firmware DCB; and even worse when we've been told
248 * that we're doing Host DCB!
249 */
250 if (dcb->state == CXGB4_DCB_STATE_START ||
251 dcb->state == CXGB4_DCB_STATE_HOST) {
252 dev_err(adap->pdev_dev, "Receiving Firmware DCB messages in State %d\n",
253 dcb->state);
254 return;
255 }
256
257 /* Now handle the general Firmware DCB update messages ...
258 */
259 switch (dcb_type) {
260 case FW_PORT_DCB_TYPE_PGID:
261 dcb->pgid = be32_to_cpu(fwdcb->pgid.pgid);
262 dcb->msgs |= CXGB4_DCB_FW_PGID;
263 break;
264
265 case FW_PORT_DCB_TYPE_PGRATE:
266 dcb->pg_num_tcs_supported = fwdcb->pgrate.num_tcs_supported;
267 memcpy(dcb->pgrate, &fwdcb->pgrate.pgrate,
268 sizeof(dcb->pgrate));
Anish Bhatt10b00462014-08-07 16:14:03 -0700269 memcpy(dcb->tsa, &fwdcb->pgrate.tsa,
270 sizeof(dcb->tsa));
Anish Bhatt76bcb312014-06-19 21:37:12 -0700271 dcb->msgs |= CXGB4_DCB_FW_PGRATE;
Anish Bhatt10b00462014-08-07 16:14:03 -0700272 if (dcb->msgs & CXGB4_DCB_FW_PGID)
273 IEEE_FAUX_SYNC(dev, dcb);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700274 break;
275
276 case FW_PORT_DCB_TYPE_PRIORATE:
277 memcpy(dcb->priorate, &fwdcb->priorate.strict_priorate,
278 sizeof(dcb->priorate));
279 dcb->msgs |= CXGB4_DCB_FW_PRIORATE;
280 break;
281
282 case FW_PORT_DCB_TYPE_PFC:
283 dcb->pfcen = fwdcb->pfc.pfcen;
284 dcb->pfc_num_tcs_supported = fwdcb->pfc.max_pfc_tcs;
285 dcb->msgs |= CXGB4_DCB_FW_PFC;
Anish Bhatt10b00462014-08-07 16:14:03 -0700286 IEEE_FAUX_SYNC(dev, dcb);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700287 break;
288
289 case FW_PORT_DCB_TYPE_APP_ID: {
290 const struct fw_port_app_priority *fwap = &fwdcb->app_priority;
291 int idx = fwap->idx;
292 struct app_priority *ap = &dcb->app_priority[idx];
293
294 struct dcb_app app = {
Anish Bhatt76bcb312014-06-19 21:37:12 -0700295 .protocol = be16_to_cpu(fwap->protocolid),
Anish Bhatt76bcb312014-06-19 21:37:12 -0700296 };
297 int err;
298
Anish Bhatt10b00462014-08-07 16:14:03 -0700299 /* Convert from firmware format to relevant format
300 * when using app selector
301 */
302 if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {
303 app.selector = (fwap->sel_field + 1);
304 app.priority = ffs(fwap->user_prio_map) - 1;
305 err = dcb_ieee_setapp(dev, &app);
306 IEEE_FAUX_SYNC(dev, dcb);
307 } else {
308 /* Default is CEE */
309 app.selector = !!(fwap->sel_field);
310 app.priority = fwap->user_prio_map;
311 err = dcb_setapp(dev, &app);
312 }
313
Anish Bhatt76bcb312014-06-19 21:37:12 -0700314 if (err)
315 dev_err(adap->pdev_dev,
316 "Failed DCB Set Application Priority: sel=%d, prot=%d, prio=%d, err=%d\n",
317 app.selector, app.protocol, app.priority, -err);
318
319 ap->user_prio_map = fwap->user_prio_map;
320 ap->sel_field = fwap->sel_field;
321 ap->protocolid = be16_to_cpu(fwap->protocolid);
322 dcb->msgs |= CXGB4_DCB_FW_APP_ID;
323 break;
324 }
325
326 default:
327 dev_err(adap->pdev_dev, "Unknown DCB update type received %x\n",
328 dcb_type);
329 break;
330 }
331}
332
333/* Data Center Bridging netlink operations.
334 */
335
336
337/* Get current DCB enabled/disabled state.
338 */
339static u8 cxgb4_getstate(struct net_device *dev)
340{
341 struct port_info *pi = netdev2pinfo(dev);
342
343 return pi->dcb.enabled;
344}
345
346/* Set DCB enabled/disabled.
347 */
348static u8 cxgb4_setstate(struct net_device *dev, u8 enabled)
349{
350 struct port_info *pi = netdev2pinfo(dev);
351
352 /* Firmware doesn't provide any mechanism to control the DCB state.
353 */
354 if (enabled != (pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED))
355 return 1;
356
357 return 0;
358}
359
360static void cxgb4_getpgtccfg(struct net_device *dev, int tc,
361 u8 *prio_type, u8 *pgid, u8 *bw_per,
362 u8 *up_tc_map, int local)
363{
364 struct fw_port_cmd pcmd;
365 struct port_info *pi = netdev2pinfo(dev);
366 struct adapter *adap = pi->adapter;
367 int err;
368
369 *prio_type = *pgid = *bw_per = *up_tc_map = 0;
370
371 if (local)
372 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
373 else
374 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
375
376 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
377 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
378 if (err != FW_PORT_DCB_CFG_SUCCESS) {
379 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
380 return;
381 }
382 *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf;
383
384 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
385 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
386 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
387 if (err != FW_PORT_DCB_CFG_SUCCESS) {
388 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
389 -err);
390 return;
391 }
392
393 *bw_per = pcmd.u.dcb.pgrate.pgrate[*pgid];
394 *up_tc_map = (1 << tc);
395
396 /* prio_type is link strict */
397 *prio_type = 0x2;
398}
399
400static void cxgb4_getpgtccfg_tx(struct net_device *dev, int tc,
401 u8 *prio_type, u8 *pgid, u8 *bw_per,
402 u8 *up_tc_map)
403{
404 return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 1);
405}
406
407
408static void cxgb4_getpgtccfg_rx(struct net_device *dev, int tc,
409 u8 *prio_type, u8 *pgid, u8 *bw_per,
410 u8 *up_tc_map)
411{
412 return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 0);
413}
414
415static void cxgb4_setpgtccfg_tx(struct net_device *dev, int tc,
416 u8 prio_type, u8 pgid, u8 bw_per,
417 u8 up_tc_map)
418{
419 struct fw_port_cmd pcmd;
420 struct port_info *pi = netdev2pinfo(dev);
421 struct adapter *adap = pi->adapter;
422 u32 _pgid;
423 int err;
424
425 if (pgid == DCB_ATTR_VALUE_UNDEFINED)
426 return;
427 if (bw_per == DCB_ATTR_VALUE_UNDEFINED)
428 return;
429
430 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
431 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
432
433 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
434 if (err != FW_PORT_DCB_CFG_SUCCESS) {
435 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
436 return;
437 }
438
439 _pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
440 _pgid &= ~(0xF << (tc * 4));
441 _pgid |= pgid << (tc * 4);
442 pcmd.u.dcb.pgid.pgid = cpu_to_be32(_pgid);
443
444 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
445
446 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
447 if (err != FW_PORT_DCB_CFG_SUCCESS) {
448 dev_err(adap->pdev_dev, "DCB write PGID failed with %d\n",
449 -err);
450 return;
451 }
452
453 memset(&pcmd, 0, sizeof(struct fw_port_cmd));
454
455 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
456 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
457
458 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
459 if (err != FW_PORT_DCB_CFG_SUCCESS) {
460 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
461 -err);
462 return;
463 }
464
465 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;
466
467 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
468 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
469 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
470
471 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
472 if (err != FW_PORT_DCB_CFG_SUCCESS)
473 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",
474 -err);
475}
476
477static void cxgb4_getpgbwgcfg(struct net_device *dev, int pgid, u8 *bw_per,
478 int local)
479{
480 struct fw_port_cmd pcmd;
481 struct port_info *pi = netdev2pinfo(dev);
482 struct adapter *adap = pi->adapter;
483 int err;
484
485 if (local)
486 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
487 else
488 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
489
490 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
491 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
492 if (err != FW_PORT_DCB_CFG_SUCCESS) {
493 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
494 -err);
Anish Bhatt10b00462014-08-07 16:14:03 -0700495 return;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700496 }
Anish Bhatt10b00462014-08-07 16:14:03 -0700497
498 *bw_per = pcmd.u.dcb.pgrate.pgrate[pgid];
Anish Bhatt76bcb312014-06-19 21:37:12 -0700499}
500
501static void cxgb4_getpgbwgcfg_tx(struct net_device *dev, int pgid, u8 *bw_per)
502{
503 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 1);
504}
505
506static void cxgb4_getpgbwgcfg_rx(struct net_device *dev, int pgid, u8 *bw_per)
507{
508 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 0);
509}
510
511static void cxgb4_setpgbwgcfg_tx(struct net_device *dev, int pgid,
512 u8 bw_per)
513{
514 struct fw_port_cmd pcmd;
515 struct port_info *pi = netdev2pinfo(dev);
516 struct adapter *adap = pi->adapter;
517 int err;
518
519 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
520 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
521
522 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
523 if (err != FW_PORT_DCB_CFG_SUCCESS) {
524 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
525 -err);
526 return;
527 }
528
529 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;
530
531 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
532 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
533 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
534
535 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
536
537 if (err != FW_PORT_DCB_CFG_SUCCESS)
538 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",
539 -err);
540}
541
542/* Return whether the specified Traffic Class Priority has Priority Pause
543 * Frames enabled.
544 */
545static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg)
546{
547 struct port_info *pi = netdev2pinfo(dev);
548 struct port_dcb_info *dcb = &pi->dcb;
549
550 if (dcb->state != CXGB4_DCB_STATE_FW_ALLSYNCED ||
551 priority >= CXGB4_MAX_PRIORITY)
552 *pfccfg = 0;
553 else
554 *pfccfg = (pi->dcb.pfcen >> priority) & 1;
555}
556
557/* Enable/disable Priority Pause Frames for the specified Traffic Class
558 * Priority.
559 */
560static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg)
561{
562 struct fw_port_cmd pcmd;
563 struct port_info *pi = netdev2pinfo(dev);
564 struct adapter *adap = pi->adapter;
565 int err;
566
567 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED ||
568 priority >= CXGB4_MAX_PRIORITY)
569 return;
570
571 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
572 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
573 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
574
575 pcmd.u.dcb.pfc.type = FW_PORT_DCB_TYPE_PFC;
Anish Bhatt5433ba32014-06-23 23:11:09 -0700576 pcmd.u.dcb.pfc.pfcen = pi->dcb.pfcen;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700577
578 if (pfccfg)
Anish Bhatt5433ba32014-06-23 23:11:09 -0700579 pcmd.u.dcb.pfc.pfcen |= (1 << priority);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700580 else
Anish Bhatt5433ba32014-06-23 23:11:09 -0700581 pcmd.u.dcb.pfc.pfcen &= (~(1 << priority));
Anish Bhatt76bcb312014-06-19 21:37:12 -0700582
583 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
584 if (err != FW_PORT_DCB_CFG_SUCCESS) {
585 dev_err(adap->pdev_dev, "DCB PFC write failed with %d\n", -err);
586 return;
587 }
588
Anish Bhatt5433ba32014-06-23 23:11:09 -0700589 pi->dcb.pfcen = pcmd.u.dcb.pfc.pfcen;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700590}
591
592static u8 cxgb4_setall(struct net_device *dev)
593{
594 return 0;
595}
596
597/* Return DCB capabilities.
598 */
599static u8 cxgb4_getcap(struct net_device *dev, int cap_id, u8 *caps)
600{
601 struct port_info *pi = netdev2pinfo(dev);
602
603 switch (cap_id) {
604 case DCB_CAP_ATTR_PG:
605 case DCB_CAP_ATTR_PFC:
606 *caps = true;
607 break;
608
609 case DCB_CAP_ATTR_PG_TCS:
610 /* 8 priorities for PG represented by bitmap */
611 *caps = 0x80;
612 break;
613
614 case DCB_CAP_ATTR_PFC_TCS:
615 /* 8 priorities for PFC represented by bitmap */
616 *caps = 0x80;
617 break;
618
619 case DCB_CAP_ATTR_GSP:
620 *caps = true;
621 break;
622
623 case DCB_CAP_ATTR_UP2TC:
624 case DCB_CAP_ATTR_BCN:
625 *caps = false;
626 break;
627
628 case DCB_CAP_ATTR_DCBX:
629 *caps = pi->dcb.supported;
630 break;
631
632 default:
633 *caps = false;
634 }
635
636 return 0;
637}
638
639/* Return the number of Traffic Classes for the indicated Traffic Class ID.
640 */
641static int cxgb4_getnumtcs(struct net_device *dev, int tcs_id, u8 *num)
642{
643 struct port_info *pi = netdev2pinfo(dev);
644
645 switch (tcs_id) {
646 case DCB_NUMTCS_ATTR_PG:
647 if (pi->dcb.msgs & CXGB4_DCB_FW_PGRATE)
648 *num = pi->dcb.pg_num_tcs_supported;
649 else
650 *num = 0x8;
651 break;
652
653 case DCB_NUMTCS_ATTR_PFC:
654 *num = 0x8;
655 break;
656
657 default:
658 return -EINVAL;
659 }
660
661 return 0;
662}
663
664/* Set the number of Traffic Classes supported for the indicated Traffic Class
665 * ID.
666 */
667static int cxgb4_setnumtcs(struct net_device *dev, int tcs_id, u8 num)
668{
669 /* Setting the number of Traffic Classes isn't supported.
670 */
671 return -ENOSYS;
672}
673
674/* Return whether Priority Flow Control is enabled. */
675static u8 cxgb4_getpfcstate(struct net_device *dev)
676{
677 struct port_info *pi = netdev2pinfo(dev);
678
679 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
680 return false;
681
682 return pi->dcb.pfcen != 0;
683}
684
685/* Enable/disable Priority Flow Control. */
686static void cxgb4_setpfcstate(struct net_device *dev, u8 state)
687{
688 /* We can't enable/disable Priority Flow Control but we also can't
689 * return an error ...
690 */
691}
692
693/* Return the Application User Priority Map associated with the specified
694 * Application ID.
695 */
696static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id,
697 int peer)
698{
699 struct port_info *pi = netdev2pinfo(dev);
700 struct adapter *adap = pi->adapter;
701 int i;
702
703 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
704 return 0;
705
706 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
707 struct fw_port_cmd pcmd;
708 int err;
709
710 if (peer)
711 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
712 else
713 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
714
715 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
716 pcmd.u.dcb.app_priority.idx = i;
717
718 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
719 if (err != FW_PORT_DCB_CFG_SUCCESS) {
720 dev_err(adap->pdev_dev, "DCB APP read failed with %d\n",
721 -err);
722 return err;
723 }
724 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id)
Anish Bhatt10b00462014-08-07 16:14:03 -0700725 if (pcmd.u.dcb.app_priority.sel_field == app_idtype)
726 return pcmd.u.dcb.app_priority.user_prio_map;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700727
728 /* exhausted app list */
729 if (!pcmd.u.dcb.app_priority.protocolid)
730 break;
731 }
732
733 return -EEXIST;
734}
735
736/* Return the Application User Priority Map associated with the specified
Anish Bhattc2659472014-07-16 22:32:39 -0700737 * Application ID.
Anish Bhatt76bcb312014-06-19 21:37:12 -0700738 */
Anish Bhattc2659472014-07-16 22:32:39 -0700739static int cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id)
Anish Bhatt76bcb312014-06-19 21:37:12 -0700740{
Anish Bhattc2659472014-07-16 22:32:39 -0700741 return __cxgb4_getapp(dev, app_idtype, app_id, 0);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700742}
743
Anish Bhattc2659472014-07-16 22:32:39 -0700744/* Write a new Application User Priority Map for the specified Application ID
Anish Bhatt76bcb312014-06-19 21:37:12 -0700745 */
Anish Bhatt10b00462014-08-07 16:14:03 -0700746static int __cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id,
747 u8 app_prio)
Anish Bhatt76bcb312014-06-19 21:37:12 -0700748{
749 struct fw_port_cmd pcmd;
750 struct port_info *pi = netdev2pinfo(dev);
751 struct adapter *adap = pi->adapter;
752 int i, err;
753
754
755 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
756 return -EINVAL;
757
758 /* DCB info gets thrown away on link up */
759 if (!netif_carrier_ok(dev))
760 return -ENOLINK;
761
Anish Bhatt76bcb312014-06-19 21:37:12 -0700762 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
763 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
764 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
765 pcmd.u.dcb.app_priority.idx = i;
766 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
767
768 if (err != FW_PORT_DCB_CFG_SUCCESS) {
769 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
770 -err);
771 return err;
772 }
773 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id) {
774 /* overwrite existing app table */
775 pcmd.u.dcb.app_priority.protocolid = 0;
776 break;
777 }
778 /* find first empty slot */
779 if (!pcmd.u.dcb.app_priority.protocolid)
780 break;
781 }
782
783 if (i == CXGB4_MAX_DCBX_APP_SUPPORTED) {
784 /* no empty slots available */
785 dev_err(adap->pdev_dev, "DCB app table full\n");
786 return -EBUSY;
787 }
788
789 /* write out new app table entry */
790 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);
791 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)
792 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY);
793
794 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
795 pcmd.u.dcb.app_priority.protocolid = cpu_to_be16(app_id);
796 pcmd.u.dcb.app_priority.sel_field = app_idtype;
797 pcmd.u.dcb.app_priority.user_prio_map = app_prio;
798 pcmd.u.dcb.app_priority.idx = i;
799
800 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
801 if (err != FW_PORT_DCB_CFG_SUCCESS) {
802 dev_err(adap->pdev_dev, "DCB app table write failed with %d\n",
803 -err);
804 return err;
805 }
806
807 return 0;
808}
809
Anish Bhatt10b00462014-08-07 16:14:03 -0700810/* Priority for CEE inside dcb_app is bitmask, with 0 being an invalid value */
811static int cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id,
812 u8 app_prio)
813{
814 int ret;
815 struct dcb_app app = {
816 .selector = app_idtype,
817 .protocol = app_id,
818 .priority = app_prio,
819 };
820
821 if (app_idtype != DCB_APP_IDTYPE_ETHTYPE &&
822 app_idtype != DCB_APP_IDTYPE_PORTNUM)
823 return -EINVAL;
824
825 /* Convert app_idtype to a format that firmware understands */
826 ret = __cxgb4_setapp(dev, app_idtype == DCB_APP_IDTYPE_ETHTYPE ?
827 app_idtype : 3, app_id, app_prio);
828 if (ret)
829 return ret;
830
831 return dcb_setapp(dev, &app);
832}
833
Anish Bhatt76bcb312014-06-19 21:37:12 -0700834/* Return whether IEEE Data Center Bridging has been negotiated.
835 */
836static inline int cxgb4_ieee_negotiation_complete(struct net_device *dev)
837{
838 struct port_info *pi = netdev2pinfo(dev);
839 struct port_dcb_info *dcb = &pi->dcb;
840
841 return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED &&
842 (dcb->supported & DCB_CAP_DCBX_VER_IEEE));
843}
844
845/* Fill in the Application User Priority Map associated with the
846 * specified Application.
Anish Bhatt10b00462014-08-07 16:14:03 -0700847 * Priority for IEEE dcb_app is an integer, with 0 being a valid value
Anish Bhatt76bcb312014-06-19 21:37:12 -0700848 */
849static int cxgb4_ieee_getapp(struct net_device *dev, struct dcb_app *app)
850{
851 int prio;
852
853 if (!cxgb4_ieee_negotiation_complete(dev))
854 return -EINVAL;
855 if (!(app->selector && app->protocol))
856 return -EINVAL;
857
Anish Bhatt10b00462014-08-07 16:14:03 -0700858 /* Try querying firmware first, use firmware format */
859 prio = __cxgb4_getapp(dev, app->selector - 1, app->protocol, 0);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700860
Anish Bhatt10b00462014-08-07 16:14:03 -0700861 if (prio < 0)
862 prio = dcb_ieee_getapp_mask(dev, app);
863
864 app->priority = ffs(prio) - 1;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700865 return 0;
866}
867
Anish Bhatt10b00462014-08-07 16:14:03 -0700868/* Write a new Application User Priority Map for the specified Application ID.
869 * Priority for IEEE dcb_app is an integer, with 0 being a valid value
870 */
Anish Bhatt76bcb312014-06-19 21:37:12 -0700871static int cxgb4_ieee_setapp(struct net_device *dev, struct dcb_app *app)
872{
Anish Bhatt10b00462014-08-07 16:14:03 -0700873 int ret;
874
Anish Bhatt76bcb312014-06-19 21:37:12 -0700875 if (!cxgb4_ieee_negotiation_complete(dev))
876 return -EINVAL;
Anish Bhatt10b00462014-08-07 16:14:03 -0700877 if (!(app->selector && app->protocol))
Anish Bhatt76bcb312014-06-19 21:37:12 -0700878 return -EINVAL;
879
Anish Bhatt10b00462014-08-07 16:14:03 -0700880 if (!(app->selector > IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
881 app->selector < IEEE_8021QAZ_APP_SEL_ANY))
882 return -EINVAL;
883
884 /* change selector to a format that firmware understands */
885 ret = __cxgb4_setapp(dev, app->selector - 1, app->protocol,
886 (1 << app->priority));
887 if (ret)
888 return ret;
889
890 return dcb_ieee_setapp(dev, app);
Anish Bhatt76bcb312014-06-19 21:37:12 -0700891}
892
893/* Return our DCBX parameters.
894 */
895static u8 cxgb4_getdcbx(struct net_device *dev)
896{
897 struct port_info *pi = netdev2pinfo(dev);
898
899 /* This is already set by cxgb4_set_dcb_caps, so just return it */
900 return pi->dcb.supported;
901}
902
903/* Set our DCBX parameters.
904 */
905static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request)
906{
907 struct port_info *pi = netdev2pinfo(dev);
908
909 /* Filter out requests which exceed our capabilities.
910 */
911 if ((dcb_request & (CXGB4_DCBX_FW_SUPPORT | CXGB4_DCBX_HOST_SUPPORT))
912 != dcb_request)
913 return 1;
914
Anish Bhatt10b00462014-08-07 16:14:03 -0700915 /* Can't enable DCB if we haven't successfully negotiated it.
916 */
917 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
Anish Bhatt76bcb312014-06-19 21:37:12 -0700918 return 1;
919
920 /* There's currently no mechanism to allow for the firmware DCBX
921 * negotiation to be changed from the Host Driver. If the caller
922 * requests exactly the same parameters that we already have then
923 * we'll allow them to be successfully "set" ...
924 */
925 if (dcb_request != pi->dcb.supported)
926 return 1;
927
928 pi->dcb.supported = dcb_request;
929 return 0;
930}
931
932static int cxgb4_getpeer_app(struct net_device *dev,
933 struct dcb_peer_app_info *info, u16 *app_count)
934{
935 struct fw_port_cmd pcmd;
936 struct port_info *pi = netdev2pinfo(dev);
937 struct adapter *adap = pi->adapter;
938 int i, err = 0;
939
940 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
941 return 1;
942
943 info->willing = 0;
944 info->error = 0;
945
946 *app_count = 0;
947 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
948 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
949 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
950 pcmd.u.dcb.app_priority.idx = *app_count;
951 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
952
953 if (err != FW_PORT_DCB_CFG_SUCCESS) {
954 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
955 -err);
956 return err;
957 }
958
959 /* find first empty slot */
960 if (!pcmd.u.dcb.app_priority.protocolid)
961 break;
962 }
963 *app_count = i;
964 return err;
965}
966
967static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table)
968{
969 struct fw_port_cmd pcmd;
970 struct port_info *pi = netdev2pinfo(dev);
971 struct adapter *adap = pi->adapter;
972 int i, err = 0;
973
974 if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED)
975 return 1;
976
977 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
978 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
979 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;
980 pcmd.u.dcb.app_priority.idx = i;
981 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
982
983 if (err != FW_PORT_DCB_CFG_SUCCESS) {
984 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",
985 -err);
986 return err;
987 }
988
989 /* find first empty slot */
990 if (!pcmd.u.dcb.app_priority.protocolid)
991 break;
992
993 table[i].selector = pcmd.u.dcb.app_priority.sel_field;
994 table[i].protocol =
995 be16_to_cpu(pcmd.u.dcb.app_priority.protocolid);
Anish Bhatt10b00462014-08-07 16:14:03 -0700996 table[i].priority =
997 ffs(pcmd.u.dcb.app_priority.user_prio_map) - 1;
Anish Bhatt76bcb312014-06-19 21:37:12 -0700998 }
999 return err;
1000}
1001
1002/* Return Priority Group information.
1003 */
1004static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg)
1005{
1006 struct fw_port_cmd pcmd;
1007 struct port_info *pi = netdev2pinfo(dev);
1008 struct adapter *adap = pi->adapter;
1009 u32 pgid;
1010 int i, err;
1011
1012 /* We're always "willing" -- the Switch Fabric always dictates the
1013 * DCBX parameters to us.
1014 */
1015 pg->willing = true;
1016
1017 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
1018 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
1019 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
1020 if (err != FW_PORT_DCB_CFG_SUCCESS) {
1021 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
1022 return err;
1023 }
1024 pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
1025
1026 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
1027 pg->prio_pg[i] = (pgid >> (i * 4)) & 0xF;
1028
1029 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
1030 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
1031 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
1032 if (err != FW_PORT_DCB_CFG_SUCCESS) {
1033 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
1034 -err);
1035 return err;
1036 }
1037
1038 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
1039 pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i];
1040
1041 return 0;
1042}
1043
1044/* Return Priority Flow Control information.
1045 */
1046static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc)
1047{
1048 struct port_info *pi = netdev2pinfo(dev);
1049
1050 cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported));
1051 pfc->pfc_en = pi->dcb.pfcen;
1052
1053 return 0;
1054}
1055
1056const struct dcbnl_rtnl_ops cxgb4_dcb_ops = {
1057 .ieee_getapp = cxgb4_ieee_getapp,
1058 .ieee_setapp = cxgb4_ieee_setapp,
1059
1060 /* CEE std */
1061 .getstate = cxgb4_getstate,
1062 .setstate = cxgb4_setstate,
1063 .getpgtccfgtx = cxgb4_getpgtccfg_tx,
1064 .getpgbwgcfgtx = cxgb4_getpgbwgcfg_tx,
1065 .getpgtccfgrx = cxgb4_getpgtccfg_rx,
1066 .getpgbwgcfgrx = cxgb4_getpgbwgcfg_rx,
1067 .setpgtccfgtx = cxgb4_setpgtccfg_tx,
1068 .setpgbwgcfgtx = cxgb4_setpgbwgcfg_tx,
1069 .setpfccfg = cxgb4_setpfccfg,
1070 .getpfccfg = cxgb4_getpfccfg,
1071 .setall = cxgb4_setall,
1072 .getcap = cxgb4_getcap,
1073 .getnumtcs = cxgb4_getnumtcs,
1074 .setnumtcs = cxgb4_setnumtcs,
1075 .getpfcstate = cxgb4_getpfcstate,
1076 .setpfcstate = cxgb4_setpfcstate,
1077 .getapp = cxgb4_getapp,
1078 .setapp = cxgb4_setapp,
1079
1080 /* DCBX configuration */
1081 .getdcbx = cxgb4_getdcbx,
1082 .setdcbx = cxgb4_setdcbx,
1083
1084 /* peer apps */
1085 .peer_getappinfo = cxgb4_getpeer_app,
1086 .peer_getapptable = cxgb4_getpeerapp_tbl,
1087
1088 /* CEE peer */
1089 .cee_peer_getpg = cxgb4_cee_peer_getpg,
1090 .cee_peer_getpfc = cxgb4_cee_peer_getpfc,
1091};