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