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