mirror of https://gitee.com/openkylin/linux.git
net: qede: add hw err scheduled handler
qede (ethernet level driver) registers a callback handler. This handler maintains eth dev state flags/bits to track error processing. It implements in place processing part for nonsleeping context (WARN_ON trigger), and a deferred (delayed work) part which triggers recovery process for recoverable errors. In later patches this atomic handler will come with more meat. We introduce err_flags on ethdevice structure, its being used to record error handling properties. Signed-off-by: Ariel Elior <ariel.elior@marvell.com> Signed-off-by: Michal Kalderon <michal.kalderon@marvell.com> Signed-off-by: Igor Russkikh <irusskikh@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d639836ab3
commit
a8736ea83b
|
@ -278,6 +278,14 @@ struct qede_dev {
|
||||||
struct qede_rdma_dev rdma_info;
|
struct qede_rdma_dev rdma_info;
|
||||||
|
|
||||||
struct bpf_prog *xdp_prog;
|
struct bpf_prog *xdp_prog;
|
||||||
|
|
||||||
|
unsigned long err_flags;
|
||||||
|
#define QEDE_ERR_IS_HANDLED 31
|
||||||
|
#define QEDE_ERR_ATTN_CLR_EN 0
|
||||||
|
#define QEDE_ERR_GET_DBG_INFO 1
|
||||||
|
#define QEDE_ERR_IS_RECOVERABLE 2
|
||||||
|
#define QEDE_ERR_WARN 3
|
||||||
|
|
||||||
struct qede_dump_info dump_info;
|
struct qede_dump_info dump_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,12 +493,15 @@ struct qede_fastpath {
|
||||||
|
|
||||||
#define QEDE_SP_RECOVERY 0
|
#define QEDE_SP_RECOVERY 0
|
||||||
#define QEDE_SP_RX_MODE 1
|
#define QEDE_SP_RX_MODE 1
|
||||||
|
#define QEDE_SP_RSVD1 2
|
||||||
|
#define QEDE_SP_RSVD2 3
|
||||||
|
#define QEDE_SP_HW_ERR 4
|
||||||
|
#define QEDE_SP_ARFS_CONFIG 5
|
||||||
#define QEDE_SP_AER 7
|
#define QEDE_SP_AER 7
|
||||||
|
|
||||||
#ifdef CONFIG_RFS_ACCEL
|
#ifdef CONFIG_RFS_ACCEL
|
||||||
int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
|
int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
|
||||||
u16 rxq_index, u32 flow_id);
|
u16 rxq_index, u32 flow_id);
|
||||||
#define QEDE_SP_ARFS_CONFIG 4
|
|
||||||
#define QEDE_SP_TASK_POLL_DELAY (5 * HZ)
|
#define QEDE_SP_TASK_POLL_DELAY (5 * HZ)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -139,10 +139,12 @@ static void qede_shutdown(struct pci_dev *pdev);
|
||||||
static void qede_link_update(void *dev, struct qed_link_output *link);
|
static void qede_link_update(void *dev, struct qed_link_output *link);
|
||||||
static void qede_schedule_recovery_handler(void *dev);
|
static void qede_schedule_recovery_handler(void *dev);
|
||||||
static void qede_recovery_handler(struct qede_dev *edev);
|
static void qede_recovery_handler(struct qede_dev *edev);
|
||||||
|
static void qede_schedule_hw_err_handler(void *dev,
|
||||||
|
enum qed_hw_err_type err_type);
|
||||||
static void qede_get_eth_tlv_data(void *edev, void *data);
|
static void qede_get_eth_tlv_data(void *edev, void *data);
|
||||||
static void qede_get_generic_tlv_data(void *edev,
|
static void qede_get_generic_tlv_data(void *edev,
|
||||||
struct qed_generic_tlvs *data);
|
struct qed_generic_tlvs *data);
|
||||||
|
static void qede_generic_hw_err_handler(struct qede_dev *edev);
|
||||||
#ifdef CONFIG_QED_SRIOV
|
#ifdef CONFIG_QED_SRIOV
|
||||||
static int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos,
|
static int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos,
|
||||||
__be16 vlan_proto)
|
__be16 vlan_proto)
|
||||||
|
@ -230,6 +232,7 @@ static struct qed_eth_cb_ops qede_ll_ops = {
|
||||||
#endif
|
#endif
|
||||||
.link_update = qede_link_update,
|
.link_update = qede_link_update,
|
||||||
.schedule_recovery_handler = qede_schedule_recovery_handler,
|
.schedule_recovery_handler = qede_schedule_recovery_handler,
|
||||||
|
.schedule_hw_err_handler = qede_schedule_hw_err_handler,
|
||||||
.get_generic_tlv_data = qede_get_generic_tlv_data,
|
.get_generic_tlv_data = qede_get_generic_tlv_data,
|
||||||
.get_protocol_tlv_data = qede_get_eth_tlv_data,
|
.get_protocol_tlv_data = qede_get_eth_tlv_data,
|
||||||
},
|
},
|
||||||
|
@ -1009,6 +1012,8 @@ static void qede_sp_task(struct work_struct *work)
|
||||||
qede_process_arfs_filters(edev, false);
|
qede_process_arfs_filters(edev, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (test_and_clear_bit(QEDE_SP_HW_ERR, &edev->sp_flags))
|
||||||
|
qede_generic_hw_err_handler(edev);
|
||||||
__qede_unlock(edev);
|
__qede_unlock(edev);
|
||||||
|
|
||||||
if (test_and_clear_bit(QEDE_SP_AER, &edev->sp_flags)) {
|
if (test_and_clear_bit(QEDE_SP_AER, &edev->sp_flags)) {
|
||||||
|
@ -2509,6 +2514,94 @@ static void qede_recovery_handler(struct qede_dev *edev)
|
||||||
qede_recovery_failed(edev);
|
qede_recovery_failed(edev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qede_atomic_hw_err_handler(struct qede_dev *edev)
|
||||||
|
{
|
||||||
|
DP_NOTICE(edev,
|
||||||
|
"Generic non-sleepable HW error handling started - err_flags 0x%lx\n",
|
||||||
|
edev->err_flags);
|
||||||
|
|
||||||
|
/* Get a call trace of the flow that led to the error */
|
||||||
|
WARN_ON(test_bit(QEDE_ERR_WARN, &edev->err_flags));
|
||||||
|
|
||||||
|
DP_NOTICE(edev, "Generic non-sleepable HW error handling is done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qede_generic_hw_err_handler(struct qede_dev *edev)
|
||||||
|
{
|
||||||
|
struct qed_dev *cdev = edev->cdev;
|
||||||
|
|
||||||
|
DP_NOTICE(edev,
|
||||||
|
"Generic sleepable HW error handling started - err_flags 0x%lx\n",
|
||||||
|
edev->err_flags);
|
||||||
|
|
||||||
|
/* Trigger a recovery process.
|
||||||
|
* This is placed in the sleep requiring section just to make
|
||||||
|
* sure it is the last one, and that all the other operations
|
||||||
|
* were completed.
|
||||||
|
*/
|
||||||
|
if (test_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags))
|
||||||
|
edev->ops->common->recovery_process(cdev);
|
||||||
|
|
||||||
|
clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags);
|
||||||
|
|
||||||
|
DP_NOTICE(edev, "Generic sleepable HW error handling is done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qede_set_hw_err_flags(struct qede_dev *edev,
|
||||||
|
enum qed_hw_err_type err_type)
|
||||||
|
{
|
||||||
|
unsigned long err_flags = 0;
|
||||||
|
|
||||||
|
switch (err_type) {
|
||||||
|
case QED_HW_ERR_DMAE_FAIL:
|
||||||
|
set_bit(QEDE_ERR_WARN, &err_flags);
|
||||||
|
fallthrough;
|
||||||
|
case QED_HW_ERR_MFW_RESP_FAIL:
|
||||||
|
case QED_HW_ERR_HW_ATTN:
|
||||||
|
case QED_HW_ERR_RAMROD_FAIL:
|
||||||
|
case QED_HW_ERR_FW_ASSERT:
|
||||||
|
set_bit(QEDE_ERR_ATTN_CLR_EN, &err_flags);
|
||||||
|
set_bit(QEDE_ERR_GET_DBG_INFO, &err_flags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DP_NOTICE(edev, "Unexpected HW error [%d]\n", err_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->err_flags |= err_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qede_schedule_hw_err_handler(void *dev,
|
||||||
|
enum qed_hw_err_type err_type)
|
||||||
|
{
|
||||||
|
struct qede_dev *edev = dev;
|
||||||
|
|
||||||
|
/* Fan failure cannot be masked by handling of another HW error or by a
|
||||||
|
* concurrent recovery process.
|
||||||
|
*/
|
||||||
|
if ((test_and_set_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags) ||
|
||||||
|
edev->state == QEDE_STATE_RECOVERY) &&
|
||||||
|
err_type != QED_HW_ERR_FAN_FAIL) {
|
||||||
|
DP_INFO(edev,
|
||||||
|
"Avoid scheduling an error handling while another HW error is being handled\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err_type >= QED_HW_ERR_LAST) {
|
||||||
|
DP_NOTICE(edev, "Unknown HW error [%d]\n", err_type);
|
||||||
|
clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qede_set_hw_err_flags(edev, err_type);
|
||||||
|
qede_atomic_hw_err_handler(edev);
|
||||||
|
set_bit(QEDE_SP_HW_ERR, &edev->sp_flags);
|
||||||
|
schedule_delayed_work(&edev->sp_task, 0);
|
||||||
|
|
||||||
|
DP_INFO(edev, "Scheduled a error handler [err_type %d]\n", err_type);
|
||||||
|
}
|
||||||
|
|
||||||
static bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq)
|
static bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq)
|
||||||
{
|
{
|
||||||
struct netdev_queue *netdev_txq;
|
struct netdev_queue *netdev_txq;
|
||||||
|
|
Loading…
Reference in New Issue