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