Commit 710f3e59 authored by Sriharsha Basavapatna's avatar Sriharsha Basavapatna Committed by David S. Miller

be2net: Support UE recovery in BEx/Skyhawk adapters

This patch supports recovery from UEs caused due to Transient Parity
Errors (TPE), in BE2, BE3 and Skyhawk adapters. This change avoids
system reboot when such errors occur. The driver recovers from these
errors such that the adapter resumes full operational status as prior
to the UE.

Following is the list of changes in the driver to support this:

o The driver registers its UE recoverable capability with ARM FW at init
time. This also allows the driver to know if the feature is supported in
the FW.

o As the UE recovery requires precise time bound processing, the driver
creates its own error recovery work queue with a single worker thread (per
module, shared across functions).

o Each function runs an error detection task at an interval of 1 second as
required by the FW. The error detection logic already exists for BEx/SH,
but it now runs in the context of a separate worker thread.

o When an error is detected by the task, if it is recoverable, the PF0
driver instance initiates a soft reset, while other PF driver instances
wait for the reset to complete and the chip to become ready. Once
the chip is ready, all driver instances including PF0, resume to
reinitialize the respective functions.

o The PF0 driver checks for some recovery criteria, to determine if the
recovery can be initiated. If the criteria is not met, the PF0 driver does
not initiate a soft reset, it retains the existing behavior to stop
further processing and requires a reboot to get the chip to operational
state again.

o To allow each function to share the workq, while also making progress in
its recovery process, a per-function recovery state machine is used.
The per-function tasks avoid blocking operations like msleep() while in
this state machine (until reinit state) and instead reschedule for the
required delay.

o With these changes, the existing error recovery code for Lancer also
runs in the context of the new worker thread.
Signed-off-by: default avatarSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dd0cb7db
......@@ -399,13 +399,13 @@ enum vf_state {
#define BE_FLAGS_PHY_MISCONFIGURED BIT(10)
#define BE_FLAGS_ERR_DETECTION_SCHEDULED BIT(11)
#define BE_FLAGS_OS2BMC BIT(12)
#define BE_FLAGS_TRY_RECOVERY BIT(13)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
#define MAX_ERR_RECOVERY_RETRY_COUNT 3
#define ERR_DETECTION_DELAY 1000
#define ERR_RECOVERY_RETRY_DELAY 30000
/* Ethtool set_dump flags */
#define LANCER_INITIATE_FW_DUMP 0x1
......@@ -512,6 +512,66 @@ struct be_eth_addr {
unsigned char mac[ETH_ALEN];
};
#define BE_SEC 1000 /* in msec */
#define BE_MIN (60 * BE_SEC) /* in msec */
#define BE_HOUR (60 * BE_MIN) /* in msec */
#define ERR_RECOVERY_MAX_RETRY_COUNT 3
#define ERR_RECOVERY_DETECTION_DELAY BE_SEC
#define ERR_RECOVERY_RETRY_DELAY (30 * BE_SEC)
/* UE-detection-duration in BEx/Skyhawk:
* All PFs must wait for this duration after they detect UE before reading
* SLIPORT_SEMAPHORE register. At the end of this duration, the Firmware
* guarantees that the SLIPORT_SEMAPHORE register is updated to indicate
* if the UE is recoverable.
*/
#define ERR_RECOVERY_UE_DETECT_DURATION BE_SEC
/* Initial idle time (in msec) to elapse after driver load,
* before UE recovery is allowed.
*/
#define ERR_IDLE_HR 24
#define ERR_RECOVERY_IDLE_TIME (ERR_IDLE_HR * BE_HOUR)
/* Time interval (in msec) after which UE recovery can be repeated */
#define ERR_INTERVAL_HR 72
#define ERR_RECOVERY_INTERVAL (ERR_INTERVAL_HR * BE_HOUR)
/* BEx/SH UE recovery state machine */
enum {
ERR_RECOVERY_ST_NONE = 0, /* No Recovery */
ERR_RECOVERY_ST_DETECT = 1, /* UE detection duration */
ERR_RECOVERY_ST_RESET = 2, /* Reset Phase (PF0 only) */
ERR_RECOVERY_ST_PRE_POLL = 3, /* Pre-Poll Phase (all PFs) */
ERR_RECOVERY_ST_REINIT = 4 /* Re-initialize Phase */
};
struct be_error_recovery {
/* Lancer error recovery variables */
u8 recovery_retries;
/* BEx/Skyhawk error recovery variables */
u8 recovery_state;
u16 ue_to_reset_time; /* Time after UE, to soft reset
* the chip - PF0 only
*/
u16 ue_to_poll_time; /* Time after UE, to Restart Polling
* of SLIPORT_SEMAPHORE reg
*/
u16 last_err_code;
bool recovery_supported;
unsigned long probe_time;
unsigned long last_recovery_time;
/* Common to both Lancer & BEx/SH error recovery */
u32 resched_delay;
struct delayed_work err_detection_work;
};
/* Ethtool priv_flags */
#define BE_DISABLE_TPE_RECOVERY 0x1
struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
......@@ -560,7 +620,6 @@ struct be_adapter {
struct delayed_work work;
u16 work_counter;
struct delayed_work be_err_detection_work;
u8 recovery_retries;
u8 err_flags;
bool pcicfg_mapped; /* pcicfg obtained via pci_iomap() */
......@@ -634,6 +693,8 @@ struct be_adapter {
u32 fat_dump_len;
u16 serial_num[CNTL_SERIAL_NUM_WORDS];
u8 phy_state; /* state of sfp optics (functional, faulted, etc.,) */
u32 priv_flags; /* ethtool get/set_priv_flags() */
struct be_error_recovery error_recovery;
};
/* Used for defered FW config cmds. Add fields to this struct as reqd */
......@@ -867,6 +928,9 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb)
return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
}
#define be_error_recovering(adapter) \
(adapter->flags & BE_FLAGS_TRY_RECOVERY)
#define BE_ERROR_EEH 1
#define BE_ERROR_UE BIT(1)
#define BE_ERROR_FW BIT(2)
......
......@@ -705,7 +705,7 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
return 0;
}
static u16 be_POST_stage_get(struct be_adapter *adapter)
u16 be_POST_stage_get(struct be_adapter *adapter)
{
u32 sem;
......@@ -4954,6 +4954,57 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter,
1, domain);
return status;
}
int be_cmd_set_features(struct be_adapter *adapter)
{
struct be_cmd_resp_set_features *resp;
struct be_cmd_req_set_features *req;
struct be_mcc_wrb *wrb;
int status;
if (mutex_lock_interruptible(&adapter->mcc_lock))
return -1;
wrb = wrb_from_mccq(adapter);
if (!wrb) {
status = -EBUSY;
goto err;
}
req = embedded_payload(wrb);
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_SET_FEATURES,
sizeof(*req), wrb, NULL);
req->features = cpu_to_le32(BE_FEATURE_UE_RECOVERY);
req->parameter_len = cpu_to_le32(sizeof(struct be_req_ue_recovery));
req->parameter.req.uer = cpu_to_le32(BE_UE_RECOVERY_UER_MASK);
status = be_mcc_notify_wait(adapter);
if (status)
goto err;
resp = embedded_payload(wrb);
adapter->error_recovery.ue_to_poll_time =
le16_to_cpu(resp->parameter.resp.ue2rp);
adapter->error_recovery.ue_to_reset_time =
le16_to_cpu(resp->parameter.resp.ue2sr);
adapter->error_recovery.recovery_supported = true;
err:
/* Checking "MCC_STATUS_INVALID_LENGTH" for SKH as FW
* returns this error in older firmware versions
*/
if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST ||
base_status(status) == MCC_STATUS_INVALID_LENGTH)
dev_info(&adapter->pdev->dev,
"Adapter does not support HW error recovery\n");
mutex_unlock(&adapter->mcc_lock);
return status;
}
int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
{
......
......@@ -58,7 +58,8 @@ enum mcc_base_status {
MCC_STATUS_INSUFFICIENT_BUFFER = 4,
MCC_STATUS_UNAUTHORIZED_REQUEST = 5,
MCC_STATUS_NOT_SUPPORTED = 66,
MCC_STATUS_FEATURE_NOT_SUPPORTED = 68
MCC_STATUS_FEATURE_NOT_SUPPORTED = 68,
MCC_STATUS_INVALID_LENGTH = 116
};
/* Additional status */
......@@ -308,6 +309,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_READ_OBJECT 171
#define OPCODE_COMMON_WRITE_OBJECT 172
#define OPCODE_COMMON_DELETE_OBJECT 174
#define OPCODE_COMMON_SET_FEATURES 191
#define OPCODE_COMMON_MANAGE_IFACE_FILTERS 193
#define OPCODE_COMMON_GET_IFACE_LIST 194
#define OPCODE_COMMON_ENABLE_DISABLE_VF 196
......@@ -2315,6 +2317,41 @@ struct be_cmd_resp_get_iface_list {
struct be_if_desc if_desc;
};
/************** Set Features *******************/
#define BE_FEATURE_UE_RECOVERY 0x10
#define BE_UE_RECOVERY_UER_MASK 0x1
struct be_req_ue_recovery {
u32 uer;
u32 rsvd;
};
struct be_cmd_req_set_features {
struct be_cmd_req_hdr hdr;
u32 features;
u32 parameter_len;
union {
struct be_req_ue_recovery req;
u32 rsvd[2];
} parameter;
};
struct be_resp_ue_recovery {
u32 uer;
u16 ue2rp;
u16 ue2sr;
};
struct be_cmd_resp_set_features {
struct be_cmd_resp_hdr hdr;
u32 features;
u32 parameter_len;
union {
struct be_resp_ue_recovery resp;
u32 rsvd[2];
} parameter;
};
/*************** Set logical link ********************/
#define PLINK_ENABLE BIT(0)
#define PLINK_TRACK BIT(8)
......@@ -2343,6 +2380,7 @@ struct be_cmd_req_manage_iface_filters {
u32 cap_control_flags;
} __packed;
u16 be_POST_stage_get(struct be_adapter *adapter);
int be_pci_fnum_get(struct be_adapter *adapter);
int be_fw_wait_ready(struct be_adapter *adapter);
int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
......@@ -2470,3 +2508,4 @@ int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op);
int be_cmd_set_sriov_config(struct be_adapter *adapter,
struct be_resources res, u16 num_vfs,
struct be_resources *vft_res);
int be_cmd_set_features(struct be_adapter *adapter);
......@@ -421,6 +421,10 @@ static void be_get_ethtool_stats(struct net_device *netdev,
}
}
static const char be_priv_flags[][ETH_GSTRING_LEN] = {
"disable-tpe-recovery"
};
static void be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
uint8_t *data)
{
......@@ -454,6 +458,10 @@ static void be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
data += ETH_GSTRING_LEN;
}
break;
case ETH_SS_PRIV_FLAGS:
for (i = 0; i < ARRAY_SIZE(be_priv_flags); i++)
strcpy(data + i * ETH_GSTRING_LEN, be_priv_flags[i]);
break;
}
}
......@@ -468,6 +476,8 @@ static int be_get_sset_count(struct net_device *netdev, int stringset)
return ETHTOOL_STATS_NUM +
adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM +
adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM;
case ETH_SS_PRIV_FLAGS:
return ARRAY_SIZE(be_priv_flags);
default:
return -EINVAL;
}
......@@ -1360,6 +1370,34 @@ static int be_get_module_eeprom(struct net_device *netdev,
return be_cmd_status(status);
}
static u32 be_get_priv_flags(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
return adapter->priv_flags;
}
static int be_set_priv_flags(struct net_device *netdev, u32 flags)
{
struct be_adapter *adapter = netdev_priv(netdev);
bool tpe_old = !!(adapter->priv_flags & BE_DISABLE_TPE_RECOVERY);
bool tpe_new = !!(flags & BE_DISABLE_TPE_RECOVERY);
if (tpe_old != tpe_new) {
if (tpe_new) {
adapter->priv_flags |= BE_DISABLE_TPE_RECOVERY;
dev_info(&adapter->pdev->dev,
"HW error recovery is disabled\n");
} else {
adapter->priv_flags &= ~BE_DISABLE_TPE_RECOVERY;
dev_info(&adapter->pdev->dev,
"HW error recovery is enabled\n");
}
}
return 0;
}
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
......@@ -1373,6 +1411,8 @@ const struct ethtool_ops be_ethtool_ops = {
.get_ringparam = be_get_ringparam,
.get_pauseparam = be_get_pauseparam,
.set_pauseparam = be_set_pauseparam,
.set_priv_flags = be_set_priv_flags,
.get_priv_flags = be_get_priv_flags,
.get_strings = be_get_stat_strings,
.set_phys_id = be_set_phys_id,
.set_dump = be_set_dump,
......
......@@ -32,18 +32,23 @@
#define MPU_EP_CONTROL 0
/********** MPU semphore: used for SH & BE *************/
#define SLIPORT_SOFTRESET_OFFSET 0x5c /* CSR BAR offset */
#define SLIPORT_SEMAPHORE_OFFSET_BEx 0xac /* CSR BAR offset */
#define SLIPORT_SEMAPHORE_OFFSET_SH 0x94 /* PCI-CFG offset */
#define POST_STAGE_MASK 0x0000FFFF
#define POST_ERR_MASK 0x1
#define POST_ERR_SHIFT 31
#define POST_ERR_RECOVERY_CODE_MASK 0xFFF
/* Soft Reset register masks */
#define SLIPORT_SOFTRESET_SR_MASK 0x00000080 /* SR bit */
/* MPU semphore POST stage values */
#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
#define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */
#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
#define POST_STAGE_RECOVERABLE_ERR 0xE000 /* Recoverable err detected */
/* Lancer SLIPORT registers */
#define SLIPORT_STATUS_OFFSET 0x404
......
This diff is collapsed.
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