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

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
...@@ -2134,7 +2134,9 @@ static int bnxt_async_event_process(struct bnxt *bp, ...@@ -2134,7 +2134,9 @@ static int bnxt_async_event_process(struct bnxt *bp,
bp->fw_reset_max_dsecs = le16_to_cpu(cmpl->timestamp_hi); bp->fw_reset_max_dsecs = le16_to_cpu(cmpl->timestamp_hi);
if (!bp->fw_reset_max_dsecs) if (!bp->fw_reset_max_dsecs)
bp->fw_reset_max_dsecs = BNXT_DFLT_FW_RST_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"; fatal_str = "fatal";
set_bit(BNXT_STATE_FW_FATAL_COND, &bp->state); set_bit(BNXT_STATE_FW_FATAL_COND, &bp->state);
} }
...@@ -12149,6 +12151,9 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12149,6 +12151,9 @@ static void bnxt_fw_reset_task(struct work_struct *work)
} }
} }
clear_bit(BNXT_STATE_FW_FATAL_COND, &bp->state); 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)) { if (pci_enable_device(bp->pdev)) {
netdev_err(bp->dev, "Cannot re-enable PCI device\n"); netdev_err(bp->dev, "Cannot re-enable PCI device\n");
rc = -ENODEV; rc = -ENODEV;
...@@ -12200,6 +12205,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12200,6 +12205,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bnxt_ptp_reapply_pps(bp); bnxt_ptp_reapply_pps(bp);
bnxt_dl_health_recovery_done(bp); bnxt_dl_health_recovery_done(bp);
bnxt_dl_health_status_update(bp, true); bnxt_dl_health_status_update(bp, true);
clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state);
rtnl_unlock(); rtnl_unlock();
break; break;
} }
......
...@@ -489,6 +489,11 @@ struct rx_tpa_end_cmp_ext { ...@@ -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_MASK) ==\
ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_FW_EXCEPTION_FATAL) 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) \ #define EVENT_DATA1_RECOVERY_MASTER_FUNC(data1) \
!!((data1) & \ !!((data1) & \
ASYNC_EVENT_CMPL_ERROR_RECOVERY_EVENT_DATA1_FLAGS_MASTER_FUNC) ASYNC_EVENT_CMPL_ERROR_RECOVERY_EVENT_DATA1_FLAGS_MASTER_FUNC)
...@@ -1888,6 +1893,8 @@ struct bnxt { ...@@ -1888,6 +1893,8 @@ struct bnxt {
#define BNXT_STATE_DRV_REGISTERED 7 #define BNXT_STATE_DRV_REGISTERED 7
#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN 8 #define BNXT_STATE_PCI_CHANNEL_IO_FROZEN 8
#define BNXT_STATE_NAPI_DISABLED 9 #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) \ #define BNXT_NO_FW_ACCESS(bp) \
(test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) || \ (test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) || \
......
...@@ -327,6 +327,30 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change, ...@@ -327,6 +327,30 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
bp->ctx = NULL; bp->ctx = NULL;
break; 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: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
...@@ -355,6 +379,35 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti ...@@ -355,6 +379,35 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti
} }
break; 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: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -381,7 +434,8 @@ static const struct devlink_ops bnxt_dl_ops = { ...@@ -381,7 +434,8 @@ static const struct devlink_ops bnxt_dl_ops = {
#endif /* CONFIG_BNXT_SRIOV */ #endif /* CONFIG_BNXT_SRIOV */
.info_get = bnxt_dl_info_get, .info_get = bnxt_dl_info_get,
.flash_update = bnxt_dl_flash_update, .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_down = bnxt_dl_reload_down,
.reload_up = bnxt_dl_reload_up, .reload_up = bnxt_dl_reload_up,
}; };
......
...@@ -20,6 +20,13 @@ static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl) ...@@ -20,6 +20,13 @@ static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
return ((struct bnxt_dl *)devlink_priv(dl))->bp; 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_MAX 108
#define NVM_OFF_MSIX_VEC_PER_PF_MIN 114 #define NVM_OFF_MSIX_VEC_PER_PF_MIN 114
#define NVM_OFF_IGNORE_ARI 164 #define NVM_OFF_IGNORE_ARI 164
......
...@@ -2180,7 +2180,7 @@ static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, ...@@ -2180,7 +2180,7 @@ static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type,
return rc; 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) u8 self_reset, u8 flags)
{ {
struct bnxt *bp = netdev_priv(dev); struct bnxt *bp = netdev_priv(dev);
......
...@@ -94,6 +94,8 @@ u32 bnxt_fw_to_ethtool_speed(u16); ...@@ -94,6 +94,8 @@ u32 bnxt_fw_to_ethtool_speed(u16);
u16 bnxt_get_fw_auto_link_speeds(u32); u16 bnxt_get_fw_auto_link_speeds(u32);
int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp,
struct hwrm_nvm_get_dev_info_output *nvm_dev_info); struct hwrm_nvm_get_dev_info_output *nvm_dev_info);
int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
u8 self_reset, u8 flags);
int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw,
u32 install_type); u32 install_type);
void bnxt_ethtool_init(struct bnxt *bp); void bnxt_ethtool_init(struct bnxt *bp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment