Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

qed: add support for dcbx.

This patch adds the necessary driver support for Management Firmware to
configure the device/firmware with the dcbx results. Management Firmware
is responsible for communicating the DCBX and driving the negotiation,
but the driver has responsibility of receiving async notification and
configuring the results in hw/fw. This patch also adds the dcbx support for
future protocols (e.g., FCoE) as preparation to their imminent submission.

Signed-off-by: Sudarsana Reddy Kalluru <sudarsana.kalluru@qlogic.com>
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Sudarsana Reddy Kalluru and committed by
David S. Miller
39651abd ccf92824

+834 -8
+1 -1
drivers/net/ethernet/qlogic/qed/Makefile
··· 2 2 3 3 qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ 4 4 qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \ 5 - qed_selftest.o 5 + qed_selftest.o qed_dcbx.o 6 6 qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
+2
drivers/net/ethernet/qlogic/qed/qed.h
··· 367 367 struct qed_pf_iov *pf_iov_info; 368 368 struct qed_mcp_info *mcp_info; 369 369 370 + struct qed_dcbx_info *p_dcbx_info; 371 + 370 372 struct qed_hw_cid_data *p_tx_cids; 371 373 struct qed_hw_cid_data *p_rx_cids; 372 374
+10
drivers/net/ethernet/qlogic/qed/qed_cxt.h
··· 131 131 void qed_qm_init_pf(struct qed_hwfn *p_hwfn); 132 132 133 133 /** 134 + * @brief Reconfigures QM pf on the fly 135 + * 136 + * @param p_hwfn 137 + * @param p_ptt 138 + * 139 + * @return int 140 + */ 141 + int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); 142 + 143 + /** 134 144 * @brief qed_cxt_release - Release a cid 135 145 * 136 146 * @param p_hwfn
+562
drivers/net/ethernet/qlogic/qed/qed_dcbx.c
··· 1 + /* QLogic qed NIC Driver 2 + * Copyright (c) 2015 QLogic Corporation 3 + * 4 + * This software is available under the terms of the GNU General Public License 5 + * (GPL) Version 2, available from the file COPYING in the main directory of 6 + * this source tree. 7 + */ 8 + 9 + #include <linux/types.h> 10 + #include <asm/byteorder.h> 11 + #include <linux/bitops.h> 12 + #include <linux/errno.h> 13 + #include <linux/kernel.h> 14 + #include <linux/slab.h> 15 + #include <linux/string.h> 16 + #include "qed.h" 17 + #include "qed_cxt.h" 18 + #include "qed_dcbx.h" 19 + #include "qed_hsi.h" 20 + #include "qed_sp.h" 21 + 22 + #define QED_DCBX_MAX_MIB_READ_TRY (100) 23 + #define QED_ETH_TYPE_DEFAULT (0) 24 + #define QED_ETH_TYPE_ROCE (0x8915) 25 + #define QED_UDP_PORT_TYPE_ROCE_V2 (0x12B7) 26 + #define QED_ETH_TYPE_FCOE (0x8906) 27 + #define QED_TCP_PORT_ISCSI (0xCBC) 28 + 29 + #define QED_DCBX_INVALID_PRIORITY 0xFF 30 + 31 + /* Get Traffic Class from priority traffic class table, 4 bits represent 32 + * the traffic class corresponding to the priority. 33 + */ 34 + #define QED_DCBX_PRIO2TC(prio_tc_tbl, prio) \ 35 + ((u32)(prio_tc_tbl >> ((7 - prio) * 4)) & 0x7) 36 + 37 + static const struct qed_dcbx_app_metadata qed_dcbx_app_update[] = { 38 + {DCBX_PROTOCOL_ISCSI, "ISCSI", QED_PCI_DEFAULT}, 39 + {DCBX_PROTOCOL_FCOE, "FCOE", QED_PCI_DEFAULT}, 40 + {DCBX_PROTOCOL_ROCE, "ROCE", QED_PCI_DEFAULT}, 41 + {DCBX_PROTOCOL_ROCE_V2, "ROCE_V2", QED_PCI_DEFAULT}, 42 + {DCBX_PROTOCOL_ETH, "ETH", QED_PCI_ETH} 43 + }; 44 + 45 + static bool qed_dcbx_app_ethtype(u32 app_info_bitmap) 46 + { 47 + return !!(QED_MFW_GET_FIELD(app_info_bitmap, DCBX_APP_SF) == 48 + DCBX_APP_SF_ETHTYPE); 49 + } 50 + 51 + static bool qed_dcbx_app_port(u32 app_info_bitmap) 52 + { 53 + return !!(QED_MFW_GET_FIELD(app_info_bitmap, DCBX_APP_SF) == 54 + DCBX_APP_SF_PORT); 55 + } 56 + 57 + static bool qed_dcbx_default_tlv(u32 app_info_bitmap, u16 proto_id) 58 + { 59 + return !!(qed_dcbx_app_ethtype(app_info_bitmap) && 60 + proto_id == QED_ETH_TYPE_DEFAULT); 61 + } 62 + 63 + static bool qed_dcbx_iscsi_tlv(u32 app_info_bitmap, u16 proto_id) 64 + { 65 + return !!(qed_dcbx_app_port(app_info_bitmap) && 66 + proto_id == QED_TCP_PORT_ISCSI); 67 + } 68 + 69 + static bool qed_dcbx_fcoe_tlv(u32 app_info_bitmap, u16 proto_id) 70 + { 71 + return !!(qed_dcbx_app_ethtype(app_info_bitmap) && 72 + proto_id == QED_ETH_TYPE_FCOE); 73 + } 74 + 75 + static bool qed_dcbx_roce_tlv(u32 app_info_bitmap, u16 proto_id) 76 + { 77 + return !!(qed_dcbx_app_ethtype(app_info_bitmap) && 78 + proto_id == QED_ETH_TYPE_ROCE); 79 + } 80 + 81 + static bool qed_dcbx_roce_v2_tlv(u32 app_info_bitmap, u16 proto_id) 82 + { 83 + return !!(qed_dcbx_app_port(app_info_bitmap) && 84 + proto_id == QED_UDP_PORT_TYPE_ROCE_V2); 85 + } 86 + 87 + static void 88 + qed_dcbx_dp_protocol(struct qed_hwfn *p_hwfn, struct qed_dcbx_results *p_data) 89 + { 90 + enum dcbx_protocol_type id; 91 + int i; 92 + 93 + DP_VERBOSE(p_hwfn, QED_MSG_DCB, "DCBX negotiated: %d\n", 94 + p_data->dcbx_enabled); 95 + 96 + for (i = 0; i < ARRAY_SIZE(qed_dcbx_app_update); i++) { 97 + id = qed_dcbx_app_update[i].id; 98 + 99 + DP_VERBOSE(p_hwfn, QED_MSG_DCB, 100 + "%s info: update %d, enable %d, prio %d, tc %d, num_tc %d\n", 101 + qed_dcbx_app_update[i].name, p_data->arr[id].update, 102 + p_data->arr[id].enable, p_data->arr[id].priority, 103 + p_data->arr[id].tc, p_hwfn->hw_info.num_tc); 104 + } 105 + } 106 + 107 + static void 108 + qed_dcbx_set_params(struct qed_dcbx_results *p_data, 109 + struct qed_hw_info *p_info, 110 + bool enable, 111 + bool update, 112 + u8 prio, 113 + u8 tc, 114 + enum dcbx_protocol_type type, 115 + enum qed_pci_personality personality) 116 + { 117 + /* PF update ramrod data */ 118 + p_data->arr[type].update = update; 119 + p_data->arr[type].enable = enable; 120 + p_data->arr[type].priority = prio; 121 + p_data->arr[type].tc = tc; 122 + 123 + /* QM reconf data */ 124 + if (p_info->personality == personality) { 125 + if (personality == QED_PCI_ETH) 126 + p_info->non_offload_tc = tc; 127 + else 128 + p_info->offload_tc = tc; 129 + } 130 + } 131 + 132 + /* Update app protocol data and hw_info fields with the TLV info */ 133 + static void 134 + qed_dcbx_update_app_info(struct qed_dcbx_results *p_data, 135 + struct qed_hwfn *p_hwfn, 136 + bool enable, 137 + bool update, 138 + u8 prio, u8 tc, enum dcbx_protocol_type type) 139 + { 140 + struct qed_hw_info *p_info = &p_hwfn->hw_info; 141 + enum qed_pci_personality personality; 142 + enum dcbx_protocol_type id; 143 + char *name; 144 + int i; 145 + 146 + for (i = 0; i < ARRAY_SIZE(qed_dcbx_app_update); i++) { 147 + id = qed_dcbx_app_update[i].id; 148 + 149 + if (type != id) 150 + continue; 151 + 152 + personality = qed_dcbx_app_update[i].personality; 153 + name = qed_dcbx_app_update[i].name; 154 + 155 + qed_dcbx_set_params(p_data, p_info, enable, update, 156 + prio, tc, type, personality); 157 + } 158 + } 159 + 160 + static bool 161 + qed_dcbx_get_app_protocol_type(struct qed_hwfn *p_hwfn, 162 + u32 app_prio_bitmap, 163 + u16 id, enum dcbx_protocol_type *type) 164 + { 165 + if (qed_dcbx_fcoe_tlv(app_prio_bitmap, id)) { 166 + *type = DCBX_PROTOCOL_FCOE; 167 + } else if (qed_dcbx_roce_tlv(app_prio_bitmap, id)) { 168 + *type = DCBX_PROTOCOL_ROCE; 169 + } else if (qed_dcbx_iscsi_tlv(app_prio_bitmap, id)) { 170 + *type = DCBX_PROTOCOL_ISCSI; 171 + } else if (qed_dcbx_default_tlv(app_prio_bitmap, id)) { 172 + *type = DCBX_PROTOCOL_ETH; 173 + } else if (qed_dcbx_roce_v2_tlv(app_prio_bitmap, id)) { 174 + *type = DCBX_PROTOCOL_ROCE_V2; 175 + } else { 176 + *type = DCBX_MAX_PROTOCOL_TYPE; 177 + DP_ERR(p_hwfn, 178 + "No action required, App TLV id = 0x%x app_prio_bitmap = 0x%x\n", 179 + id, app_prio_bitmap); 180 + return false; 181 + } 182 + 183 + return true; 184 + } 185 + 186 + /* Parse app TLV's to update TC information in hw_info structure for 187 + * reconfiguring QM. Get protocol specific data for PF update ramrod command. 188 + */ 189 + static int 190 + qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, 191 + struct qed_dcbx_results *p_data, 192 + struct dcbx_app_priority_entry *p_tbl, 193 + u32 pri_tc_tbl, int count, bool dcbx_enabled) 194 + { 195 + u8 tc, priority, priority_map; 196 + enum dcbx_protocol_type type; 197 + u16 protocol_id; 198 + bool enable; 199 + int i; 200 + 201 + DP_VERBOSE(p_hwfn, QED_MSG_DCB, "Num APP entries = %d\n", count); 202 + 203 + /* Parse APP TLV */ 204 + for (i = 0; i < count; i++) { 205 + protocol_id = QED_MFW_GET_FIELD(p_tbl[i].entry, 206 + DCBX_APP_PROTOCOL_ID); 207 + priority_map = QED_MFW_GET_FIELD(p_tbl[i].entry, 208 + DCBX_APP_PRI_MAP); 209 + priority = ffs(priority_map) - 1; 210 + if (priority < 0) { 211 + DP_ERR(p_hwfn, "Invalid priority\n"); 212 + return -EINVAL; 213 + } 214 + 215 + tc = QED_DCBX_PRIO2TC(pri_tc_tbl, priority); 216 + if (qed_dcbx_get_app_protocol_type(p_hwfn, p_tbl[i].entry, 217 + protocol_id, &type)) { 218 + /* ETH always have the enable bit reset, as it gets 219 + * vlan information per packet. For other protocols, 220 + * should be set according to the dcbx_enabled 221 + * indication, but we only got here if there was an 222 + * app tlv for the protocol, so dcbx must be enabled. 223 + */ 224 + enable = !!(type == DCBX_PROTOCOL_ETH); 225 + 226 + qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, 227 + priority, tc, type); 228 + } 229 + } 230 + 231 + /* If RoCE-V2 TLV is not detected, driver need to use RoCE app 232 + * data for RoCE-v2 not the default app data. 233 + */ 234 + if (!p_data->arr[DCBX_PROTOCOL_ROCE_V2].update && 235 + p_data->arr[DCBX_PROTOCOL_ROCE].update) { 236 + tc = p_data->arr[DCBX_PROTOCOL_ROCE].tc; 237 + priority = p_data->arr[DCBX_PROTOCOL_ROCE].priority; 238 + qed_dcbx_update_app_info(p_data, p_hwfn, true, true, 239 + priority, tc, DCBX_PROTOCOL_ROCE_V2); 240 + } 241 + 242 + /* Update ramrod protocol data and hw_info fields 243 + * with default info when corresponding APP TLV's are not detected. 244 + * The enabled field has a different logic for ethernet as only for 245 + * ethernet dcb should disabled by default, as the information arrives 246 + * from the OS (unless an explicit app tlv was present). 247 + */ 248 + tc = p_data->arr[DCBX_PROTOCOL_ETH].tc; 249 + priority = p_data->arr[DCBX_PROTOCOL_ETH].priority; 250 + for (type = 0; type < DCBX_MAX_PROTOCOL_TYPE; type++) { 251 + if (p_data->arr[type].update) 252 + continue; 253 + 254 + enable = (type == DCBX_PROTOCOL_ETH) ? false : dcbx_enabled; 255 + qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, 256 + priority, tc, type); 257 + } 258 + 259 + return 0; 260 + } 261 + 262 + /* Parse app TLV's to update TC information in hw_info structure for 263 + * reconfiguring QM. Get protocol specific data for PF update ramrod command. 264 + */ 265 + static int qed_dcbx_process_mib_info(struct qed_hwfn *p_hwfn) 266 + { 267 + struct dcbx_app_priority_feature *p_app; 268 + struct dcbx_app_priority_entry *p_tbl; 269 + struct qed_dcbx_results data = { 0 }; 270 + struct dcbx_ets_feature *p_ets; 271 + struct qed_hw_info *p_info; 272 + u32 pri_tc_tbl, flags; 273 + bool dcbx_enabled; 274 + int num_entries; 275 + int rc = 0; 276 + 277 + /* If DCBx version is non zero, then negotiation was 278 + * successfuly performed 279 + */ 280 + flags = p_hwfn->p_dcbx_info->operational.flags; 281 + dcbx_enabled = !!QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION); 282 + 283 + p_app = &p_hwfn->p_dcbx_info->operational.features.app; 284 + p_tbl = p_app->app_pri_tbl; 285 + 286 + p_ets = &p_hwfn->p_dcbx_info->operational.features.ets; 287 + pri_tc_tbl = p_ets->pri_tc_tbl[0]; 288 + 289 + p_info = &p_hwfn->hw_info; 290 + num_entries = QED_MFW_GET_FIELD(p_app->flags, DCBX_APP_NUM_ENTRIES); 291 + 292 + rc = qed_dcbx_process_tlv(p_hwfn, &data, p_tbl, pri_tc_tbl, 293 + num_entries, dcbx_enabled); 294 + if (rc) 295 + return rc; 296 + 297 + p_info->num_tc = QED_MFW_GET_FIELD(p_ets->flags, DCBX_ETS_MAX_TCS); 298 + data.pf_id = p_hwfn->rel_pf_id; 299 + data.dcbx_enabled = dcbx_enabled; 300 + 301 + qed_dcbx_dp_protocol(p_hwfn, &data); 302 + 303 + memcpy(&p_hwfn->p_dcbx_info->results, &data, 304 + sizeof(struct qed_dcbx_results)); 305 + 306 + return 0; 307 + } 308 + 309 + static int 310 + qed_dcbx_copy_mib(struct qed_hwfn *p_hwfn, 311 + struct qed_ptt *p_ptt, 312 + struct qed_dcbx_mib_meta_data *p_data, 313 + enum qed_mib_read_type type) 314 + { 315 + u32 prefix_seq_num, suffix_seq_num; 316 + int read_count = 0; 317 + int rc = 0; 318 + 319 + /* The data is considered to be valid only if both sequence numbers are 320 + * the same. 321 + */ 322 + do { 323 + if (type == QED_DCBX_REMOTE_LLDP_MIB) { 324 + qed_memcpy_from(p_hwfn, p_ptt, p_data->lldp_remote, 325 + p_data->addr, p_data->size); 326 + prefix_seq_num = p_data->lldp_remote->prefix_seq_num; 327 + suffix_seq_num = p_data->lldp_remote->suffix_seq_num; 328 + } else { 329 + qed_memcpy_from(p_hwfn, p_ptt, p_data->mib, 330 + p_data->addr, p_data->size); 331 + prefix_seq_num = p_data->mib->prefix_seq_num; 332 + suffix_seq_num = p_data->mib->suffix_seq_num; 333 + } 334 + read_count++; 335 + 336 + DP_VERBOSE(p_hwfn, 337 + QED_MSG_DCB, 338 + "mib type = %d, try count = %d prefix seq num = %d suffix seq num = %d\n", 339 + type, read_count, prefix_seq_num, suffix_seq_num); 340 + } while ((prefix_seq_num != suffix_seq_num) && 341 + (read_count < QED_DCBX_MAX_MIB_READ_TRY)); 342 + 343 + if (read_count >= QED_DCBX_MAX_MIB_READ_TRY) { 344 + DP_ERR(p_hwfn, 345 + "MIB read err, mib type = %d, try count = %d prefix seq num = %d suffix seq num = %d\n", 346 + type, read_count, prefix_seq_num, suffix_seq_num); 347 + rc = -EIO; 348 + } 349 + 350 + return rc; 351 + } 352 + 353 + static int 354 + qed_dcbx_read_local_lldp_mib(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 355 + { 356 + struct qed_dcbx_mib_meta_data data; 357 + int rc = 0; 358 + 359 + memset(&data, 0, sizeof(data)); 360 + data.addr = p_hwfn->mcp_info->port_addr + offsetof(struct public_port, 361 + lldp_config_params); 362 + data.lldp_local = p_hwfn->p_dcbx_info->lldp_local; 363 + data.size = sizeof(struct lldp_config_params_s); 364 + qed_memcpy_from(p_hwfn, p_ptt, data.lldp_local, data.addr, data.size); 365 + 366 + return rc; 367 + } 368 + 369 + static int 370 + qed_dcbx_read_remote_lldp_mib(struct qed_hwfn *p_hwfn, 371 + struct qed_ptt *p_ptt, 372 + enum qed_mib_read_type type) 373 + { 374 + struct qed_dcbx_mib_meta_data data; 375 + int rc = 0; 376 + 377 + memset(&data, 0, sizeof(data)); 378 + data.addr = p_hwfn->mcp_info->port_addr + offsetof(struct public_port, 379 + lldp_status_params); 380 + data.lldp_remote = p_hwfn->p_dcbx_info->lldp_remote; 381 + data.size = sizeof(struct lldp_status_params_s); 382 + rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type); 383 + 384 + return rc; 385 + } 386 + 387 + static int 388 + qed_dcbx_read_operational_mib(struct qed_hwfn *p_hwfn, 389 + struct qed_ptt *p_ptt, 390 + enum qed_mib_read_type type) 391 + { 392 + struct qed_dcbx_mib_meta_data data; 393 + int rc = 0; 394 + 395 + memset(&data, 0, sizeof(data)); 396 + data.addr = p_hwfn->mcp_info->port_addr + 397 + offsetof(struct public_port, operational_dcbx_mib); 398 + data.mib = &p_hwfn->p_dcbx_info->operational; 399 + data.size = sizeof(struct dcbx_mib); 400 + rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type); 401 + 402 + return rc; 403 + } 404 + 405 + static int 406 + qed_dcbx_read_remote_mib(struct qed_hwfn *p_hwfn, 407 + struct qed_ptt *p_ptt, enum qed_mib_read_type type) 408 + { 409 + struct qed_dcbx_mib_meta_data data; 410 + int rc = 0; 411 + 412 + memset(&data, 0, sizeof(data)); 413 + data.addr = p_hwfn->mcp_info->port_addr + 414 + offsetof(struct public_port, remote_dcbx_mib); 415 + data.mib = &p_hwfn->p_dcbx_info->remote; 416 + data.size = sizeof(struct dcbx_mib); 417 + rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type); 418 + 419 + return rc; 420 + } 421 + 422 + static int 423 + qed_dcbx_read_local_mib(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 424 + { 425 + struct qed_dcbx_mib_meta_data data; 426 + int rc = 0; 427 + 428 + memset(&data, 0, sizeof(data)); 429 + data.addr = p_hwfn->mcp_info->port_addr + 430 + offsetof(struct public_port, local_admin_dcbx_mib); 431 + data.local_admin = &p_hwfn->p_dcbx_info->local_admin; 432 + data.size = sizeof(struct dcbx_local_params); 433 + qed_memcpy_from(p_hwfn, p_ptt, data.local_admin, data.addr, data.size); 434 + 435 + return rc; 436 + } 437 + 438 + static int qed_dcbx_read_mib(struct qed_hwfn *p_hwfn, 439 + struct qed_ptt *p_ptt, enum qed_mib_read_type type) 440 + { 441 + int rc = -EINVAL; 442 + 443 + switch (type) { 444 + case QED_DCBX_OPERATIONAL_MIB: 445 + rc = qed_dcbx_read_operational_mib(p_hwfn, p_ptt, type); 446 + break; 447 + case QED_DCBX_REMOTE_MIB: 448 + rc = qed_dcbx_read_remote_mib(p_hwfn, p_ptt, type); 449 + break; 450 + case QED_DCBX_LOCAL_MIB: 451 + rc = qed_dcbx_read_local_mib(p_hwfn, p_ptt); 452 + break; 453 + case QED_DCBX_REMOTE_LLDP_MIB: 454 + rc = qed_dcbx_read_remote_lldp_mib(p_hwfn, p_ptt, type); 455 + break; 456 + case QED_DCBX_LOCAL_LLDP_MIB: 457 + rc = qed_dcbx_read_local_lldp_mib(p_hwfn, p_ptt); 458 + break; 459 + default: 460 + DP_ERR(p_hwfn, "MIB read err, unknown mib type %d\n", type); 461 + } 462 + 463 + return rc; 464 + } 465 + 466 + /* Read updated MIB. 467 + * Reconfigure QM and invoke PF update ramrod command if operational MIB 468 + * change is detected. 469 + */ 470 + int 471 + qed_dcbx_mib_update_event(struct qed_hwfn *p_hwfn, 472 + struct qed_ptt *p_ptt, enum qed_mib_read_type type) 473 + { 474 + int rc = 0; 475 + 476 + rc = qed_dcbx_read_mib(p_hwfn, p_ptt, type); 477 + if (rc) 478 + return rc; 479 + 480 + if (type == QED_DCBX_OPERATIONAL_MIB) { 481 + rc = qed_dcbx_process_mib_info(p_hwfn); 482 + if (!rc) { 483 + /* reconfigure tcs of QM queues according 484 + * to negotiation results 485 + */ 486 + qed_qm_reconf(p_hwfn, p_ptt); 487 + 488 + /* update storm FW with negotiation results */ 489 + qed_sp_pf_update(p_hwfn); 490 + } 491 + } 492 + 493 + return rc; 494 + } 495 + 496 + int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn) 497 + { 498 + int rc = 0; 499 + 500 + p_hwfn->p_dcbx_info = kzalloc(sizeof(*p_hwfn->p_dcbx_info), GFP_KERNEL); 501 + if (!p_hwfn->p_dcbx_info) { 502 + DP_NOTICE(p_hwfn, 503 + "Failed to allocate 'struct qed_dcbx_info'\n"); 504 + rc = -ENOMEM; 505 + } 506 + 507 + return rc; 508 + } 509 + 510 + void qed_dcbx_info_free(struct qed_hwfn *p_hwfn, 511 + struct qed_dcbx_info *p_dcbx_info) 512 + { 513 + kfree(p_hwfn->p_dcbx_info); 514 + } 515 + 516 + static void qed_dcbx_update_protocol_data(struct protocol_dcb_data *p_data, 517 + struct qed_dcbx_results *p_src, 518 + enum dcbx_protocol_type type) 519 + { 520 + p_data->dcb_enable_flag = p_src->arr[type].enable; 521 + p_data->dcb_priority = p_src->arr[type].priority; 522 + p_data->dcb_tc = p_src->arr[type].tc; 523 + } 524 + 525 + /* Set pf update ramrod command params */ 526 + void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src, 527 + struct pf_update_ramrod_data *p_dest) 528 + { 529 + struct protocol_dcb_data *p_dcb_data; 530 + bool update_flag = false; 531 + 532 + p_dest->pf_id = p_src->pf_id; 533 + 534 + update_flag = p_src->arr[DCBX_PROTOCOL_FCOE].update; 535 + p_dest->update_fcoe_dcb_data_flag = update_flag; 536 + 537 + update_flag = p_src->arr[DCBX_PROTOCOL_ROCE].update; 538 + p_dest->update_roce_dcb_data_flag = update_flag; 539 + update_flag = p_src->arr[DCBX_PROTOCOL_ROCE_V2].update; 540 + p_dest->update_roce_dcb_data_flag = update_flag; 541 + 542 + update_flag = p_src->arr[DCBX_PROTOCOL_ISCSI].update; 543 + p_dest->update_iscsi_dcb_data_flag = update_flag; 544 + update_flag = p_src->arr[DCBX_PROTOCOL_ETH].update; 545 + p_dest->update_eth_dcb_data_flag = update_flag; 546 + 547 + p_dcb_data = &p_dest->fcoe_dcb_data; 548 + qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_FCOE); 549 + p_dcb_data = &p_dest->roce_dcb_data; 550 + 551 + if (p_src->arr[DCBX_PROTOCOL_ROCE].update) 552 + qed_dcbx_update_protocol_data(p_dcb_data, p_src, 553 + DCBX_PROTOCOL_ROCE); 554 + if (p_src->arr[DCBX_PROTOCOL_ROCE_V2].update) 555 + qed_dcbx_update_protocol_data(p_dcb_data, p_src, 556 + DCBX_PROTOCOL_ROCE_V2); 557 + 558 + p_dcb_data = &p_dest->iscsi_dcb_data; 559 + qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_ISCSI); 560 + p_dcb_data = &p_dest->eth_dcb_data; 561 + qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_ETH); 562 + }
+80
drivers/net/ethernet/qlogic/qed/qed_dcbx.h
··· 1 + /* QLogic qed NIC Driver 2 + * Copyright (c) 2015 QLogic Corporation 3 + * 4 + * This software is available under the terms of the GNU General Public License 5 + * (GPL) Version 2, available from the file COPYING in the main directory of 6 + * this source tree. 7 + */ 8 + 9 + #ifndef _QED_DCBX_H 10 + #define _QED_DCBX_H 11 + #include <linux/types.h> 12 + #include <linux/slab.h> 13 + #include "qed.h" 14 + #include "qed_hsi.h" 15 + #include "qed_hw.h" 16 + #include "qed_mcp.h" 17 + #include "qed_reg_addr.h" 18 + 19 + #define DCBX_CONFIG_MAX_APP_PROTOCOL 4 20 + 21 + enum qed_mib_read_type { 22 + QED_DCBX_OPERATIONAL_MIB, 23 + QED_DCBX_REMOTE_MIB, 24 + QED_DCBX_LOCAL_MIB, 25 + QED_DCBX_REMOTE_LLDP_MIB, 26 + QED_DCBX_LOCAL_LLDP_MIB 27 + }; 28 + 29 + struct qed_dcbx_app_data { 30 + bool enable; /* DCB enabled */ 31 + bool update; /* Update indication */ 32 + u8 priority; /* Priority */ 33 + u8 tc; /* Traffic Class */ 34 + }; 35 + 36 + struct qed_dcbx_results { 37 + bool dcbx_enabled; 38 + u8 pf_id; 39 + struct qed_dcbx_app_data arr[DCBX_MAX_PROTOCOL_TYPE]; 40 + }; 41 + 42 + struct qed_dcbx_app_metadata { 43 + enum dcbx_protocol_type id; 44 + char *name; 45 + enum qed_pci_personality personality; 46 + }; 47 + 48 + #define QED_MFW_GET_FIELD(name, field) \ 49 + (((name) & (field ## _MASK)) >> (field ## _SHIFT)) 50 + 51 + struct qed_dcbx_info { 52 + struct lldp_status_params_s lldp_remote[LLDP_MAX_LLDP_AGENTS]; 53 + struct lldp_config_params_s lldp_local[LLDP_MAX_LLDP_AGENTS]; 54 + struct dcbx_local_params local_admin; 55 + struct qed_dcbx_results results; 56 + struct dcbx_mib operational; 57 + struct dcbx_mib remote; 58 + u8 dcbx_cap; 59 + }; 60 + 61 + struct qed_dcbx_mib_meta_data { 62 + struct lldp_config_params_s *lldp_local; 63 + struct lldp_status_params_s *lldp_remote; 64 + struct dcbx_local_params *local_admin; 65 + struct dcbx_mib *mib; 66 + size_t size; 67 + u32 addr; 68 + }; 69 + 70 + /* QED local interface routines */ 71 + int 72 + qed_dcbx_mib_update_event(struct qed_hwfn *, 73 + struct qed_ptt *, enum qed_mib_read_type); 74 + 75 + int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn); 76 + void qed_dcbx_info_free(struct qed_hwfn *, struct qed_dcbx_info *); 77 + void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src, 78 + struct pf_update_ramrod_data *p_dest); 79 + 80 + #endif
+100 -5
drivers/net/ethernet/qlogic/qed/qed_dev.c
··· 22 22 #include <linux/qed/qed_if.h> 23 23 #include "qed.h" 24 24 #include "qed_cxt.h" 25 + #include "qed_dcbx.h" 25 26 #include "qed_dev_api.h" 26 27 #include "qed_hsi.h" 27 28 #include "qed_hw.h" ··· 33 32 #include "qed_sp.h" 34 33 #include "qed_sriov.h" 35 34 #include "qed_vf.h" 35 + 36 + static spinlock_t qm_lock; 37 + static bool qm_lock_init = false; 36 38 37 39 /* API common to all protocols */ 38 40 enum BAR_ID { ··· 151 147 qed_int_free(p_hwfn); 152 148 qed_iov_free(p_hwfn); 153 149 qed_dmae_info_free(p_hwfn); 150 + qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info); 154 151 } 155 152 } 156 153 ··· 205 200 vport_id = (u8)RESC_START(p_hwfn, QED_VPORT); 206 201 207 202 /* First init per-TC PQs */ 208 - for (i = 0; i < multi_cos_tcs; i++, curr_queue++) { 203 + for (i = 0; i < multi_cos_tcs; i++) { 209 204 struct init_qm_pq_params *params = 210 - &qm_info->qm_pq_params[curr_queue]; 205 + &qm_info->qm_pq_params[curr_queue++]; 211 206 212 - params->vport_id = vport_id; 213 - params->tc_id = p_hwfn->hw_info.non_offload_tc; 214 - params->wrr_group = 1; 207 + if (p_hwfn->hw_info.personality == QED_PCI_ETH) { 208 + params->vport_id = vport_id; 209 + params->tc_id = p_hwfn->hw_info.non_offload_tc; 210 + params->wrr_group = 1; 211 + } else { 212 + params->vport_id = vport_id; 213 + params->tc_id = p_hwfn->hw_info.offload_tc; 214 + params->wrr_group = 1; 215 + } 215 216 } 216 217 217 218 /* Then init pure-LB PQ */ ··· 275 264 DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n"); 276 265 qed_qm_info_free(p_hwfn); 277 266 return -ENOMEM; 267 + } 268 + 269 + /* This function reconfigures the QM pf on the fly. 270 + * For this purpose we: 271 + * 1. reconfigure the QM database 272 + * 2. set new values to runtime arrat 273 + * 3. send an sdm_qm_cmd through the rbc interface to stop the QM 274 + * 4. activate init tool in QM_PF stage 275 + * 5. send an sdm_qm_cmd through rbc interface to release the QM 276 + */ 277 + int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 278 + { 279 + struct qed_qm_info *qm_info = &p_hwfn->qm_info; 280 + bool b_rc; 281 + int rc; 282 + 283 + /* qm_info is allocated in qed_init_qm_info() which is already called 284 + * from qed_resc_alloc() or previous call of qed_qm_reconf(). 285 + * The allocated size may change each init, so we free it before next 286 + * allocation. 287 + */ 288 + qed_qm_info_free(p_hwfn); 289 + 290 + /* initialize qed's qm data structure */ 291 + rc = qed_init_qm_info(p_hwfn); 292 + if (rc) 293 + return rc; 294 + 295 + /* stop PF's qm queues */ 296 + spin_lock_bh(&qm_lock); 297 + b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true, 298 + qm_info->start_pq, qm_info->num_pqs); 299 + spin_unlock_bh(&qm_lock); 300 + if (!b_rc) 301 + return -EINVAL; 302 + 303 + /* clear the QM_PF runtime phase leftovers from previous init */ 304 + qed_init_clear_rt_data(p_hwfn); 305 + 306 + /* prepare QM portion of runtime array */ 307 + qed_qm_init_pf(p_hwfn); 308 + 309 + /* activate init tool on runtime array */ 310 + rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id, 311 + p_hwfn->hw_info.hw_mode); 312 + if (rc) 313 + return rc; 314 + 315 + /* start PF's qm queues */ 316 + spin_lock_bh(&qm_lock); 317 + b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true, 318 + qm_info->start_pq, qm_info->num_pqs); 319 + spin_unlock_bh(&qm_lock); 320 + if (!b_rc) 321 + return -EINVAL; 322 + 323 + return 0; 278 324 } 279 325 280 326 int qed_resc_alloc(struct qed_dev *cdev) ··· 441 373 if (rc) { 442 374 DP_NOTICE(p_hwfn, 443 375 "Failed to allocate memory for dmae_info structure\n"); 376 + goto alloc_err; 377 + } 378 + 379 + /* DCBX initialization */ 380 + rc = qed_dcbx_info_alloc(p_hwfn); 381 + if (rc) { 382 + DP_NOTICE(p_hwfn, 383 + "Failed to allocate memory for dcbx structure\n"); 444 384 goto alloc_err; 445 385 } 446 386 } ··· 856 780 p_hwfn->first_on_engine = (load_code == 857 781 FW_MSG_CODE_DRV_LOAD_ENGINE); 858 782 783 + if (!qm_lock_init) { 784 + spin_lock_init(&qm_lock); 785 + qm_lock_init = true; 786 + } 787 + 859 788 switch (load_code) { 860 789 case FW_MSG_CODE_DRV_LOAD_ENGINE: 861 790 rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, ··· 899 818 return rc; 900 819 if (mfw_rc) { 901 820 DP_NOTICE(p_hwfn, "Failed sending LOAD_DONE command\n"); 821 + return mfw_rc; 822 + } 823 + 824 + /* send DCBX attention request command */ 825 + DP_VERBOSE(p_hwfn, 826 + QED_MSG_DCB, 827 + "sending phony dcbx set command to trigger DCBx attention handling\n"); 828 + mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, 829 + DRV_MSG_CODE_SET_DCBX, 830 + 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, 831 + &load_code, &param); 832 + if (mfw_rc) { 833 + DP_NOTICE(p_hwfn, 834 + "Failed to send DCBX attention request\n"); 902 835 return mfw_rc; 903 836 } 904 837
+19 -2
drivers/net/ethernet/qlogic/qed/qed_hsi.h
··· 634 634 u8 reserved0[4]; 635 635 }; 636 636 637 + /* Data for port update ramrod */ 638 + struct protocol_dcb_data { 639 + u8 dcb_enable_flag; 640 + u8 dcb_priority; 641 + u8 dcb_tc; 642 + u8 reserved; 643 + }; 644 + 637 645 /* tunnel configuration */ 638 646 struct pf_update_tunnel_config { 639 647 u8 update_rx_pf_clss; ··· 664 656 }; 665 657 666 658 struct pf_update_ramrod_data { 667 - u32 reserved[2]; 668 - u32 reserved_1[6]; 659 + u8 pf_id; 660 + u8 update_eth_dcb_data_flag; 661 + u8 update_fcoe_dcb_data_flag; 662 + u8 update_iscsi_dcb_data_flag; 663 + u8 update_roce_dcb_data_flag; 664 + u8 update_mf_vlan_flag; 665 + __le16 mf_vlan; 666 + struct protocol_dcb_data eth_dcb_data; 667 + struct protocol_dcb_data fcoe_dcb_data; 668 + struct protocol_dcb_data iscsi_dcb_data; 669 + struct protocol_dcb_data roce_dcb_data; 669 670 struct pf_update_tunnel_config tunnel_config; 670 671 }; 671 672
+13
drivers/net/ethernet/qlogic/qed/qed_mcp.c
··· 15 15 #include <linux/spinlock.h> 16 16 #include <linux/string.h> 17 17 #include "qed.h" 18 + #include "qed_dcbx.h" 18 19 #include "qed_hsi.h" 19 20 #include "qed_hw.h" 20 21 #include "qed_mcp.h" ··· 825 824 break; 826 825 case MFW_DRV_MSG_VF_DISABLED: 827 826 qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 827 + break; 828 + case MFW_DRV_MSG_LLDP_DATA_UPDATED: 829 + qed_dcbx_mib_update_event(p_hwfn, p_ptt, 830 + QED_DCBX_REMOTE_LLDP_MIB); 831 + break; 832 + case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 833 + qed_dcbx_mib_update_event(p_hwfn, p_ptt, 834 + QED_DCBX_REMOTE_MIB); 835 + break; 836 + case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 837 + qed_dcbx_mib_update_event(p_hwfn, p_ptt, 838 + QED_DCBX_OPERATIONAL_MIB); 828 839 break; 829 840 case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 830 841 qed_mcp_handle_transceiver_change(p_hwfn, p_ptt);
+13
drivers/net/ethernet/qlogic/qed/qed_sp.h
··· 354 354 enum qed_mf_mode mode, bool allow_npar_tx_switch); 355 355 356 356 /** 357 + * @brief qed_sp_pf_update - PF Function Update Ramrod 358 + * 359 + * This ramrod updates function-related parameters. Every parameter can be 360 + * updated independently, according to configuration flags. 361 + * 362 + * @param p_hwfn 363 + * 364 + * @return int 365 + */ 366 + 367 + int qed_sp_pf_update(struct qed_hwfn *p_hwfn); 368 + 369 + /** 357 370 * @brief qed_sp_pf_stop - PF Function Stop Ramrod 358 371 * 359 372 * This ramrod is sent to close a Physical Function (PF). It is the last ramrod
+25
drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
··· 15 15 #include "qed.h" 16 16 #include <linux/qed/qed_chain.h> 17 17 #include "qed_cxt.h" 18 + #include "qed_dcbx.h" 18 19 #include "qed_hsi.h" 19 20 #include "qed_hw.h" 20 21 #include "qed_int.h" ··· 383 382 } 384 383 385 384 return rc; 385 + } 386 + 387 + int qed_sp_pf_update(struct qed_hwfn *p_hwfn) 388 + { 389 + struct qed_spq_entry *p_ent = NULL; 390 + struct qed_sp_init_data init_data; 391 + int rc = -EINVAL; 392 + 393 + /* Get SPQ entry */ 394 + memset(&init_data, 0, sizeof(init_data)); 395 + init_data.cid = qed_spq_get_cid(p_hwfn); 396 + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 397 + init_data.comp_mode = QED_SPQ_MODE_CB; 398 + 399 + rc = qed_sp_init_request(p_hwfn, &p_ent, 400 + COMMON_RAMROD_PF_UPDATE, PROTOCOLID_COMMON, 401 + &init_data); 402 + if (rc) 403 + return rc; 404 + 405 + qed_dcbx_set_pf_update_params(&p_hwfn->p_dcbx_info->results, 406 + &p_ent->ramrod.pf_update); 407 + 408 + return qed_spq_post(p_hwfn, p_ent, NULL); 386 409 } 387 410 388 411 /* Set pf update ramrod command params */
+9
include/linux/qed/qed_if.h
··· 25 25 #include <linux/qed/common_hsi.h> 26 26 #include <linux/qed/qed_chain.h> 27 27 28 + enum dcbx_protocol_type { 29 + DCBX_PROTOCOL_ISCSI, 30 + DCBX_PROTOCOL_FCOE, 31 + DCBX_PROTOCOL_ROCE, 32 + DCBX_PROTOCOL_ROCE_V2, 33 + DCBX_PROTOCOL_ETH, 34 + DCBX_MAX_PROTOCOL_TYPE 35 + }; 36 + 28 37 enum qed_led_mode { 29 38 QED_LED_MODE_OFF, 30 39 QED_LED_MODE_ON,