+uint32_t bnxt_read_fw_status_reg(struct bnxt *bp, uint32_t index)
+{
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ uint32_t reg = info->status_regs[index];
+ uint32_t type, offset, val = 0;
+
+ type = BNXT_FW_STATUS_REG_TYPE(reg);
+ offset = BNXT_FW_STATUS_REG_OFF(reg);
+
+ switch (type) {
+ case BNXT_FW_STATUS_REG_TYPE_CFG:
+ rte_pci_read_config(bp->pdev, &val, sizeof(val), offset);
+ break;
+ case BNXT_FW_STATUS_REG_TYPE_GRC:
+ offset = info->mapped_status_regs[index];
+ /* FALLTHROUGH */
+ case BNXT_FW_STATUS_REG_TYPE_BAR0:
+ val = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 +
+ offset));
+ break;
+ }
+
+ return val;
+}
+
+static int bnxt_fw_reset_all(struct bnxt *bp)
+{
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ uint32_t i;
+ int rc = 0;
+
+ if (info->flags & BNXT_FLAG_ERROR_RECOVERY_HOST) {
+ /* Reset through master function driver */
+ for (i = 0; i < info->reg_array_cnt; i++)
+ bnxt_write_fw_reset_reg(bp, i);
+ /* Wait for time specified by FW after triggering reset */
+ rte_delay_ms(info->master_func_wait_period_after_reset);
+ } else if (info->flags & BNXT_FLAG_ERROR_RECOVERY_CO_CPU) {
+ /* Reset with the help of Kong processor */
+ rc = bnxt_hwrm_fw_reset(bp);
+ if (rc)
+ PMD_DRV_LOG(ERR, "Failed to reset FW\n");
+ }
+
+ return rc;
+}
+
+static void bnxt_fw_reset_cb(void *arg)
+{
+ struct bnxt *bp = arg;
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ int rc = 0;
+
+ /* Only Master function can do FW reset */
+ if (bnxt_is_master_func(bp) &&
+ bnxt_is_recovery_enabled(bp)) {
+ rc = bnxt_fw_reset_all(bp);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Adapter recovery failed\n");
+ return;
+ }
+ }
+
+ /* if recovery method is ERROR_RECOVERY_CO_CPU, KONG will send
+ * EXCEPTION_FATAL_ASYNC event to all the functions
+ * (including MASTER FUNC). After receiving this Async, all the active
+ * drivers should treat this case as FW initiated recovery
+ */
+ if (info->flags & BNXT_FLAG_ERROR_RECOVERY_HOST) {
+ bp->fw_reset_min_msecs = BNXT_MIN_FW_READY_TIMEOUT;
+ bp->fw_reset_max_msecs = BNXT_MAX_FW_RESET_TIMEOUT;
+
+ /* To recover from error */
+ rte_eal_alarm_set(US_PER_MS, bnxt_dev_reset_and_resume,
+ (void *)bp);
+ }
+}
+
+/* Driver should poll FW heartbeat, reset_counter with the frequency
+ * advertised by FW in HWRM_ERROR_RECOVERY_QCFG.
+ * When the driver detects heartbeat stop or change in reset_counter,
+ * it has to trigger a reset to recover from the error condition.
+ * A “master PF” is the function who will have the privilege to
+ * initiate the chimp reset. The master PF will be elected by the
+ * firmware and will be notified through async message.
+ */
+static void bnxt_check_fw_health(void *arg)
+{
+ struct bnxt *bp = arg;
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ uint32_t val = 0, wait_msec;
+
+ if (!info || !bnxt_is_recovery_enabled(bp) ||
+ is_bnxt_in_error(bp))
+ return;
+
+ val = bnxt_read_fw_status_reg(bp, BNXT_FW_HEARTBEAT_CNT_REG);
+ if (val == info->last_heart_beat)
+ goto reset;
+
+ info->last_heart_beat = val;
+
+ val = bnxt_read_fw_status_reg(bp, BNXT_FW_RECOVERY_CNT_REG);
+ if (val != info->last_reset_counter)
+ goto reset;
+
+ info->last_reset_counter = val;
+
+ rte_eal_alarm_set(US_PER_MS * info->driver_polling_freq,
+ bnxt_check_fw_health, (void *)bp);
+
+ return;
+reset:
+ /* Stop DMA to/from device */
+ bp->flags |= BNXT_FLAG_FATAL_ERROR;
+ bp->flags |= BNXT_FLAG_FW_RESET;
+
+ PMD_DRV_LOG(ERR, "Detected FW dead condition\n");
+
+ if (bnxt_is_master_func(bp))
+ wait_msec = info->master_func_wait_period;
+ else
+ wait_msec = info->normal_func_wait_period;
+
+ rte_eal_alarm_set(US_PER_MS * wait_msec,
+ bnxt_fw_reset_cb, (void *)bp);
+}
+
+void bnxt_schedule_fw_health_check(struct bnxt *bp)
+{
+ uint32_t polling_freq;
+
+ if (!bnxt_is_recovery_enabled(bp))
+ return;
+
+ if (bp->flags & BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED)
+ return;
+
+ polling_freq = bp->recovery_info->driver_polling_freq;
+
+ rte_eal_alarm_set(US_PER_MS * polling_freq,
+ bnxt_check_fw_health, (void *)bp);
+ bp->flags |= BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED;
+}
+
+static void bnxt_cancel_fw_health_check(struct bnxt *bp)
+{
+ if (!bnxt_is_recovery_enabled(bp))
+ return;
+
+ rte_eal_alarm_cancel(bnxt_check_fw_health, (void *)bp);
+ bp->flags &= ~BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED;
+}
+
+static bool bnxt_vf_pciid(uint16_t device_id)