Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bnx2x_dcb.c
Go to the documentation of this file.
1 /* bnx2x_dcb.c: Broadcom Everest network driver.
2  *
3  * Copyright 2009-2012 Broadcom Corporation
4  *
5  * Unless you and Broadcom execute a separate written software license
6  * agreement governing use of this software, this software is licensed to you
7  * under the terms of the GNU General Public License version 2, available
8  * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
9  *
10  * Notwithstanding the above, under no circumstances may you combine this
11  * software in any way with any other Broadcom software provided under a
12  * license other than the GPL, without Broadcom's express prior written
13  * consent.
14  *
15  * Maintained by: Eilon Greenstein <[email protected]>
16  * Written by: Dmitry Kravkov
17  *
18  */
19 
20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 
22 #include <linux/netdevice.h>
23 #include <linux/types.h>
24 #include <linux/errno.h>
25 #include <linux/rtnetlink.h>
26 #include <net/dcbnl.h>
27 
28 #include "bnx2x.h"
29 #include "bnx2x_cmn.h"
30 #include "bnx2x_dcb.h"
31 
32 /* forward declarations of dcbx related functions */
33 static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
34 static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
35 static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
36 static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
37 static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
38  u32 *set_configuration_ets_pg,
39  u32 *pri_pg_tbl);
40 static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
41  u32 *pg_pri_orginal_spread,
42  struct pg_help_data *help_data);
43 static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
44  struct pg_help_data *help_data,
45  struct dcbx_ets_feature *ets,
46  u32 *pg_pri_orginal_spread);
47 static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
48  struct cos_help_data *cos_data,
49  u32 *pg_pri_orginal_spread,
50  struct dcbx_ets_feature *ets);
51 static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
53 
54 /* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */
55 static void bnx2x_read_data(struct bnx2x *bp, u32 *buff,
56  u32 addr, u32 len)
57 {
58  int i;
59  for (i = 0; i < len; i += 4, buff++)
60  *buff = REG_RD(bp, addr + i);
61 }
62 
63 static void bnx2x_write_data(struct bnx2x *bp, u32 *buff,
64  u32 addr, u32 len)
65 {
66  int i;
67  for (i = 0; i < len; i += 4, buff++)
68  REG_WR(bp, addr + i, *buff);
69 }
70 
71 static void bnx2x_pfc_set(struct bnx2x *bp)
72 {
73  struct bnx2x_nig_brb_pfc_port_params pfc_params = {0};
74  u32 pri_bit, val = 0;
75  int i;
76 
77  pfc_params.num_of_rx_cos_priority_mask =
78  bp->dcbx_port_params.ets.num_of_cos;
79 
80  /* Tx COS configuration */
81  for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++)
82  /*
83  * We configure only the pauseable bits (non pauseable aren't
84  * configured at all) it's done to avoid false pauses from
85  * network
86  */
87  pfc_params.rx_cos_priority_mask[i] =
88  bp->dcbx_port_params.ets.cos_params[i].pri_bitmask
90 
91  /*
92  * Rx COS configuration
93  * Changing PFC RX configuration .
94  * In RX COS0 will always be configured to lossless and COS1 to lossy
95  */
96  for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) {
97  pri_bit = 1 << i;
98 
99  if (!(pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp)))
100  val |= 1 << (i * 4);
101  }
102 
103  pfc_params.pkt_priority_to_cos = val;
104 
105  /* RX COS0 */
107  /* RX COS1 */
108  pfc_params.llfc_high_priority_classes = 0;
109 
111  bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED;
112  bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params);
114 }
115 
116 static void bnx2x_pfc_clear(struct bnx2x *bp)
117 {
118  struct bnx2x_nig_brb_pfc_port_params nig_params = {0};
119  nig_params.pause_enable = 1;
121  bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED;
122  bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params);
124 }
125 
126 static void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp,
127  struct dcbx_features *features,
128  u32 error)
129 {
130  u8 i = 0;
131  DP(NETIF_MSG_LINK, "local_mib.error %x\n", error);
132 
133  /* PG */
135  "local_mib.features.ets.enabled %x\n", features->ets.enabled);
136  for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++)
138  "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i,
139  DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i));
140  for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++)
142  "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i,
143  DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i));
144 
145  /* pfc */
146  DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pri_en_bitmap %x\n",
147  features->pfc.pri_en_bitmap);
148  DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pfc_caps %x\n",
149  features->pfc.pfc_caps);
150  DP(BNX2X_MSG_DCB, "dcbx_features.pfc.enabled %x\n",
151  features->pfc.enabled);
152 
153  DP(BNX2X_MSG_DCB, "dcbx_features.app.default_pri %x\n",
154  features->app.default_pri);
155  DP(BNX2X_MSG_DCB, "dcbx_features.app.tc_supported %x\n",
156  features->app.tc_supported);
157  DP(BNX2X_MSG_DCB, "dcbx_features.app.enabled %x\n",
158  features->app.enabled);
159  for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
161  "dcbx_features.app.app_pri_tbl[%x].app_id %x\n",
162  i, features->app.app_pri_tbl[i].app_id);
164  "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n",
165  i, features->app.app_pri_tbl[i].pri_bitmap);
167  "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n",
168  i, features->app.app_pri_tbl[i].appBitfield);
169  }
170 }
171 
172 static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp,
173  u8 pri_bitmap,
174  u8 llfc_traf_type)
175 {
177  u32 index = MAX_PFC_PRIORITIES - 1;
178  u32 pri_mask;
179  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
180 
181  /* Choose the highest priority */
182  while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) {
183  pri_mask = 1 << index;
184  if (GET_FLAGS(pri_bitmap, pri_mask))
185  pri = index ;
186  index--;
187  }
188 
189  if (pri < MAX_PFC_PRIORITIES)
190  ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri);
191 }
192 
193 static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
194  struct dcbx_app_priority_feature *app,
195  u32 error) {
196  u8 index;
197  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
198 
199  if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))
200  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_ERROR\n");
201 
203  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_MISMATCH\n");
204 
206  DP(BNX2X_MSG_DCB, "DCBX_REMOTE_APP_TLV_NOT_FOUND\n");
207  if (app->enabled &&
210 
211  bp->dcbx_port_params.app.enabled = true;
212 
213  for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
214  ttp[index] = 0;
215 
216  if (app->default_pri < MAX_PFC_PRIORITIES)
217  ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri;
218 
219  for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) {
221  app->app_pri_tbl;
222 
223  if (GET_FLAGS(entry[index].appBitfield,
224  DCBX_APP_SF_ETH_TYPE) &&
225  ETH_TYPE_FCOE == entry[index].app_id)
226  bnx2x_dcbx_get_ap_priority(bp,
227  entry[index].pri_bitmap,
229 
230  if (GET_FLAGS(entry[index].appBitfield,
231  DCBX_APP_SF_PORT) &&
232  TCP_PORT_ISCSI == entry[index].app_id)
233  bnx2x_dcbx_get_ap_priority(bp,
234  entry[index].pri_bitmap,
236  }
237  } else {
238  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_DISABLED\n");
239  bp->dcbx_port_params.app.enabled = false;
240  for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
241  ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY;
242  }
243 }
244 
245 static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
246  struct dcbx_ets_feature *ets,
247  u32 error) {
248  int i = 0;
249  u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0};
250  struct pg_help_data pg_help_data;
251  struct bnx2x_dcbx_cos_params *cos_params =
252  bp->dcbx_port_params.ets.cos_params;
253 
254  memset(&pg_help_data, 0, sizeof(struct pg_help_data));
255 
256 
257  if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR))
258  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ERROR\n");
259 
261  DP(BNX2X_MSG_DCB, "DCBX_REMOTE_ETS_TLV_NOT_FOUND\n");
262 
263  /* Clean up old settings of ets on COS */
264  for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) {
265  cos_params[i].pauseable = false;
266  cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID;
267  cos_params[i].bw_tbl = DCBX_INVALID_COS_BW;
268  cos_params[i].pri_bitmask = 0;
269  }
270 
271  if (bp->dcbx_port_params.app.enabled && ets->enabled &&
272  !GET_FLAGS(error,
274  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ENABLE\n");
275  bp->dcbx_port_params.ets.enabled = true;
276 
277  bnx2x_dcbx_get_ets_pri_pg_tbl(bp,
278  pg_pri_orginal_spread,
279  ets->pri_pg_tbl);
280 
281  bnx2x_dcbx_get_num_pg_traf_type(bp,
282  pg_pri_orginal_spread,
283  &pg_help_data);
284 
285  bnx2x_dcbx_fill_cos_params(bp, &pg_help_data,
286  ets, pg_pri_orginal_spread);
287 
288  } else {
289  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_DISABLED\n");
290  bp->dcbx_port_params.ets.enabled = false;
291  ets->pri_pg_tbl[0] = 0;
292 
293  for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++)
294  DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1);
295  }
296 }
297 
298 static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,
299  struct dcbx_pfc_feature *pfc, u32 error)
300 {
301 
302  if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR))
303  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_ERROR\n");
304 
306  DP(BNX2X_MSG_DCB, "DCBX_REMOTE_PFC_TLV_NOT_FOUND\n");
307  if (bp->dcbx_port_params.app.enabled && pfc->enabled &&
310  bp->dcbx_port_params.pfc.enabled = true;
311  bp->dcbx_port_params.pfc.priority_non_pauseable_mask =
312  ~(pfc->pri_en_bitmap);
313  } else {
314  DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_DISABLED\n");
315  bp->dcbx_port_params.pfc.enabled = false;
316  bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0;
317  }
318 }
319 
320 /* maps unmapped priorities to to the same COS as L2 */
321 static void bnx2x_dcbx_map_nw(struct bnx2x *bp)
322 {
323  int i;
324  u32 unmapped = (1 << MAX_PFC_PRIORITIES) - 1; /* all ones */
325  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
326  u32 nw_prio = 1 << ttp[LLFC_TRAFFIC_TYPE_NW];
327  struct bnx2x_dcbx_cos_params *cos_params =
328  bp->dcbx_port_params.ets.cos_params;
329 
330  /* get unmapped priorities by clearing mapped bits */
331  for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
332  unmapped &= ~(1 << ttp[i]);
333 
334  /* find cos for nw prio and extend it with unmapped */
335  for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params); i++) {
336  if (cos_params[i].pri_bitmask & nw_prio) {
337  /* extend the bitmask with unmapped */
339  "cos %d extended with 0x%08x\n", i, unmapped);
340  cos_params[i].pri_bitmask |= unmapped;
341  break;
342  }
343  }
344 }
345 
346 static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp,
347  struct dcbx_features *features,
348  u32 error)
349 {
350  bnx2x_dcbx_get_ap_feature(bp, &features->app, error);
351 
352  bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error);
353 
354  bnx2x_dcbx_get_ets_feature(bp, &features->ets, error);
355 
356  bnx2x_dcbx_map_nw(bp);
357 }
358 
359 #define DCBX_LOCAL_MIB_MAX_TRY_READ (100)
360 static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
361  u32 *base_mib_addr,
362  u32 offset,
363  int read_mib_type)
364 {
365  int max_try_read = 0;
366  u32 mib_size, prefix_seq_num, suffix_seq_num;
367  struct lldp_remote_mib *remote_mib ;
368  struct lldp_local_mib *local_mib;
369 
370 
371  switch (read_mib_type) {
372  case DCBX_READ_LOCAL_MIB:
373  mib_size = sizeof(struct lldp_local_mib);
374  break;
376  mib_size = sizeof(struct lldp_remote_mib);
377  break;
378  default:
379  return 1; /*error*/
380  }
381 
382  offset += BP_PORT(bp) * mib_size;
383 
384  do {
385  bnx2x_read_data(bp, base_mib_addr, offset, mib_size);
386 
387  max_try_read++;
388 
389  switch (read_mib_type) {
390  case DCBX_READ_LOCAL_MIB:
391  local_mib = (struct lldp_local_mib *) base_mib_addr;
392  prefix_seq_num = local_mib->prefix_seq_num;
393  suffix_seq_num = local_mib->suffix_seq_num;
394  break;
396  remote_mib = (struct lldp_remote_mib *) base_mib_addr;
397  prefix_seq_num = remote_mib->prefix_seq_num;
398  suffix_seq_num = remote_mib->suffix_seq_num;
399  break;
400  default:
401  return 1; /*error*/
402  }
403  } while ((prefix_seq_num != suffix_seq_num) &&
404  (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ));
405 
406  if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) {
407  BNX2X_ERR("MIB could not be read\n");
408  return 1;
409  }
410 
411  return 0;
412 }
413 
414 static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
415 {
416  if (bp->dcbx_port_params.pfc.enabled &&
418  /*
419  * 1. Fills up common PFC structures if required
420  * 2. Configure NIG, MAC and BRB via the elink
421  */
422  bnx2x_pfc_set(bp);
423  else
424  bnx2x_pfc_clear(bp);
425 }
426 
427 static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
428 {
429  struct bnx2x_func_state_params func_params = {NULL};
430 
431  func_params.f_obj = &bp->func_obj;
432  func_params.cmd = BNX2X_F_CMD_TX_STOP;
433 
434  DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n");
435  return bnx2x_func_state_change(bp, &func_params);
436 }
437 
438 static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
439 {
440  struct bnx2x_func_state_params func_params = {NULL};
442  &func_params.params.tx_start;
443 
444  func_params.f_obj = &bp->func_obj;
445  func_params.cmd = BNX2X_F_CMD_TX_START;
446 
447  bnx2x_dcbx_fw_struct(bp, tx_params);
448 
449  DP(BNX2X_MSG_DCB, "START TRAFFIC\n");
450  return bnx2x_func_state_change(bp, &func_params);
451 }
452 
453 static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
454 {
455  struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
456  int rc = 0;
457 
458  if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) {
459  BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos);
460  return;
461  }
462 
463  /* valid COS entries */
464  if (ets->num_of_cos == 1) /* no ETS */
465  return;
466 
467  /* sanity */
468  if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) &&
469  (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) ||
470  ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) &&
471  (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) {
472  BNX2X_ERR("all COS should have at least bw_limit or strict"
473  "ets->cos_params[0].strict= %x"
474  "ets->cos_params[0].bw_tbl= %x"
475  "ets->cos_params[1].strict= %x"
476  "ets->cos_params[1].bw_tbl= %x",
477  ets->cos_params[0].strict,
478  ets->cos_params[0].bw_tbl,
479  ets->cos_params[1].strict,
480  ets->cos_params[1].bw_tbl);
481  return;
482  }
483  /* If we join a group and there is bw_tbl and strict then bw rules */
484  if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) &&
485  (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) {
486  u32 bw_tbl_0 = ets->cos_params[0].bw_tbl;
487  u32 bw_tbl_1 = ets->cos_params[1].bw_tbl;
488  /* Do not allow 0-100 configuration
489  * since PBF does not support it
490  * force 1-99 instead
491  */
492  if (bw_tbl_0 == 0) {
493  bw_tbl_0 = 1;
494  bw_tbl_1 = 99;
495  } else if (bw_tbl_1 == 0) {
496  bw_tbl_1 = 1;
497  bw_tbl_0 = 99;
498  }
499 
500  bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1);
501  } else {
502  if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST)
503  rc = bnx2x_ets_strict(&bp->link_params, 0);
504  else if (ets->cos_params[1].strict
506  rc = bnx2x_ets_strict(&bp->link_params, 1);
507  if (rc)
508  BNX2X_ERR("update_ets_params failed\n");
509  }
510 }
511 
512 /*
513  * In E3B0 the configuration may have more than 2 COS.
514  */
515 static void bnx2x_dcbx_update_ets_config(struct bnx2x *bp)
516 {
517  struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
518  struct bnx2x_ets_params ets_params = { 0 };
519  u8 i;
520 
521  ets_params.num_of_cos = ets->num_of_cos;
522 
523  for (i = 0; i < ets->num_of_cos; i++) {
524  /* COS is SP */
525  if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) {
526  if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) {
527  BNX2X_ERR("COS can't be not BW and not SP\n");
528  return;
529  }
530 
531  ets_params.cos[i].state = bnx2x_cos_state_strict;
532  ets_params.cos[i].params.sp_params.pri =
533  ets->cos_params[i].strict;
534  } else { /* COS is BW */
535  if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) {
536  BNX2X_ERR("COS can't be not BW and not SP\n");
537  return;
538  }
539  ets_params.cos[i].state = bnx2x_cos_state_bw;
540  ets_params.cos[i].params.bw_params.bw =
541  (u8)ets->cos_params[i].bw_tbl;
542  }
543  }
544 
545  /* Configure the ETS in HW */
547  &ets_params)) {
548  BNX2X_ERR("bnx2x_ets_e3b0_config failed\n");
550  }
551 }
552 
553 static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
554 {
556 
557  if (!bp->dcbx_port_params.ets.enabled ||
559  return;
560 
561  if (CHIP_IS_E3B0(bp))
562  bnx2x_dcbx_update_ets_config(bp);
563  else
564  bnx2x_dcbx_2cos_limit_update_ets_config(bp);
565 }
566 
567 #ifdef BCM_DCBNL
568 static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)
569 {
570  struct lldp_remote_mib remote_mib = {0};
571  u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset);
572  int rc;
573 
574  DP(BNX2X_MSG_DCB, "dcbx_remote_mib_offset 0x%x\n",
575  dcbx_remote_mib_offset);
576 
577  if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) {
578  BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n");
579  return -EINVAL;
580  }
581 
582  rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset,
584 
585  if (rc) {
586  BNX2X_ERR("Faild to read remote mib from FW\n");
587  return rc;
588  }
589 
590  /* save features and flags */
591  bp->dcbx_remote_feat = remote_mib.features;
592  bp->dcbx_remote_flags = remote_mib.flags;
593  return 0;
594 }
595 #endif
596 
597 static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
598 {
599  struct lldp_local_mib local_mib = {0};
600  u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset);
601  int rc;
602 
603  DP(BNX2X_MSG_DCB, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset);
604 
605  if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) {
606  BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n");
607  return -EINVAL;
608  }
609 
610  rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset,
612 
613  if (rc) {
614  BNX2X_ERR("Faild to read local mib from FW\n");
615  return rc;
616  }
617 
618  /* save features and error */
619  bp->dcbx_local_feat = local_mib.features;
620  bp->dcbx_error = local_mib.error;
621  return 0;
622 }
623 
624 
625 #ifdef BCM_DCBNL
626 static inline
627 u8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent)
628 {
629  u8 pri;
630 
631  /* Choose the highest priority */
632  for (pri = MAX_PFC_PRIORITIES - 1; pri > 0; pri--)
633  if (ent->pri_bitmap & (1 << pri))
634  break;
635  return pri;
636 }
637 
638 static inline
639 u8 bnx2x_dcbx_dcbnl_app_idtype(struct dcbx_app_priority_entry *ent)
640 {
641  return ((ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) ==
642  DCBX_APP_SF_PORT) ? DCB_APP_IDTYPE_PORTNUM :
644 }
645 
646 int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall)
647 {
648  int i, err = 0;
649 
650  for (i = 0; i < DCBX_MAX_APP_PROTOCOL && err == 0; i++) {
651  struct dcbx_app_priority_entry *ent =
652  &bp->dcbx_local_feat.app.app_pri_tbl[i];
653 
654  if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {
655  u8 up = bnx2x_dcbx_dcbnl_app_up(ent);
656 
657  /* avoid invalid user-priority */
658  if (up) {
659  struct dcb_app app;
660  app.selector = bnx2x_dcbx_dcbnl_app_idtype(ent);
661  app.protocol = ent->app_id;
662  app.priority = delall ? 0 : up;
663  err = dcb_setapp(bp->dev, &app);
664  }
665  }
666  }
667  return err;
668 }
669 #endif
670 
671 static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
672 {
673  u8 prio, cos;
674  for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) {
675  for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) {
676  if (bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask
677  & (1 << prio)) {
678  bp->prio_to_cos[prio] = cos;
680  "tx_mapping %d --> %d\n", prio, cos);
681  }
682  }
683  }
684 
685  /* setup tc must be called under rtnl lock, but we can't take it here
686  * as we are handling an attetntion on a work queue which must be
687  * flushed at some rtnl-locked contexts (e.g. if down)
688  */
691 }
692 
694 {
695  switch (state) {
697  {
698  DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_NEG_RECEIVED\n");
699 #ifdef BCM_DCBNL
700 
704  bnx2x_dcbnl_update_applist(bp, true);
705 
706  /* Read rmeote mib if dcbx is in the FW */
707  if (bnx2x_dcbx_read_shmem_remote_mib(bp))
708  return;
709 #endif
710  /* Read neg results if dcbx is in the FW */
711  if (bnx2x_dcbx_read_shmem_neg_results(bp))
712  return;
713 
714  bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,
715  bp->dcbx_error);
716 
717  bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
718  bp->dcbx_error);
719 
720  /* mark DCBX result for PMF migration */
721  bnx2x_update_drv_flags(bp,
723  1);
724 #ifdef BCM_DCBNL
725  /*
726  * Add new app tlvs to dcbnl
727  */
728  bnx2x_dcbnl_update_applist(bp, false);
729 #endif
730  /*
731  * reconfigure the netdevice with the results of the new
732  * dcbx negotiation.
733  */
734  bnx2x_dcbx_update_tc_mapping(bp);
735 
736  /*
737  * allow other funtions to update their netdevices
738  * accordingly
739  */
740  if (IS_MF(bp))
741  bnx2x_link_sync_notify(bp);
742 
743  bnx2x_dcbx_stop_hw_tx(bp);
744 
745  return;
746  }
748  DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_PAUSED\n");
749  bnx2x_pfc_set_pfc(bp);
750 
751  bnx2x_dcbx_update_ets_params(bp);
752  bnx2x_dcbx_resume_hw_tx(bp);
753 
754  return;
756  DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_RELEASED\n");
758 #ifdef BCM_DCBNL
759  /*
760  * Send a notification for the new negotiated parameters
761  */
763 #endif
764  return;
765  default:
766  BNX2X_ERR("Unknown DCBX_STATE\n");
767  }
768 }
769 
770 #define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \
771  BP_PORT(bp)*sizeof(struct lldp_admin_mib))
772 
773 static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
774  u32 dcbx_lldp_params_offset)
775 {
776  struct lldp_admin_mib admin_mib;
777  u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0;
778  u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp);
779 
780  /*shortcuts*/
781  struct dcbx_features *af = &admin_mib.features;
783 
784  memset(&admin_mib, 0, sizeof(struct lldp_admin_mib));
785 
786  /* Read the data first */
787  bnx2x_read_data(bp, (u32 *)&admin_mib, offset,
788  sizeof(struct lldp_admin_mib));
789 
792  else
794 
796 
798  admin_mib.ver_cfg_flags |=
801 
802  af->ets.enabled = (u8)dp->admin_ets_enable;
803 
804  af->pfc.enabled = (u8)dp->admin_pfc_enable;
805 
806  /* FOR IEEE dp->admin_tc_supported_tx_enable */
808  SET_FLAGS(admin_mib.ver_cfg_flags,
810  else
811  RESET_FLAGS(admin_mib.ver_cfg_flags,
813  /* For IEEE admin_ets_recommendation_tx_enable */
814  if (dp->admin_pfc_tx_enable)
815  SET_FLAGS(admin_mib.ver_cfg_flags,
817  else
818  RESET_FLAGS(admin_mib.ver_cfg_flags,
820 
822  SET_FLAGS(admin_mib.ver_cfg_flags,
824  else
825  RESET_FLAGS(admin_mib.ver_cfg_flags,
827 
828  if (dp->admin_ets_willing)
830  else
832  /* For IEEE admin_ets_reco_valid */
833  if (dp->admin_pfc_willing)
835  else
837 
840  else
842 
843  for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) {
844  DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i,
846 
847  DP(BNX2X_MSG_DCB, "pg_bw_tbl[%d] = %02x\n",
848  i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i));
849  }
850 
851  for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
852  DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i,
854 
855  DP(BNX2X_MSG_DCB, "pri_pg_tbl[%d] = %02x\n",
856  i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i));
857  }
858 
859  /*For IEEE admin_recommendation_bw_precentage
860  *For IEEE admin_recommendation_ets_pg */
861  af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
862  for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
863  if (dp->admin_priority_app_table[i].valid) {
866  if ((ETH_TYPE_FCOE == table[i].app_id) &&
867  (TRAFFIC_TYPE_ETH == table[i].traffic_type))
868  traf_type = FCOE_APP_IDX;
869  else if ((TCP_PORT_ISCSI == table[i].app_id) &&
870  (TRAFFIC_TYPE_PORT == table[i].traffic_type))
871  traf_type = ISCSI_APP_IDX;
872  else
873  traf_type = other_traf_type++;
874 
875  af->app.app_pri_tbl[traf_type].app_id =
876  table[i].app_id;
877 
878  af->app.app_pri_tbl[traf_type].pri_bitmap =
879  (u8)(1 << table[i].priority);
880 
881  af->app.app_pri_tbl[traf_type].appBitfield =
882  (DCBX_APP_ENTRY_VALID);
883 
884  af->app.app_pri_tbl[traf_type].appBitfield |=
885  (TRAFFIC_TYPE_ETH == table[i].traffic_type) ?
886  DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT;
887  }
888  }
889 
890  af->app.default_pri = (u8)dp->admin_default_priority;
891 
892  }
893 
894  /* Write the data. */
895  bnx2x_write_data(bp, (u32 *)&admin_mib, offset,
896  sizeof(struct lldp_admin_mib));
897 
898 }
899 
900 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
901 {
902  if (!CHIP_IS_E1x(bp)) {
903  bp->dcb_state = dcb_on;
904  bp->dcbx_enabled = dcbx_enabled;
905  } else {
906  bp->dcb_state = false;
908  }
909  DP(BNX2X_MSG_DCB, "DCB state [%s:%s]\n",
910  dcb_on ? "ON" : "OFF",
911  dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" :
912  dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" :
913  dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ?
914  "on-chip with negotiation" : "invalid");
915 }
916 
918 {
919  bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */
920  bp->dcbx_config_params.admin_ets_willing = 1;
921  bp->dcbx_config_params.admin_pfc_willing = 1;
922  bp->dcbx_config_params.overwrite_settings = 1;
923  bp->dcbx_config_params.admin_ets_enable = 1;
924  bp->dcbx_config_params.admin_pfc_enable = 1;
925  bp->dcbx_config_params.admin_tc_supported_tx_enable = 1;
926  bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
927  bp->dcbx_config_params.admin_pfc_tx_enable = 1;
928  bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
929  bp->dcbx_config_params.admin_ets_reco_valid = 1;
930  bp->dcbx_config_params.admin_app_priority_willing = 1;
931  bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 100;
932  bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 0;
933  bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 0;
934  bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0;
935  bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0;
936  bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0;
937  bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0;
938  bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0;
939  bp->dcbx_config_params.admin_configuration_ets_pg[0] = 0;
940  bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0;
941  bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0;
942  bp->dcbx_config_params.admin_configuration_ets_pg[3] = 0;
943  bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0;
944  bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0;
945  bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0;
946  bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0;
947  bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 100;
948  bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 0;
949  bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 0;
950  bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0;
951  bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 0;
952  bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 0;
953  bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 0;
954  bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 0;
955  bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0;
956  bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1;
957  bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2;
958  bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3;
959  bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4;
960  bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5;
961  bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6;
962  bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7;
963  bp->dcbx_config_params.admin_pfc_bitmap = 0x0;
964  bp->dcbx_config_params.admin_priority_app_table[0].valid = 0;
965  bp->dcbx_config_params.admin_priority_app_table[1].valid = 0;
966  bp->dcbx_config_params.admin_priority_app_table[2].valid = 0;
967  bp->dcbx_config_params.admin_priority_app_table[3].valid = 0;
968  bp->dcbx_config_params.admin_default_priority = 0;
969 }
970 
971 void bnx2x_dcbx_init(struct bnx2x *bp, bool update_shmem)
972 {
973  u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE;
974 
975  /* only PMF can send ADMIN msg to MFW in old MFW versions */
976  if ((!bp->port.pmf) && (!(bp->flags & BC_SUPPORTS_DCBX_MSG_NON_PMF)))
977  return;
978 
979  if (bp->dcbx_enabled <= 0)
980  return;
981 
982  /* validate:
983  * chip of good for dcbx version,
984  * dcb is wanted
985  * shmem2 contains DCBX support fields
986  */
987  DP(BNX2X_MSG_DCB, "dcb_state %d bp->port.pmf %d\n",
988  bp->dcb_state, bp->port.pmf);
989 
990  if (bp->dcb_state == BNX2X_DCB_STATE_ON &&
991  SHMEM2_HAS(bp, dcbx_lldp_params_offset)) {
992  dcbx_lldp_params_offset =
993  SHMEM2_RD(bp, dcbx_lldp_params_offset);
994 
995  DP(BNX2X_MSG_DCB, "dcbx_lldp_params_offset 0x%x\n",
996  dcbx_lldp_params_offset);
997 
998  bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
999 
1000  if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
1001  /* need HW lock to avoid scenario of two drivers
1002  * writing in parallel to shmem
1003  */
1006  if (update_shmem)
1007  bnx2x_dcbx_admin_mib_updated_params(bp,
1008  dcbx_lldp_params_offset);
1009 
1010  /* Let HW start negotiation */
1011  bnx2x_fw_command(bp,
1013  /* release HW lock only after MFW acks that it finished
1014  * reading values from shmem
1015  */
1018  }
1019  }
1020 }
1021 static void
1022 bnx2x_dcbx_print_cos_params(struct bnx2x *bp,
1023  struct bnx2x_func_tx_start_params *pfc_fw_cfg)
1024 {
1025  u8 pri = 0;
1026  u8 cos = 0;
1027 
1028  DP(BNX2X_MSG_DCB,
1029  "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version);
1030  DP(BNX2X_MSG_DCB,
1031  "pdev->params.dcbx_port_params.pfc.priority_non_pauseable_mask %x\n",
1032  bp->dcbx_port_params.pfc.priority_non_pauseable_mask);
1033 
1034  for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) {
1035  DP(BNX2X_MSG_DCB,
1036  "pdev->params.dcbx_port_params.ets.cos_params[%d].pri_bitmask %x\n",
1037  cos, bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask);
1038 
1039  DP(BNX2X_MSG_DCB,
1040  "pdev->params.dcbx_port_params.ets.cos_params[%d].bw_tbl %x\n",
1041  cos, bp->dcbx_port_params.ets.cos_params[cos].bw_tbl);
1042 
1043  DP(BNX2X_MSG_DCB,
1044  "pdev->params.dcbx_port_params.ets.cos_params[%d].strict %x\n",
1045  cos, bp->dcbx_port_params.ets.cos_params[cos].strict);
1046 
1047  DP(BNX2X_MSG_DCB,
1048  "pdev->params.dcbx_port_params.ets.cos_params[%d].pauseable %x\n",
1049  cos, bp->dcbx_port_params.ets.cos_params[cos].pauseable);
1050  }
1051 
1052  for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
1053  DP(BNX2X_MSG_DCB,
1054  "pfc_fw_cfg->traffic_type_to_priority_cos[%d].priority %x\n",
1055  pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority);
1056 
1057  DP(BNX2X_MSG_DCB,
1058  "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n",
1059  pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos);
1060  }
1061 }
1062 
1063 /* fills help_data according to pg_info */
1064 static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
1065  u32 *pg_pri_orginal_spread,
1066  struct pg_help_data *help_data)
1067 {
1068  bool pg_found = false;
1069  u32 i, traf_type, add_traf_type, add_pg;
1070  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
1071  struct pg_entry_help_data *data = help_data->data; /*shotcut*/
1072 
1073  /* Set to invalid */
1074  for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
1075  data[i].pg = DCBX_ILLEGAL_PG;
1076 
1077  for (add_traf_type = 0;
1078  add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) {
1079  pg_found = false;
1080  if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) {
1081  add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]];
1082  for (traf_type = 0;
1083  traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX;
1084  traf_type++) {
1085  if (data[traf_type].pg == add_pg) {
1086  if (!(data[traf_type].pg_priority &
1087  (1 << ttp[add_traf_type])))
1088  data[traf_type].
1089  num_of_dif_pri++;
1090  data[traf_type].pg_priority |=
1091  (1 << ttp[add_traf_type]);
1092  pg_found = true;
1093  break;
1094  }
1095  }
1096  if (false == pg_found) {
1097  data[help_data->num_of_pg].pg = add_pg;
1098  data[help_data->num_of_pg].pg_priority =
1099  (1 << ttp[add_traf_type]);
1100  data[help_data->num_of_pg].num_of_dif_pri = 1;
1101  help_data->num_of_pg++;
1102  }
1103  }
1104  DP(BNX2X_MSG_DCB,
1105  "add_traf_type %d pg_found %s num_of_pg %d\n",
1106  add_traf_type, (false == pg_found) ? "NO" : "YES",
1107  help_data->num_of_pg);
1108  }
1109 }
1110 
1111 static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,
1112  struct cos_help_data *cos_data,
1113  u32 pri_join_mask)
1114 {
1115  /* Only one priority than only one COS */
1116  cos_data->data[0].pausable =
1117  IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
1118  cos_data->data[0].pri_join_mask = pri_join_mask;
1119  cos_data->data[0].cos_bw = 100;
1120  cos_data->num_of_cos = 1;
1121 }
1122 
1123 static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,
1124  struct cos_entry_help_data *data,
1125  u8 pg_bw)
1126 {
1127  if (data->cos_bw == DCBX_INVALID_COS_BW)
1128  data->cos_bw = pg_bw;
1129  else
1130  data->cos_bw += pg_bw;
1131 }
1132 
1133 static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
1134  struct cos_help_data *cos_data,
1135  u32 *pg_pri_orginal_spread,
1136  struct dcbx_ets_feature *ets)
1137 {
1138  u32 pri_tested = 0;
1139  u8 i = 0;
1140  u8 entry = 0;
1141  u8 pg_entry = 0;
1142  u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
1143 
1144  cos_data->data[0].pausable = true;
1145  cos_data->data[1].pausable = false;
1146  cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
1147 
1148  for (i = 0 ; i < num_of_pri ; i++) {
1149  pri_tested = 1 << bp->dcbx_port_params.
1150  app.traffic_type_priority[i];
1151 
1152  if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) {
1153  cos_data->data[1].pri_join_mask |= pri_tested;
1154  entry = 1;
1155  } else {
1156  cos_data->data[0].pri_join_mask |= pri_tested;
1157  entry = 0;
1158  }
1159  pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params.
1160  app.traffic_type_priority[i]];
1161  /* There can be only one strict pg */
1162  if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES)
1163  bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry],
1164  DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry));
1165  else
1166  /* If we join a group and one is strict
1167  * than the bw rulls */
1168  cos_data->data[entry].strict =
1170  }
1171  if ((0 == cos_data->data[0].pri_join_mask) &&
1172  (0 == cos_data->data[1].pri_join_mask))
1173  BNX2X_ERR("dcbx error: Both groups must have priorities\n");
1174 }
1175 
1176 
1177 #ifndef POWER_OF_2
1178 #define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))
1179 #endif
1180 
1181 static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp,
1182  struct pg_help_data *pg_help_data,
1183  struct cos_help_data *cos_data,
1184  u32 pri_join_mask,
1186 {
1187  u8 i = 0;
1188  u32 pri_tested = 0;
1189  u32 pri_mask_without_pri = 0;
1190  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
1191  /*debug*/
1192  if (num_of_dif_pri == 1) {
1193  bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask);
1194  return;
1195  }
1196  /* single priority group */
1197  if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
1198  /* If there are both pauseable and non-pauseable priorities,
1199  * the pauseable priorities go to the first queue and
1200  * the non-pauseable priorities go to the second queue.
1201  */
1202  if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
1203  /* Pauseable */
1204  cos_data->data[0].pausable = true;
1205  /* Non pauseable.*/
1206  cos_data->data[1].pausable = false;
1207 
1208  if (2 == num_of_dif_pri) {
1209  cos_data->data[0].cos_bw = 50;
1210  cos_data->data[1].cos_bw = 50;
1211  }
1212 
1213  if (3 == num_of_dif_pri) {
1215  pri_join_mask))) {
1216  cos_data->data[0].cos_bw = 33;
1217  cos_data->data[1].cos_bw = 67;
1218  } else {
1219  cos_data->data[0].cos_bw = 67;
1220  cos_data->data[1].cos_bw = 33;
1221  }
1222  }
1223 
1224  } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) {
1225  /* If there are only pauseable priorities,
1226  * then one/two priorities go to the first queue
1227  * and one priority goes to the second queue.
1228  */
1229  if (2 == num_of_dif_pri) {
1230  cos_data->data[0].cos_bw = 50;
1231  cos_data->data[1].cos_bw = 50;
1232  } else {
1233  cos_data->data[0].cos_bw = 67;
1234  cos_data->data[1].cos_bw = 33;
1235  }
1236  cos_data->data[1].pausable = true;
1237  cos_data->data[0].pausable = true;
1238  /* All priorities except FCOE */
1239  cos_data->data[0].pri_join_mask = (pri_join_mask &
1240  ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE])));
1241  /* Only FCOE priority.*/
1242  cos_data->data[1].pri_join_mask =
1243  (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]);
1244  } else
1245  /* If there are only non-pauseable priorities,
1246  * they will all go to the same queue.
1247  */
1248  bnx2x_dcbx_ets_disabled_entry_data(bp,
1249  cos_data, pri_join_mask);
1250  } else {
1251  /* priority group which is not BW limited (PG#15):*/
1252  if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
1253  /* If there are both pauseable and non-pauseable
1254  * priorities, the pauseable priorities go to the first
1255  * queue and the non-pauseable priorities
1256  * go to the second queue.
1257  */
1258  if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) >
1259  DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) {
1260  cos_data->data[0].strict =
1262  cos_data->data[1].strict =
1265  } else {
1266  cos_data->data[0].strict =
1269  cos_data->data[1].strict =
1271  }
1272  /* Pauseable */
1273  cos_data->data[0].pausable = true;
1274  /* Non pause-able.*/
1275  cos_data->data[1].pausable = false;
1276  } else {
1277  /* If there are only pauseable priorities or
1278  * only non-pauseable,* the lower priorities go
1279  * to the first queue and the higherpriorities go
1280  * to the second queue.
1281  */
1282  cos_data->data[0].pausable =
1283  cos_data->data[1].pausable =
1284  IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
1285 
1286  for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) {
1287  pri_tested = 1 << bp->dcbx_port_params.
1288  app.traffic_type_priority[i];
1289  /* Remove priority tested */
1290  pri_mask_without_pri =
1291  (pri_join_mask & ((u8)(~pri_tested)));
1292  if (pri_mask_without_pri < pri_tested)
1293  break;
1294  }
1295 
1296  if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX)
1297  BNX2X_ERR("Invalid value for pri_join_mask - could not find a priority\n");
1298 
1299  cos_data->data[0].pri_join_mask = pri_mask_without_pri;
1300  cos_data->data[1].pri_join_mask = pri_tested;
1301  /* Both queues are strict priority,
1302  * and that with the highest priority
1303  * gets the highest strict priority in the arbiter.
1304  */
1305  cos_data->data[0].strict =
1308  cos_data->data[1].strict =
1310  }
1311  }
1312 }
1313 
1314 static void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
1315  struct bnx2x *bp,
1316  struct pg_help_data *pg_help_data,
1317  struct dcbx_ets_feature *ets,
1318  struct cos_help_data *cos_data,
1319  u32 *pg_pri_orginal_spread,
1320  u32 pri_join_mask,
1322 {
1323  u8 i = 0;
1324  u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 };
1325 
1326  /* If there are both pauseable and non-pauseable priorities,
1327  * the pauseable priorities go to the first queue and
1328  * the non-pauseable priorities go to the second queue.
1329  */
1330  if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
1332  pg_help_data->data[0].pg_priority) ||
1334  pg_help_data->data[1].pg_priority)) {
1335  /* If one PG contains both pauseable and
1336  * non-pauseable priorities then ETS is disabled.
1337  */
1338  bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data,
1339  pg_pri_orginal_spread, ets);
1340  bp->dcbx_port_params.ets.enabled = false;
1341  return;
1342  }
1343 
1344  /* Pauseable */
1345  cos_data->data[0].pausable = true;
1346  /* Non pauseable. */
1347  cos_data->data[1].pausable = false;
1349  pg_help_data->data[0].pg_priority)) {
1350  /* 0 is pauseable */
1351  cos_data->data[0].pri_join_mask =
1352  pg_help_data->data[0].pg_priority;
1353  pg[0] = pg_help_data->data[0].pg;
1354  cos_data->data[1].pri_join_mask =
1355  pg_help_data->data[1].pg_priority;
1356  pg[1] = pg_help_data->data[1].pg;
1357  } else {/* 1 is pauseable */
1358  cos_data->data[0].pri_join_mask =
1359  pg_help_data->data[1].pg_priority;
1360  pg[0] = pg_help_data->data[1].pg;
1361  cos_data->data[1].pri_join_mask =
1362  pg_help_data->data[0].pg_priority;
1363  pg[1] = pg_help_data->data[0].pg;
1364  }
1365  } else {
1366  /* If there are only pauseable priorities or
1367  * only non-pauseable, each PG goes to a queue.
1368  */
1369  cos_data->data[0].pausable = cos_data->data[1].pausable =
1370  IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
1371  cos_data->data[0].pri_join_mask =
1372  pg_help_data->data[0].pg_priority;
1373  pg[0] = pg_help_data->data[0].pg;
1374  cos_data->data[1].pri_join_mask =
1375  pg_help_data->data[1].pg_priority;
1376  pg[1] = pg_help_data->data[1].pg;
1377  }
1378 
1379  /* There can be only one strict pg */
1380  for (i = 0 ; i < ARRAY_SIZE(pg); i++) {
1381  if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES)
1382  cos_data->data[i].cos_bw =
1383  DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]);
1384  else
1385  cos_data->data[i].strict =
1387  }
1388 }
1389 
1390 static int bnx2x_dcbx_join_pgs(
1391  struct bnx2x *bp,
1392  struct dcbx_ets_feature *ets,
1393  struct pg_help_data *pg_help_data,
1394  u8 required_num_of_pg)
1395 {
1396  u8 entry_joined = pg_help_data->num_of_pg - 1;
1397  u8 entry_removed = entry_joined + 1;
1398  u8 pg_joined = 0;
1399 
1400  if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data)
1401  <= pg_help_data->num_of_pg) {
1402 
1403  BNX2X_ERR("required_num_of_pg can't be zero\n");
1404  return -EINVAL;
1405  }
1406 
1407  while (required_num_of_pg < pg_help_data->num_of_pg) {
1408  entry_joined = pg_help_data->num_of_pg - 2;
1409  entry_removed = entry_joined + 1;
1410  /* protect index */
1411  entry_removed %= ARRAY_SIZE(pg_help_data->data);
1412 
1413  pg_help_data->data[entry_joined].pg_priority |=
1414  pg_help_data->data[entry_removed].pg_priority;
1415 
1416  pg_help_data->data[entry_joined].num_of_dif_pri +=
1417  pg_help_data->data[entry_removed].num_of_dif_pri;
1418 
1419  if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG ||
1420  pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG)
1421  /* Entries joined strict priority rules */
1422  pg_help_data->data[entry_joined].pg =
1424  else {
1425  /* Entries can be joined join BW */
1426  pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl,
1427  pg_help_data->data[entry_joined].pg) +
1429  pg_help_data->data[entry_removed].pg);
1430 
1432  pg_help_data->data[entry_joined].pg, pg_joined);
1433  }
1434  /* Joined the entries */
1435  pg_help_data->num_of_pg--;
1436  }
1437 
1438  return 0;
1439 }
1440 
1441 static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
1442  struct bnx2x *bp,
1443  struct pg_help_data *pg_help_data,
1444  struct dcbx_ets_feature *ets,
1445  struct cos_help_data *cos_data,
1446  u32 *pg_pri_orginal_spread,
1447  u32 pri_join_mask,
1448  u8 num_of_dif_pri)
1449 {
1450  u8 i = 0;
1451  u32 pri_tested = 0;
1452  u8 entry = 0;
1453  u8 pg_entry = 0;
1454  bool b_found_strict = false;
1455  u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
1456 
1457  cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
1458  /* If there are both pauseable and non-pauseable priorities,
1459  * the pauseable priorities go to the first queue and the
1460  * non-pauseable priorities go to the second queue.
1461  */
1462  if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask))
1463  bnx2x_dcbx_separate_pauseable_from_non(bp,
1464  cos_data, pg_pri_orginal_spread, ets);
1465  else {
1466  /* If two BW-limited PG-s were combined to one queue,
1467  * the BW is their sum.
1468  *
1469  * If there are only pauseable priorities or only non-pauseable,
1470  * and there are both BW-limited and non-BW-limited PG-s,
1471  * the BW-limited PG/s go to one queue and the non-BW-limited
1472  * PG/s go to the second queue.
1473  *
1474  * If there are only pauseable priorities or only non-pauseable
1475  * and all are BW limited, then two priorities go to the first
1476  * queue and one priority goes to the second queue.
1477  *
1478  * We will join this two cases:
1479  * if one is BW limited it will go to the secoend queue
1480  * otherwise the last priority will get it
1481  */
1482 
1483  cos_data->data[0].pausable = cos_data->data[1].pausable =
1484  IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
1485 
1486  for (i = 0 ; i < num_of_pri; i++) {
1487  pri_tested = 1 << bp->dcbx_port_params.
1488  app.traffic_type_priority[i];
1489  pg_entry = (u8)pg_pri_orginal_spread[bp->
1490  dcbx_port_params.app.traffic_type_priority[i]];
1491 
1492  if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) {
1493  entry = 0;
1494 
1495  if (i == (num_of_pri-1) &&
1496  false == b_found_strict)
1497  /* last entry will be handled separately
1498  * If no priority is strict than last
1499  * enty goes to last queue.*/
1500  entry = 1;
1501  cos_data->data[entry].pri_join_mask |=
1502  pri_tested;
1503  bnx2x_dcbx_add_to_cos_bw(bp,
1504  &cos_data->data[entry],
1506  pg_entry));
1507  } else {
1508  b_found_strict = true;
1509  cos_data->data[1].pri_join_mask |= pri_tested;
1510  /* If we join a group and one is strict
1511  * than the bw rulls */
1512  cos_data->data[1].strict =
1514  }
1515  }
1516  }
1517 }
1518 
1519 
1520 static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,
1521  struct pg_help_data *help_data,
1522  struct dcbx_ets_feature *ets,
1523  struct cos_help_data *cos_data,
1524  u32 *pg_pri_orginal_spread,
1525  u32 pri_join_mask,
1526  u8 num_of_dif_pri)
1527 {
1528 
1529  /* default E2 settings */
1530  cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2;
1531 
1532  switch (help_data->num_of_pg) {
1533  case 1:
1534  bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(
1535  bp,
1536  help_data,
1537  cos_data,
1538  pri_join_mask,
1539  num_of_dif_pri);
1540  break;
1541  case 2:
1542  bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
1543  bp,
1544  help_data,
1545  ets,
1546  cos_data,
1547  pg_pri_orginal_spread,
1548  pri_join_mask,
1549  num_of_dif_pri);
1550  break;
1551 
1552  case 3:
1553  bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
1554  bp,
1555  help_data,
1556  ets,
1557  cos_data,
1558  pg_pri_orginal_spread,
1559  pri_join_mask,
1560  num_of_dif_pri);
1561  break;
1562  default:
1563  BNX2X_ERR("Wrong pg_help_data.num_of_pg\n");
1564  bnx2x_dcbx_ets_disabled_entry_data(bp,
1565  cos_data, pri_join_mask);
1566  }
1567 }
1568 
1569 static int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp,
1570  struct cos_help_data *cos_data,
1571  u8 entry,
1572  u8 num_spread_of_entries,
1573  u8 strict_app_pris)
1574 {
1575  u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST;
1576  u8 num_of_app_pri = MAX_PFC_PRIORITIES;
1577  u8 app_pri_bit = 0;
1578 
1579  while (num_spread_of_entries && num_of_app_pri > 0) {
1580  app_pri_bit = 1 << (num_of_app_pri - 1);
1581  if (app_pri_bit & strict_app_pris) {
1582  struct cos_entry_help_data *data = &cos_data->
1583  data[entry];
1584  num_spread_of_entries--;
1585  if (num_spread_of_entries == 0) {
1586  /* last entry needed put all the entries left */
1587  data->cos_bw = DCBX_INVALID_COS_BW;
1588  data->strict = strict_pri;
1589  data->pri_join_mask = strict_app_pris;
1591  data->pri_join_mask);
1592  } else {
1593  strict_app_pris &= ~app_pri_bit;
1594 
1595  data->cos_bw = DCBX_INVALID_COS_BW;
1596  data->strict = strict_pri;
1597  data->pri_join_mask = app_pri_bit;
1599  data->pri_join_mask);
1600  }
1601 
1602  strict_pri =
1604  entry++;
1605  }
1606 
1607  num_of_app_pri--;
1608  }
1609 
1610  if (num_spread_of_entries) {
1611  BNX2X_ERR("Didn't succeed to spread strict priorities\n");
1612  return -EINVAL;
1613  }
1614 
1615  return 0;
1616 }
1617 
1618 static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp,
1619  struct cos_help_data *cos_data,
1620  u8 entry,
1621  u8 num_spread_of_entries,
1622  u8 strict_app_pris)
1623 {
1624 
1625  if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry,
1626  num_spread_of_entries,
1627  strict_app_pris)) {
1628  struct cos_entry_help_data *data = &cos_data->
1629  data[entry];
1630  /* Fill BW entry */
1631  data->cos_bw = DCBX_INVALID_COS_BW;
1633  data->pri_join_mask = strict_app_pris;
1635  data->pri_join_mask);
1636  return 1;
1637  }
1638 
1639  return num_spread_of_entries;
1640 }
1641 
1642 static void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp,
1643  struct pg_help_data *help_data,
1644  struct dcbx_ets_feature *ets,
1645  struct cos_help_data *cos_data,
1646  u32 pri_join_mask)
1647 
1648 {
1649  u8 need_num_of_entries = 0;
1650  u8 i = 0;
1651  u8 entry = 0;
1652 
1653  /*
1654  * if the number of requested PG-s in CEE is greater than 3
1655  * then the results are not determined since this is a violation
1656  * of the standard.
1657  */
1658  if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) {
1659  if (bnx2x_dcbx_join_pgs(bp, ets, help_data,
1661  BNX2X_ERR("Unable to reduce the number of PGs - we will disables ETS\n");
1662  bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data,
1663  pri_join_mask);
1664  return;
1665  }
1666  }
1667 
1668  for (i = 0 ; i < help_data->num_of_pg; i++) {
1669  struct pg_entry_help_data *pg = &help_data->data[i];
1670  if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
1671  struct cos_entry_help_data *data = &cos_data->
1672  data[entry];
1673  /* Fill BW entry */
1674  data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg);
1676  data->pri_join_mask = pg->pg_priority;
1678  data->pri_join_mask);
1679 
1680  entry++;
1681  } else {
1682  need_num_of_entries = min_t(u8,
1683  (u8)pg->num_of_dif_pri,
1685  help_data->num_of_pg + 1);
1686  /*
1687  * If there are still VOQ-s which have no associated PG,
1688  * then associate these VOQ-s to PG15. These PG-s will
1689  * be used for SP between priorities on PG15.
1690  */
1691  entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data,
1692  entry, need_num_of_entries, pg->pg_priority);
1693  }
1694  }
1695 
1696  /* the entry will represent the number of COSes used */
1697  cos_data->num_of_cos = entry;
1698 }
1699 static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
1700  struct pg_help_data *help_data,
1701  struct dcbx_ets_feature *ets,
1702  u32 *pg_pri_orginal_spread)
1703 {
1704  struct cos_help_data cos_data;
1705  u8 i = 0;
1706  u32 pri_join_mask = 0;
1707  u8 num_of_dif_pri = 0;
1708 
1709  memset(&cos_data, 0, sizeof(cos_data));
1710 
1711  /* Validate the pg value */
1712  for (i = 0; i < help_data->num_of_pg ; i++) {
1713  if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&
1714  DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)
1715  BNX2X_ERR("Invalid pg[%d] data %x\n", i,
1716  help_data->data[i].pg);
1717  pri_join_mask |= help_data->data[i].pg_priority;
1718  num_of_dif_pri += help_data->data[i].num_of_dif_pri;
1719  }
1720 
1721  /* defaults */
1722  cos_data.num_of_cos = 1;
1723  for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) {
1724  cos_data.data[i].pri_join_mask = 0;
1725  cos_data.data[i].pausable = false;
1726  cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID;
1727  cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;
1728  }
1729 
1730  if (CHIP_IS_E3B0(bp))
1731  bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets,
1732  &cos_data, pri_join_mask);
1733  else /* E2 + E3A0 */
1734  bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp,
1735  help_data, ets,
1736  &cos_data,
1737  pg_pri_orginal_spread,
1738  pri_join_mask,
1739  num_of_dif_pri);
1740 
1741  for (i = 0; i < cos_data.num_of_cos ; i++) {
1742  struct bnx2x_dcbx_cos_params *p =
1743  &bp->dcbx_port_params.ets.cos_params[i];
1744 
1745  p->strict = cos_data.data[i].strict;
1746  p->bw_tbl = cos_data.data[i].cos_bw;
1747  p->pri_bitmask = cos_data.data[i].pri_join_mask;
1748  p->pauseable = cos_data.data[i].pausable;
1749 
1750  /* sanity */
1751  if (p->bw_tbl != DCBX_INVALID_COS_BW ||
1753  if (p->pri_bitmask == 0)
1754  BNX2X_ERR("Invalid pri_bitmask for %d\n", i);
1755 
1756  if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) {
1757 
1758  if (p->pauseable &&
1760  p->pri_bitmask) != 0)
1761  BNX2X_ERR("Inconsistent config for pausable COS %d\n",
1762  i);
1763 
1764  if (!p->pauseable &&
1766  p->pri_bitmask) != 0)
1767  BNX2X_ERR("Inconsistent config for nonpausable COS %d\n",
1768  i);
1769  }
1770  }
1771 
1772  if (p->pauseable)
1773  DP(BNX2X_MSG_DCB, "COS %d PAUSABLE prijoinmask 0x%x\n",
1774  i, cos_data.data[i].pri_join_mask);
1775  else
1776  DP(BNX2X_MSG_DCB,
1777  "COS %d NONPAUSABLE prijoinmask 0x%x\n",
1778  i, cos_data.data[i].pri_join_mask);
1779  }
1780 
1781  bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ;
1782 }
1783 
1784 static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
1785  u32 *set_configuration_ets_pg,
1786  u32 *pri_pg_tbl)
1787 {
1788  int i;
1789 
1790  for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
1791  set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i);
1792 
1793  DP(BNX2X_MSG_DCB, "set_configuration_ets_pg[%d] = 0x%x\n",
1794  i, set_configuration_ets_pg[i]);
1795  }
1796 }
1797 
1798 static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
1799  struct bnx2x_func_tx_start_params *pfc_fw_cfg)
1800 {
1801  u16 pri_bit = 0;
1802  u8 cos = 0, pri = 0;
1803  struct priority_cos *tt2cos;
1804  u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
1805 
1806  memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg));
1807 
1808  /* to disable DCB - the structure must be zeroed */
1810  return;
1811 
1812  /*shortcut*/
1813  tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos;
1814 
1815  /* Fw version should be incremented each update */
1816  pfc_fw_cfg->dcb_version = ++bp->dcb_version;
1817  pfc_fw_cfg->dcb_enabled = 1;
1818 
1819  /* Fill priority parameters */
1820  for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
1821  tt2cos[pri].priority = ttp[pri];
1822  pri_bit = 1 << tt2cos[pri].priority;
1823 
1824  /* Fill COS parameters based on COS calculated to
1825  * make it more general for future use */
1826  for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++)
1827  if (bp->dcbx_port_params.ets.cos_params[cos].
1828  pri_bitmask & pri_bit)
1829  tt2cos[pri].cos = cos;
1830  }
1831 
1832  /* we never want the FW to add a 0 vlan tag */
1833  pfc_fw_cfg->dont_add_pri_0_en = 1;
1834 
1835  bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg);
1836 }
1837 
1839 {
1840  /* if we need to syncronize DCBX result from prev PMF
1841  * read it from shmem and update bp and netdev accordingly
1842  */
1843  if (SHMEM2_HAS(bp, drv_flags) &&
1844  GET_FLAGS(SHMEM2_RD(bp, drv_flags), 1 << DRV_FLAGS_DCB_CONFIGURED)) {
1845  /* Read neg results if dcbx is in the FW */
1846  if (bnx2x_dcbx_read_shmem_neg_results(bp))
1847  return;
1848 
1849  bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,
1850  bp->dcbx_error);
1851  bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
1852  bp->dcbx_error);
1853 #ifdef BCM_DCBNL
1854  /*
1855  * Add new app tlvs to dcbnl
1856  */
1857  bnx2x_dcbnl_update_applist(bp, false);
1858  /*
1859  * Send a notification for the new negotiated parameters
1860  */
1862 #endif
1863  /*
1864  * reconfigure the netdevice with the results of the new
1865  * dcbx negotiation.
1866  */
1867  bnx2x_dcbx_update_tc_mapping(bp);
1868 
1869  }
1870 }
1871 
1872 /* DCB netlink */
1873 #ifdef BCM_DCBNL
1874 
1875 #define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \
1876  DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC)
1877 
1878 static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp)
1879 {
1880  /* validate dcbnl call that may change HW state:
1881  * DCB is on and DCBX mode was SUCCESSFULLY set by the user.
1882  */
1883  return bp->dcb_state && bp->dcbx_mode_uset;
1884 }
1885 
1886 static u8 bnx2x_dcbnl_get_state(struct net_device *netdev)
1887 {
1888  struct bnx2x *bp = netdev_priv(netdev);
1889  DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcb_state);
1890  return bp->dcb_state;
1891 }
1892 
1893 static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)
1894 {
1895  struct bnx2x *bp = netdev_priv(netdev);
1896  DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");
1897 
1898  bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
1899  return 0;
1900 }
1901 
1902 static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev,
1903  u8 *perm_addr)
1904 {
1905  struct bnx2x *bp = netdev_priv(netdev);
1906  DP(BNX2X_MSG_DCB, "GET-PERM-ADDR\n");
1907 
1908  /* first the HW mac address */
1909  memcpy(perm_addr, netdev->dev_addr, netdev->addr_len);
1910 
1911 #ifdef BCM_CNIC
1912  /* second SAN address */
1913  memcpy(perm_addr+netdev->addr_len, bp->fip_mac, netdev->addr_len);
1914 #endif
1915 }
1916 
1917 static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio,
1918  u8 prio_type, u8 pgid, u8 bw_pct,
1919  u8 up_map)
1920 {
1921  struct bnx2x *bp = netdev_priv(netdev);
1922 
1923  DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, pgid);
1924  if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
1925  return;
1926 
1940  bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid;
1941  bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
1942 }
1943 
1944 static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev,
1945  int pgid, u8 bw_pct)
1946 {
1947  struct bnx2x *bp = netdev_priv(netdev);
1948  DP(BNX2X_MSG_DCB, "pgid[%d] = %d\n", pgid, bw_pct);
1949 
1950  if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
1951  return;
1952 
1953  bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct;
1954  bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
1955 }
1956 
1957 static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio,
1958  u8 prio_type, u8 pgid, u8 bw_pct,
1959  u8 up_map)
1960 {
1961  struct bnx2x *bp = netdev_priv(netdev);
1962  DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n");
1963 }
1964 
1965 static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev,
1966  int pgid, u8 bw_pct)
1967 {
1968  struct bnx2x *bp = netdev_priv(netdev);
1969  DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n");
1970 }
1971 
1972 static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio,
1973  u8 *prio_type, u8 *pgid, u8 *bw_pct,
1974  u8 *up_map)
1975 {
1976  struct bnx2x *bp = netdev_priv(netdev);
1977  DP(BNX2X_MSG_DCB, "prio = %d\n", prio);
1978 
1991  *up_map = *bw_pct = *prio_type = *pgid = 0;
1992 
1993  if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
1994  return;
1995 
1996  *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio);
1997 }
1998 
1999 static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev,
2000  int pgid, u8 *bw_pct)
2001 {
2002  struct bnx2x *bp = netdev_priv(netdev);
2003  DP(BNX2X_MSG_DCB, "pgid = %d\n", pgid);
2004 
2005  *bw_pct = 0;
2006 
2007  if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
2008  return;
2009 
2010  *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid);
2011 }
2012 
2013 static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio,
2014  u8 *prio_type, u8 *pgid, u8 *bw_pct,
2015  u8 *up_map)
2016 {
2017  struct bnx2x *bp = netdev_priv(netdev);
2018  DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n");
2019 
2020  *prio_type = *pgid = *bw_pct = *up_map = 0;
2021 }
2022 
2023 static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev,
2024  int pgid, u8 *bw_pct)
2025 {
2026  struct bnx2x *bp = netdev_priv(netdev);
2027  DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n");
2028 
2029  *bw_pct = 0;
2030 }
2031 
2032 static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
2033  u8 setting)
2034 {
2035  struct bnx2x *bp = netdev_priv(netdev);
2036  DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, setting);
2037 
2038  if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
2039  return;
2040 
2041  bp->dcbx_config_params.admin_pfc_bitmap |= ((setting ? 1 : 0) << prio);
2042 
2043  if (setting)
2044  bp->dcbx_config_params.admin_pfc_tx_enable = 1;
2045 }
2046 
2047 static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
2048  u8 *setting)
2049 {
2050  struct bnx2x *bp = netdev_priv(netdev);
2051  DP(BNX2X_MSG_DCB, "prio = %d\n", prio);
2052 
2053  *setting = 0;
2054 
2055  if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES)
2056  return;
2057 
2058  *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1;
2059 }
2060 
2061 static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
2062 {
2063  struct bnx2x *bp = netdev_priv(netdev);
2064  int rc = 0;
2065 
2066  DP(BNX2X_MSG_DCB, "SET-ALL\n");
2067 
2068  if (!bnx2x_dcbnl_set_valid(bp))
2069  return 1;
2070 
2071  if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
2072  netdev_err(bp->dev,
2073  "Handling parity error recovery. Try again later\n");
2074  return 1;
2075  }
2076  if (netif_running(bp->dev))
2077  bnx2x_dcbx_init(bp, true);
2078  DP(BNX2X_MSG_DCB, "set_dcbx_params done (%d)\n", rc);
2079  if (rc)
2080  return 1;
2081 
2082  return 0;
2083 }
2084 
2085 static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
2086 {
2087  struct bnx2x *bp = netdev_priv(netdev);
2088  u8 rval = 0;
2089 
2090  if (bp->dcb_state) {
2091  switch (capid) {
2092  case DCB_CAP_ATTR_PG:
2093  *cap = true;
2094  break;
2095  case DCB_CAP_ATTR_PFC:
2096  *cap = true;
2097  break;
2098  case DCB_CAP_ATTR_UP2TC:
2099  *cap = false;
2100  break;
2101  case DCB_CAP_ATTR_PG_TCS:
2102  *cap = 0x80; /* 8 priorities for PGs */
2103  break;
2104  case DCB_CAP_ATTR_PFC_TCS:
2105  *cap = 0x80; /* 8 priorities for PFC */
2106  break;
2107  case DCB_CAP_ATTR_GSP:
2108  *cap = true;
2109  break;
2110  case DCB_CAP_ATTR_BCN:
2111  *cap = false;
2112  break;
2113  case DCB_CAP_ATTR_DCBX:
2114  *cap = BNX2X_DCBX_CAPS;
2115  break;
2116  default:
2117  BNX2X_ERR("Non valid capability ID\n");
2118  rval = -EINVAL;
2119  break;
2120  }
2121  } else {
2122  DP(BNX2X_MSG_DCB, "DCB disabled\n");
2123  rval = -EINVAL;
2124  }
2125 
2126  DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap);
2127  return rval;
2128 }
2129 
2130 static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)
2131 {
2132  struct bnx2x *bp = netdev_priv(netdev);
2133  u8 rval = 0;
2134 
2135  DP(BNX2X_MSG_DCB, "tcid %d\n", tcid);
2136 
2137  if (bp->dcb_state) {
2138  switch (tcid) {
2139  case DCB_NUMTCS_ATTR_PG:
2140  *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
2142  break;
2143  case DCB_NUMTCS_ATTR_PFC:
2144  *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
2146  break;
2147  default:
2148  BNX2X_ERR("Non valid TC-ID\n");
2149  rval = -EINVAL;
2150  break;
2151  }
2152  } else {
2153  DP(BNX2X_MSG_DCB, "DCB disabled\n");
2154  rval = -EINVAL;
2155  }
2156 
2157  return rval;
2158 }
2159 
2160 static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)
2161 {
2162  struct bnx2x *bp = netdev_priv(netdev);
2163  DP(BNX2X_MSG_DCB, "num tcs = %d; Not supported\n", num);
2164  return -EINVAL;
2165 }
2166 
2167 static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)
2168 {
2169  struct bnx2x *bp = netdev_priv(netdev);
2170  DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled);
2171 
2172  if (!bp->dcb_state)
2173  return 0;
2174 
2175  return bp->dcbx_local_feat.pfc.enabled;
2176 }
2177 
2178 static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state)
2179 {
2180  struct bnx2x *bp = netdev_priv(netdev);
2181  DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");
2182 
2183  if (!bnx2x_dcbnl_set_valid(bp))
2184  return;
2185 
2186  bp->dcbx_config_params.admin_pfc_tx_enable =
2187  bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0);
2188 }
2189 
2190 static void bnx2x_admin_app_set_ent(
2191  struct bnx2x_admin_priority_app_table *app_ent,
2192  u8 idtype, u16 idval, u8 up)
2193 {
2194  app_ent->valid = 1;
2195 
2196  switch (idtype) {
2198  app_ent->traffic_type = TRAFFIC_TYPE_ETH;
2199  break;
2201  app_ent->traffic_type = TRAFFIC_TYPE_PORT;
2202  break;
2203  default:
2204  break; /* never gets here */
2205  }
2206  app_ent->app_id = idval;
2207  app_ent->priority = up;
2208 }
2209 
2210 static bool bnx2x_admin_app_is_equal(
2211  struct bnx2x_admin_priority_app_table *app_ent,
2212  u8 idtype, u16 idval)
2213 {
2214  if (!app_ent->valid)
2215  return false;
2216 
2217  switch (idtype) {
2219  if (app_ent->traffic_type != TRAFFIC_TYPE_ETH)
2220  return false;
2221  break;
2223  if (app_ent->traffic_type != TRAFFIC_TYPE_PORT)
2224  return false;
2225  break;
2226  default:
2227  return false;
2228  }
2229  if (app_ent->app_id != idval)
2230  return false;
2231 
2232  return true;
2233 }
2234 
2235 static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
2236 {
2237  int i, ff;
2238 
2239  /* iterate over the app entries looking for idtype and idval */
2240  for (i = 0, ff = -1; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
2241  struct bnx2x_admin_priority_app_table *app_ent =
2242  &bp->dcbx_config_params.admin_priority_app_table[i];
2243  if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))
2244  break;
2245 
2246  if (ff < 0 && !app_ent->valid)
2247  ff = i;
2248  }
2249  if (i < DCBX_CONFIG_MAX_APP_PROTOCOL)
2250  /* if found overwrite up */
2251  bp->dcbx_config_params.
2252  admin_priority_app_table[i].priority = up;
2253  else if (ff >= 0)
2254  /* not found use first-free */
2255  bnx2x_admin_app_set_ent(
2256  &bp->dcbx_config_params.admin_priority_app_table[ff],
2257  idtype, idval, up);
2258  else {
2259  /* app table is full */
2260  BNX2X_ERR("Application table is too large\n");
2261  return -EBUSY;
2262  }
2263 
2264  /* up configured, if not 0 make sure feature is enabled */
2265  if (up)
2266  bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
2267 
2268  return 0;
2269 }
2270 
2271 static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,
2272  u16 idval, u8 up)
2273 {
2274  struct bnx2x *bp = netdev_priv(netdev);
2275 
2276  DP(BNX2X_MSG_DCB, "app_type %d, app_id %x, prio bitmap %d\n",
2277  idtype, idval, up);
2278 
2279  if (!bnx2x_dcbnl_set_valid(bp)) {
2280  DP(BNX2X_MSG_DCB, "dcbnl call not valid\n");
2281  return -EINVAL;
2282  }
2283 
2284  /* verify idtype */
2285  switch (idtype) {
2288  break;
2289  default:
2290  DP(BNX2X_MSG_DCB, "Wrong ID type\n");
2291  return -EINVAL;
2292  }
2293  return bnx2x_set_admin_app_up(bp, idtype, idval, up);
2294 }
2295 
2296 static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev)
2297 {
2298  struct bnx2x *bp = netdev_priv(netdev);
2299  u8 state;
2300 
2302 
2304  state |= DCB_CAP_DCBX_STATIC;
2305 
2306  return state;
2307 }
2308 
2309 static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state)
2310 {
2311  struct bnx2x *bp = netdev_priv(netdev);
2312  DP(BNX2X_MSG_DCB, "state = %02x\n", state);
2313 
2314  /* set dcbx mode */
2315 
2316  if ((state & BNX2X_DCBX_CAPS) != state) {
2317  BNX2X_ERR("Requested DCBX mode %x is beyond advertised capabilities\n",
2318  state);
2319  return 1;
2320  }
2321 
2322  if (bp->dcb_state != BNX2X_DCB_STATE_ON) {
2323  BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n");
2324  return 1;
2325  }
2326 
2327  if (state & DCB_CAP_DCBX_STATIC)
2329  else
2331 
2332  bp->dcbx_mode_uset = true;
2333  return 0;
2334 }
2335 
2336 static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
2337  u8 *flags)
2338 {
2339  struct bnx2x *bp = netdev_priv(netdev);
2340  u8 rval = 0;
2341 
2342  DP(BNX2X_MSG_DCB, "featid %d\n", featid);
2343 
2344  if (bp->dcb_state) {
2345  *flags = 0;
2346  switch (featid) {
2347  case DCB_FEATCFG_ATTR_PG:
2348  if (bp->dcbx_local_feat.ets.enabled)
2349  *flags |= DCB_FEATCFG_ENABLE;
2350  if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR)
2351  *flags |= DCB_FEATCFG_ERROR;
2352  break;
2353  case DCB_FEATCFG_ATTR_PFC:
2354  if (bp->dcbx_local_feat.pfc.enabled)
2355  *flags |= DCB_FEATCFG_ENABLE;
2356  if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |
2358  *flags |= DCB_FEATCFG_ERROR;
2359  break;
2360  case DCB_FEATCFG_ATTR_APP:
2361  if (bp->dcbx_local_feat.app.enabled)
2362  *flags |= DCB_FEATCFG_ENABLE;
2363  if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |
2365  *flags |= DCB_FEATCFG_ERROR;
2366  break;
2367  default:
2368  BNX2X_ERR("Non valid featrue-ID\n");
2369  rval = -EINVAL;
2370  break;
2371  }
2372  } else {
2373  DP(BNX2X_MSG_DCB, "DCB disabled\n");
2374  rval = -EINVAL;
2375  }
2376 
2377  return rval;
2378 }
2379 
2380 static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
2381  u8 flags)
2382 {
2383  struct bnx2x *bp = netdev_priv(netdev);
2384  u8 rval = 0;
2385 
2386  DP(BNX2X_MSG_DCB, "featid = %d flags = %02x\n", featid, flags);
2387 
2388  /* ignore the 'advertise' flag */
2389  if (bnx2x_dcbnl_set_valid(bp)) {
2390  switch (featid) {
2391  case DCB_FEATCFG_ATTR_PG:
2392  bp->dcbx_config_params.admin_ets_enable =
2393  flags & DCB_FEATCFG_ENABLE ? 1 : 0;
2394  bp->dcbx_config_params.admin_ets_willing =
2395  flags & DCB_FEATCFG_WILLING ? 1 : 0;
2396  break;
2397  case DCB_FEATCFG_ATTR_PFC:
2398  bp->dcbx_config_params.admin_pfc_enable =
2399  flags & DCB_FEATCFG_ENABLE ? 1 : 0;
2400  bp->dcbx_config_params.admin_pfc_willing =
2401  flags & DCB_FEATCFG_WILLING ? 1 : 0;
2402  break;
2403  case DCB_FEATCFG_ATTR_APP:
2404  /* ignore enable, always enabled */
2405  bp->dcbx_config_params.admin_app_priority_willing =
2406  flags & DCB_FEATCFG_WILLING ? 1 : 0;
2407  break;
2408  default:
2409  BNX2X_ERR("Non valid featrue-ID\n");
2410  rval = -EINVAL;
2411  break;
2412  }
2413  } else {
2414  DP(BNX2X_MSG_DCB, "dcbnl call not valid\n");
2415  rval = -EINVAL;
2416  }
2417 
2418  return rval;
2419 }
2420 
2421 static int bnx2x_peer_appinfo(struct net_device *netdev,
2422  struct dcb_peer_app_info *info, u16* app_count)
2423 {
2424  int i;
2425  struct bnx2x *bp = netdev_priv(netdev);
2426 
2427  DP(BNX2X_MSG_DCB, "APP-INFO\n");
2428 
2429  info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0;
2430  info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0;
2431  *app_count = 0;
2432 
2433  for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++)
2434  if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield &
2435  DCBX_APP_ENTRY_VALID)
2436  (*app_count)++;
2437  return 0;
2438 }
2439 
2440 static int bnx2x_peer_apptable(struct net_device *netdev,
2441  struct dcb_app *table)
2442 {
2443  int i, j;
2444  struct bnx2x *bp = netdev_priv(netdev);
2445 
2446  DP(BNX2X_MSG_DCB, "APP-TABLE\n");
2447 
2448  for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
2449  struct dcbx_app_priority_entry *ent =
2450  &bp->dcbx_remote_feat.app.app_pri_tbl[i];
2451 
2452  if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {
2453  table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent);
2454  table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent);
2455  table[j++].protocol = ent->app_id;
2456  }
2457  }
2458  return 0;
2459 }
2460 
2461 static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg)
2462 {
2463  int i;
2464  struct bnx2x *bp = netdev_priv(netdev);
2465 
2466  pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0;
2467 
2468  for (i = 0; i < CEE_DCBX_MAX_PGS; i++) {
2469  pg->pg_bw[i] =
2470  DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i);
2471  pg->prio_pg[i] =
2472  DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i);
2473  }
2474  return 0;
2475 }
2476 
2477 static int bnx2x_cee_peer_getpfc(struct net_device *netdev,
2478  struct cee_pfc *pfc)
2479 {
2480  struct bnx2x *bp = netdev_priv(netdev);
2481  pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps;
2482  pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap;
2483  return 0;
2484 }
2485 
2486 const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = {
2487  .getstate = bnx2x_dcbnl_get_state,
2488  .setstate = bnx2x_dcbnl_set_state,
2489  .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr,
2490  .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx,
2491  .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx,
2492  .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx,
2493  .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx,
2494  .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx,
2495  .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx,
2496  .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx,
2497  .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx,
2498  .setpfccfg = bnx2x_dcbnl_set_pfc_cfg,
2499  .getpfccfg = bnx2x_dcbnl_get_pfc_cfg,
2500  .setall = bnx2x_dcbnl_set_all,
2501  .getcap = bnx2x_dcbnl_get_cap,
2502  .getnumtcs = bnx2x_dcbnl_get_numtcs,
2503  .setnumtcs = bnx2x_dcbnl_set_numtcs,
2504  .getpfcstate = bnx2x_dcbnl_get_pfc_state,
2505  .setpfcstate = bnx2x_dcbnl_set_pfc_state,
2506  .setapp = bnx2x_dcbnl_set_app_up,
2507  .getdcbx = bnx2x_dcbnl_get_dcbx,
2508  .setdcbx = bnx2x_dcbnl_set_dcbx,
2509  .getfeatcfg = bnx2x_dcbnl_get_featcfg,
2510  .setfeatcfg = bnx2x_dcbnl_set_featcfg,
2511  .peer_getappinfo = bnx2x_peer_appinfo,
2512  .peer_getapptable = bnx2x_peer_apptable,
2513  .cee_peer_getpg = bnx2x_cee_peer_getpg,
2514  .cee_peer_getpfc = bnx2x_cee_peer_getpfc,
2515 };
2516 
2517 #endif /* BCM_DCBNL */