1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2023 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <rte_malloc.h> 7 #include <rte_alarm.h> 8 #include <rte_cycles.h> 9 10 #include "bnxt.h" 11 #include "bnxt_hwrm.h" 12 #include "bnxt_ring.h" 13 #include "hsi_struct_def_dpdk.h" 14 #include "tfc_vf2pf_msg.h" 15 16 void bnxt_wait_for_device_shutdown(struct bnxt *bp) 17 { 18 uint32_t val, timeout; 19 20 /* if HWRM_FUNC_QCAPS_OUTPUT_FLAGS_ERR_RECOVER_RELOAD is set 21 * in HWRM_FUNC_QCAPS command, wait for FW_STATUS to set 22 * the SHUTDOWN bit in health register 23 */ 24 if (!(bp->recovery_info && 25 (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD))) 26 return; 27 28 /* Driver has to wait for fw_reset_max_msecs or shutdown bit which comes 29 * first for FW to collect crash dump. 30 */ 31 timeout = bp->fw_reset_max_msecs; 32 33 /* Driver has to poll for shutdown bit in fw_status register 34 * 35 * 1. in case of hot fw upgrade, this bit will be set after all 36 * function drivers unregistered with fw. 37 * 2. in case of fw initiated error recovery, this bit will be 38 * set after fw has collected the core dump 39 */ 40 do { 41 val = bnxt_read_fw_status_reg(bp, BNXT_FW_STATUS_REG); 42 if (val & BNXT_FW_STATUS_SHUTDOWN) 43 return; 44 45 rte_delay_ms(100); 46 timeout -= 100; 47 } while (timeout); 48 } 49 50 static void bnxt_handle_event_error_report(struct bnxt *bp, 51 uint32_t data1, 52 uint32_t data2) 53 { 54 switch (BNXT_EVENT_ERROR_REPORT_TYPE(data1)) { 55 case HWRM_ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM: 56 PMD_DRV_LOG_LINE(WARNING, "Port:%d Pause Storm detected!", 57 bp->eth_dev->data->port_id); 58 break; 59 case HWRM_ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DUAL_DATA_RATE_NOT_SUPPORTED: 60 PMD_DRV_LOG_LINE(WARNING, "Port:%d Speed change not supported with dual rate transceivers on this board", 61 bp->eth_dev->data->port_id); 62 break; 63 default: 64 PMD_DRV_LOG_LINE(INFO, "FW reported unknown error type data1 %d" 65 " data2: %d", data1, data2); 66 break; 67 } 68 } 69 70 void bnxt_handle_vf_cfg_change(void *arg) 71 { 72 struct bnxt *bp = arg; 73 struct rte_eth_dev *eth_dev = bp->eth_dev; 74 int rc; 75 76 /* Free and recreate filters with default VLAN */ 77 if (eth_dev->data->dev_started) { 78 rc = bnxt_dev_stop_op(eth_dev); 79 if (rc != 0) { 80 PMD_DRV_LOG_LINE(ERR, "Failed to stop Port:%u", eth_dev->data->port_id); 81 return; 82 } 83 84 rc = bnxt_dev_start_op(eth_dev); 85 if (rc != 0) 86 PMD_DRV_LOG_LINE(ERR, "Failed to start Port:%u", eth_dev->data->port_id); 87 } 88 } 89 90 static void 91 bnxt_process_vf_flr(struct bnxt *bp, uint32_t data1) 92 { 93 uint16_t pfid, vfid; 94 int rc; 95 96 if (!BNXT_TRUFLOW_EN(bp)) 97 return; 98 99 pfid = (data1 & HWRM_ASYNC_EVENT_CMPL_VF_FLR_EVENT_DATA1_PF_ID_MASK) >> 100 HWRM_ASYNC_EVENT_CMPL_VF_FLR_EVENT_DATA1_PF_ID_SFT; 101 vfid = (data1 & HWRM_ASYNC_EVENT_CMPL_VF_FLR_EVENT_DATA1_VF_ID_MASK) >> 102 HWRM_ASYNC_EVENT_CMPL_VF_FLR_EVENT_DATA1_VF_ID_SFT; 103 104 PMD_DRV_LOG_LINE(INFO, "VF FLR async event received pfid: %u, vfid: %u", 105 pfid, vfid); 106 107 rc = tfc_tbl_scope_func_reset(&bp->tfcp, vfid); 108 if (rc != 0) 109 PMD_DRV_LOG_LINE(ERR, "Failed to reset vf"); 110 } 111 112 /* 113 * Async event handling 114 */ 115 void bnxt_handle_async_event(struct bnxt *bp, 116 struct cmpl_base *cmp) 117 { 118 struct hwrm_async_event_cmpl *async_cmp = 119 (struct hwrm_async_event_cmpl *)cmp; 120 uint16_t event_id = rte_le_to_cpu_16(async_cmp->event_id); 121 uint16_t port_id = bp->eth_dev->data->port_id; 122 struct bnxt_error_recovery_info *info; 123 uint32_t event_data; 124 uint32_t data1, data2; 125 uint32_t status; 126 127 data1 = rte_le_to_cpu_32(async_cmp->event_data1); 128 data2 = rte_le_to_cpu_32(async_cmp->event_data2); 129 130 switch (event_id) { 131 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: 132 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE: 133 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: 134 /* FALLTHROUGH */ 135 bnxt_link_update_op(bp->eth_dev, 0); 136 rte_eth_dev_callback_process(bp->eth_dev, 137 RTE_ETH_EVENT_INTR_LSC, NULL); 138 break; 139 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD: 140 PMD_DRV_LOG_LINE(INFO, "Async event: PF driver unloaded"); 141 break; 142 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE: 143 PMD_DRV_LOG_LINE(INFO, "Port %u: VF config change async event", port_id); 144 PMD_DRV_LOG_LINE(INFO, "event: data1 %#x data2 %#x", data1, data2); 145 bnxt_hwrm_func_qcfg(bp, NULL); 146 if (BNXT_VF(bp)) 147 rte_eal_alarm_set(1, bnxt_handle_vf_cfg_change, (void *)bp); 148 break; 149 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED: 150 PMD_DRV_LOG_LINE(INFO, "Port conn async event"); 151 break; 152 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY: 153 /* 154 * Avoid any rx/tx packet processing during firmware reset 155 * operation. 156 */ 157 bnxt_stop_rxtx(bp->eth_dev); 158 159 /* Ignore reset notify async events when stopping the port */ 160 if (!bp->eth_dev->data->dev_started) { 161 bp->flags |= BNXT_FLAG_FATAL_ERROR; 162 return; 163 } 164 165 rte_eth_dev_callback_process(bp->eth_dev, 166 RTE_ETH_EVENT_ERR_RECOVERING, 167 NULL); 168 169 pthread_mutex_lock(&bp->err_recovery_lock); 170 event_data = data1; 171 /* timestamp_lo/hi values are in units of 100ms */ 172 bp->fw_reset_max_msecs = async_cmp->timestamp_hi ? 173 rte_le_to_cpu_16(async_cmp->timestamp_hi) * 100 : 174 BNXT_MAX_FW_RESET_TIMEOUT; 175 bp->fw_reset_min_msecs = async_cmp->timestamp_lo ? 176 async_cmp->timestamp_lo * 100 : 177 BNXT_MIN_FW_READY_TIMEOUT; 178 if ((event_data & EVENT_DATA1_REASON_CODE_MASK) == 179 EVENT_DATA1_REASON_CODE_FW_EXCEPTION_FATAL) { 180 PMD_DRV_LOG_LINE(INFO, 181 "Port %u: Firmware fatal reset event received", 182 port_id); 183 bp->flags |= BNXT_FLAG_FATAL_ERROR; 184 } else { 185 PMD_DRV_LOG_LINE(INFO, 186 "Port %u: Firmware non-fatal reset event received", 187 port_id); 188 } 189 190 bp->flags |= BNXT_FLAG_FW_RESET; 191 pthread_mutex_unlock(&bp->err_recovery_lock); 192 rte_eal_alarm_set(US_PER_MS, bnxt_dev_reset_and_resume, 193 (void *)bp); 194 break; 195 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY: 196 info = bp->recovery_info; 197 198 if (!info) 199 return; 200 201 event_data = data1 & EVENT_DATA1_FLAGS_MASK; 202 203 if (event_data & EVENT_DATA1_FLAGS_RECOVERY_ENABLED) { 204 info->flags |= BNXT_FLAG_RECOVERY_ENABLED; 205 } else { 206 info->flags &= ~BNXT_FLAG_RECOVERY_ENABLED; 207 PMD_DRV_LOG_LINE(INFO, "Driver recovery watchdog is disabled"); 208 return; 209 } 210 211 if (event_data & EVENT_DATA1_FLAGS_MASTER_FUNC) 212 info->flags |= BNXT_FLAG_PRIMARY_FUNC; 213 else 214 info->flags &= ~BNXT_FLAG_PRIMARY_FUNC; 215 216 status = bnxt_read_fw_status_reg(bp, BNXT_FW_STATUS_REG); 217 PMD_DRV_LOG_LINE(INFO, 218 "Port: %u Driver recovery watchdog, role: %s, FW status: 0x%x (%s)", 219 port_id, bnxt_is_primary_func(bp) ? "primary" : "backup", status, 220 (status == BNXT_FW_STATUS_HEALTHY) ? "healthy" : "unhealthy"); 221 222 if (bp->flags & BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED) 223 return; 224 225 info->last_heart_beat = 226 bnxt_read_fw_status_reg(bp, BNXT_FW_HEARTBEAT_CNT_REG); 227 info->last_reset_counter = 228 bnxt_read_fw_status_reg(bp, BNXT_FW_RECOVERY_CNT_REG); 229 230 bnxt_schedule_fw_health_check(bp); 231 break; 232 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_DEBUG_NOTIFICATION: 233 PMD_DRV_LOG_LINE(INFO, "Port: %u DNC event: data1 %#x data2 %#x", 234 port_id, data1, data2); 235 break; 236 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST: 237 PMD_DRV_LOG_LINE(INFO, 238 "Port %u: Received fw echo request: data1 %#x data2 %#x", 239 port_id, data1, data2); 240 if (bp->recovery_info) 241 bnxt_hwrm_fw_echo_reply(bp, data1, data2); 242 break; 243 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT: 244 bnxt_handle_event_error_report(bp, data1, data2); 245 break; 246 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_FLR: 247 bnxt_process_vf_flr(bp, data1); 248 break; 249 case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_RSS_CHANGE: 250 /* RSS change notification, re-read QCAPS */ 251 PMD_DRV_LOG_LINE(INFO, "Async event: RSS change event [%#x, %#x]", 252 data1, data2); 253 bnxt_hwrm_vnic_qcaps(bp); 254 break; 255 default: 256 PMD_DRV_LOG_LINE(DEBUG, "handle_async_event id = 0x%x", event_id); 257 break; 258 } 259 } 260 261 void bnxt_handle_fwd_req(struct bnxt *bp, struct cmpl_base *cmpl) 262 { 263 struct hwrm_exec_fwd_resp_input *fwreq; 264 struct hwrm_fwd_req_cmpl *fwd_cmpl = (struct hwrm_fwd_req_cmpl *)cmpl; 265 struct input *fwd_cmd; 266 uint16_t fw_vf_id; 267 uint16_t vf_id; 268 uint16_t req_len; 269 int rc; 270 271 if (bp->pf->active_vfs <= 0) { 272 PMD_DRV_LOG_LINE(ERR, "Forwarded VF with no active VFs"); 273 return; 274 } 275 276 /* Qualify the fwd request */ 277 fw_vf_id = rte_le_to_cpu_16(fwd_cmpl->source_id); 278 vf_id = fw_vf_id - bp->pf->first_vf_id; 279 280 req_len = (rte_le_to_cpu_16(fwd_cmpl->req_len_type) & 281 HWRM_FWD_REQ_CMPL_REQ_LEN_MASK) >> 282 HWRM_FWD_REQ_CMPL_REQ_LEN_SFT; 283 if (req_len > sizeof(fwreq->encap_request)) 284 req_len = sizeof(fwreq->encap_request); 285 286 /* Locate VF's forwarded command */ 287 fwd_cmd = (struct input *)bp->pf->vf_info[vf_id].req_buf; 288 289 if (fw_vf_id < bp->pf->first_vf_id || 290 fw_vf_id >= bp->pf->first_vf_id + bp->pf->active_vfs) { 291 PMD_DRV_LOG_LINE(ERR, 292 "FWD req's source_id 0x%x out of range 0x%x - 0x%x (%d %d)", 293 fw_vf_id, bp->pf->first_vf_id, 294 (bp->pf->first_vf_id) + bp->pf->active_vfs - 1, 295 bp->pf->first_vf_id, bp->pf->active_vfs); 296 goto reject; 297 } 298 299 if (bnxt_rcv_msg_from_vf(bp, vf_id, fwd_cmd)) { 300 /* 301 * In older firmware versions, the MAC had to be all zeros for 302 * the VF to set it's MAC via hwrm_func_vf_cfg. Set to all 303 * zeros if it's being configured and has been ok'd by caller. 304 */ 305 if (fwd_cmd->req_type == HWRM_FUNC_VF_CFG) { 306 struct hwrm_func_vf_cfg_input *vfc = (void *)fwd_cmd; 307 308 if (vfc->enables & 309 HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR) { 310 bnxt_hwrm_func_vf_mac(bp, vf_id, 311 (const uint8_t *)"\x00\x00\x00\x00\x00"); 312 } 313 } 314 315 if (fwd_cmd->req_type == HWRM_CFA_L2_SET_RX_MASK) { 316 struct hwrm_cfa_l2_set_rx_mask_input *srm = 317 (void *)fwd_cmd; 318 319 srm->vlan_tag_tbl_addr = rte_cpu_to_le_64(0); 320 srm->num_vlan_tags = rte_cpu_to_le_32(0); 321 srm->mask &= ~rte_cpu_to_le_32( 322 HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLANONLY | 323 HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLAN_NONVLAN | 324 HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN); 325 } 326 327 if (fwd_cmd->req_type == HWRM_OEM_CMD) { 328 struct hwrm_oem_cmd_input *oem_cmd = (void *)fwd_cmd; 329 struct hwrm_oem_cmd_output oem_out = { 0 }; 330 331 if (oem_cmd->oem_id == 0x14e4 && 332 oem_cmd->naming_authority 333 == HWRM_OEM_CMD_INPUT_NAMING_AUTHORITY_PCI_SIG && 334 oem_cmd->message_family 335 == HWRM_OEM_CMD_INPUT_MESSAGE_FAMILY_TRUFLOW) { 336 uint32_t resp[18] = { 0 }; 337 uint16_t oem_data_len = sizeof(oem_out.oem_data); 338 uint16_t resp_len = oem_data_len; 339 340 rc = tfc_oem_cmd_process(&bp->tfcp, 341 oem_cmd->oem_data, 342 resp, 343 &resp_len); 344 if (rc) { 345 PMD_DRV_LOG_LINE(ERR, 346 "OEM cmd process error id 0x%x, name 0x%x, family 0x%x", 347 oem_cmd->oem_id, 348 oem_cmd->naming_authority, 349 oem_cmd->message_family); 350 goto reject; 351 } 352 353 oem_out.error_code = 0; 354 oem_out.req_type = oem_cmd->req_type; 355 oem_out.seq_id = oem_cmd->seq_id; 356 oem_out.resp_len = rte_cpu_to_le_16(sizeof(oem_out)); 357 oem_out.oem_id = oem_cmd->oem_id; 358 oem_out.naming_authority = oem_cmd->naming_authority; 359 oem_out.message_family = oem_cmd->message_family; 360 memcpy(oem_out.oem_data, resp, resp_len); 361 oem_out.valid = 1; 362 363 rc = bnxt_hwrm_fwd_resp(bp, fw_vf_id, &oem_out, oem_out.resp_len, 364 oem_cmd->resp_addr, oem_cmd->cmpl_ring); 365 if (rc) { 366 PMD_DRV_LOG_LINE(ERR, 367 "Failed to send HWRM_FWD_RESP VF 0x%x, type", 368 fw_vf_id - bp->pf->first_vf_id); 369 } 370 } else { 371 PMD_DRV_LOG_LINE(ERR, 372 "Unsupported OEM cmd id 0x%x, name 0x%x, family 0x%x", 373 oem_cmd->oem_id, oem_cmd->naming_authority, 374 oem_cmd->message_family); 375 goto reject; 376 } 377 378 return; 379 } 380 381 /* Forward */ 382 rc = bnxt_hwrm_exec_fwd_resp(bp, fw_vf_id, fwd_cmd, req_len); 383 if (rc) { 384 PMD_DRV_LOG_LINE(ERR, 385 "Failed to send FWD req VF 0x%x, type 0x%x.", 386 fw_vf_id - bp->pf->first_vf_id, 387 rte_le_to_cpu_16(fwd_cmd->req_type)); 388 } 389 return; 390 } 391 392 reject: 393 rc = bnxt_hwrm_reject_fwd_resp(bp, fw_vf_id, fwd_cmd, req_len); 394 if (rc) { 395 PMD_DRV_LOG_LINE(ERR, 396 "Failed to send REJECT req VF 0x%x, type 0x%x.", 397 fw_vf_id - bp->pf->first_vf_id, 398 rte_le_to_cpu_16(fwd_cmd->req_type)); 399 } 400 401 return; 402 } 403 404 int bnxt_event_hwrm_resp_handler(struct bnxt *bp, struct cmpl_base *cmp) 405 { 406 bool evt = 0; 407 408 if (bp == NULL || cmp == NULL) { 409 PMD_DRV_LOG_LINE(ERR, "invalid NULL argument"); 410 return evt; 411 } 412 413 if (unlikely(is_bnxt_in_error(bp))) 414 return 0; 415 416 switch (CMP_TYPE(cmp)) { 417 case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: 418 /* Handle any async event */ 419 bnxt_handle_async_event(bp, cmp); 420 evt = 1; 421 break; 422 case CMPL_BASE_TYPE_HWRM_FWD_REQ: 423 /* Handle HWRM forwarded responses */ 424 bnxt_handle_fwd_req(bp, cmp); 425 evt = 1; 426 break; 427 default: 428 /* Ignore any other events */ 429 PMD_DRV_LOG_LINE(DEBUG, "Ignoring %02x completion", CMP_TYPE(cmp)); 430 break; 431 } 432 433 return evt; 434 } 435 436 bool bnxt_is_primary_func(struct bnxt *bp) 437 { 438 if (bp->recovery_info->flags & BNXT_FLAG_PRIMARY_FUNC) 439 return true; 440 441 return false; 442 } 443 444 bool bnxt_is_recovery_enabled(struct bnxt *bp) 445 { 446 struct bnxt_error_recovery_info *info; 447 448 info = bp->recovery_info; 449 if (info && (info->flags & BNXT_FLAG_RECOVERY_ENABLED)) 450 return true; 451 452 return false; 453 } 454 455 void bnxt_stop_rxtx(struct rte_eth_dev *eth_dev) 456 { 457 eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; 458 eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy; 459 460 rte_eth_fp_ops[eth_dev->data->port_id].rx_pkt_burst = 461 eth_dev->rx_pkt_burst; 462 rte_eth_fp_ops[eth_dev->data->port_id].tx_pkt_burst = 463 eth_dev->tx_pkt_burst; 464 rte_mb(); 465 466 /* Allow time for threads to exit the real burst functions. */ 467 rte_delay_ms(100); 468 } 469