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