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