Commit 8f6c5e4d authored by Edwin Peer's avatar Edwin Peer Committed by David S. Miller
Browse files

bnxt_en: implement devlink dev reload fw_activate



Similar to reload driver_reinit, the RTNL lock is held across reload
down and up to prevent interleaving state changes.  But we need to
subsequently release the RTNL lock while waiting for firmware reset
to complete.

Also keep a statistic on fw_activate resets initiated remotely from
other functions.

Signed-off-by: default avatarEdwin Peer <edwin.peer@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 228ea8c1
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -2134,7 +2134,9 @@ static int bnxt_async_event_process(struct bnxt *bp,
		bp->fw_reset_max_dsecs = le16_to_cpu(cmpl->timestamp_hi);
		if (!bp->fw_reset_max_dsecs)
			bp->fw_reset_max_dsecs = BNXT_DFLT_FW_RST_MAX_DSECS;
		if (EVENT_DATA1_RESET_NOTIFY_FATAL(data1)) {
		if (EVENT_DATA1_RESET_NOTIFY_FW_ACTIVATION(data1)) {
			set_bit(BNXT_STATE_FW_ACTIVATE_RESET, &bp->state);
		} else if (EVENT_DATA1_RESET_NOTIFY_FATAL(data1)) {
			fatal_str = "fatal";
			set_bit(BNXT_STATE_FW_FATAL_COND, &bp->state);
		}
@@ -12149,6 +12151,9 @@ static void bnxt_fw_reset_task(struct work_struct *work)
			}
		}
		clear_bit(BNXT_STATE_FW_FATAL_COND, &bp->state);
		if (test_and_clear_bit(BNXT_STATE_FW_ACTIVATE_RESET, &bp->state) &&
		    !test_bit(BNXT_STATE_FW_ACTIVATE, &bp->state))
			bnxt_dl_remote_reload(bp);
		if (pci_enable_device(bp->pdev)) {
			netdev_err(bp->dev, "Cannot re-enable PCI device\n");
			rc = -ENODEV;
@@ -12200,6 +12205,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
		bnxt_ptp_reapply_pps(bp);
		bnxt_dl_health_recovery_done(bp);
		bnxt_dl_health_status_update(bp, true);
		clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state);
		rtnl_unlock();
		break;
	}
+7 −0
Original line number Diff line number Diff line
@@ -489,6 +489,11 @@ struct rx_tpa_end_cmp_ext {
	  ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_MASK) ==\
	 ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_FW_EXCEPTION_FATAL)

#define EVENT_DATA1_RESET_NOTIFY_FW_ACTIVATION(data1)			\
	(((data1) &							\
	  ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_MASK) ==\
	ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_FW_ACTIVATION)

#define EVENT_DATA1_RECOVERY_MASTER_FUNC(data1)				\
	!!((data1) &							\
	   ASYNC_EVENT_CMPL_ERROR_RECOVERY_EVENT_DATA1_FLAGS_MASTER_FUNC)
@@ -1888,6 +1893,8 @@ struct bnxt {
#define BNXT_STATE_DRV_REGISTERED	7
#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN	8
#define BNXT_STATE_NAPI_DISABLED	9
#define BNXT_STATE_FW_ACTIVATE		11
#define BNXT_STATE_FW_ACTIVATE_RESET	14

#define BNXT_NO_FW_ACCESS(bp)					\
	(test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) ||	\
+55 −1
Original line number Diff line number Diff line
@@ -327,6 +327,30 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
		bp->ctx = NULL;
		break;
	}
	case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: {
		if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET) {
			NL_SET_ERR_MSG_MOD(extack, "Device not capable, requires reboot");
			return -EOPNOTSUPP;
		}
		rtnl_lock();
		if (bp->dev->reg_state == NETREG_UNREGISTERED) {
			rtnl_unlock();
			return -ENODEV;
		}
		if (netif_running(bp->dev))
			set_bit(BNXT_STATE_FW_ACTIVATE, &bp->state);
		rc = bnxt_hwrm_firmware_reset(bp->dev,
					      FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP,
					      FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP,
					      FW_RESET_REQ_FLAGS_RESET_GRACEFUL |
					      FW_RESET_REQ_FLAGS_FW_ACTIVATION);
		if (rc) {
			NL_SET_ERR_MSG_MOD(extack, "Failed to activate firmware");
			clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state);
			rtnl_unlock();
		}
		break;
	}
	default:
		rc = -EOPNOTSUPP;
	}
@@ -355,6 +379,35 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti
		}
		break;
	}
	case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: {
		unsigned long start = jiffies;
		unsigned long timeout = start + BNXT_DFLT_FW_RST_MAX_DSECS * HZ / 10;

		if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
			timeout = start + bp->fw_health->normal_func_wait_dsecs * HZ / 10;
		if (!netif_running(bp->dev))
			NL_SET_ERR_MSG_MOD(extack,
					   "Device is closed, not waiting for reset notice that will never come");
		rtnl_unlock();
		while (test_bit(BNXT_STATE_FW_ACTIVATE, &bp->state)) {
			if (time_after(jiffies, timeout)) {
				NL_SET_ERR_MSG_MOD(extack, "Activation incomplete");
				rc = -ETIMEDOUT;
				break;
			}
			if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
				NL_SET_ERR_MSG_MOD(extack, "Activation aborted");
				rc = -ENODEV;
				break;
			}
			msleep(50);
		}
		rtnl_lock();
		if (!rc)
			*actions_performed |= BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
		clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state);
		break;
	}
	default:
		return -EOPNOTSUPP;
	}
@@ -381,7 +434,8 @@ static const struct devlink_ops bnxt_dl_ops = {
#endif /* CONFIG_BNXT_SRIOV */
	.info_get	  = bnxt_dl_info_get,
	.flash_update	  = bnxt_dl_flash_update,
	.reload_actions	  = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
	.reload_actions	  = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
			    BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
	.reload_down	  = bnxt_dl_reload_down,
	.reload_up	  = bnxt_dl_reload_up,
};
+7 −0
Original line number Diff line number Diff line
@@ -20,6 +20,13 @@ static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
	return ((struct bnxt_dl *)devlink_priv(dl))->bp;
}

static inline void bnxt_dl_remote_reload(struct bnxt *bp)
{
	devlink_remote_reload_actions_performed(bp->dl, 0,
						BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
						BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE));
}

#define NVM_OFF_MSIX_VEC_PER_PF_MAX	108
#define NVM_OFF_MSIX_VEC_PER_PF_MIN	114
#define NVM_OFF_IGNORE_ARI		164
+2 −2
Original line number Diff line number Diff line
@@ -2180,7 +2180,7 @@ static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type,
	return rc;
}

static int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
			     u8 self_reset, u8 flags)
{
	struct bnxt *bp = netdev_priv(dev);
Loading