Commit 1dd271d9 authored by David S. Miller's avatar David S. Miller

Merge branch 'bnxt_en-fixes'

Michael Chan says:

====================
bnxt_en: Bug fixes

Most of the fixes in this series have to do with error recovery.  They
include error path handling when the error recovery has to abort, and
the rediscovery of capabilities (PTP and RoCE) after firmware reset
that may result in capability changes.

Two other fixes are to reject invalid ETS settings and to validate
VLAN protocol in the RX path.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 517a16b1 de5bf194
...@@ -1671,11 +1671,16 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, ...@@ -1671,11 +1671,16 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
if ((tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) && if ((tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) &&
(skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) { (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) {
u16 vlan_proto = tpa_info->metadata >> __be16 vlan_proto = htons(tpa_info->metadata >>
RX_CMP_FLAGS2_METADATA_TPID_SFT; RX_CMP_FLAGS2_METADATA_TPID_SFT);
u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_TCI_MASK; u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_TCI_MASK;
__vlan_hwaccel_put_tag(skb, htons(vlan_proto), vtag); if (eth_type_vlan(vlan_proto)) {
__vlan_hwaccel_put_tag(skb, vlan_proto, vtag);
} else {
dev_kfree_skb(skb);
return NULL;
}
} }
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
...@@ -1897,9 +1902,15 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, ...@@ -1897,9 +1902,15 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
(skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) { (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) {
u32 meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data); u32 meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data);
u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK; u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK;
u16 vlan_proto = meta_data >> RX_CMP_FLAGS2_METADATA_TPID_SFT; __be16 vlan_proto = htons(meta_data >>
RX_CMP_FLAGS2_METADATA_TPID_SFT);
__vlan_hwaccel_put_tag(skb, htons(vlan_proto), vtag); if (eth_type_vlan(vlan_proto)) {
__vlan_hwaccel_put_tag(skb, vlan_proto, vtag);
} else {
dev_kfree_skb(skb);
goto next_rx;
}
} }
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
...@@ -7563,8 +7574,12 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) ...@@ -7563,8 +7574,12 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
bp->flags &= ~BNXT_FLAG_WOL_CAP; bp->flags &= ~BNXT_FLAG_WOL_CAP;
if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED) if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)
bp->flags |= BNXT_FLAG_WOL_CAP; bp->flags |= BNXT_FLAG_WOL_CAP;
if (flags & FUNC_QCAPS_RESP_FLAGS_PTP_SUPPORTED) if (flags & FUNC_QCAPS_RESP_FLAGS_PTP_SUPPORTED) {
__bnxt_hwrm_ptp_qcfg(bp); __bnxt_hwrm_ptp_qcfg(bp);
} else {
kfree(bp->ptp_cfg);
bp->ptp_cfg = NULL;
}
} else { } else {
#ifdef CONFIG_BNXT_SRIOV #ifdef CONFIG_BNXT_SRIOV
struct bnxt_vf_info *vf = &bp->vf; struct bnxt_vf_info *vf = &bp->vf;
...@@ -10123,7 +10138,6 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) ...@@ -10123,7 +10138,6 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
} }
} }
bnxt_ptp_start(bp);
rc = bnxt_init_nic(bp, irq_re_init); rc = bnxt_init_nic(bp, irq_re_init);
if (rc) { if (rc) {
netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc); netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
...@@ -10197,6 +10211,12 @@ int bnxt_half_open_nic(struct bnxt *bp) ...@@ -10197,6 +10211,12 @@ int bnxt_half_open_nic(struct bnxt *bp)
{ {
int rc = 0; int rc = 0;
if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
netdev_err(bp->dev, "A previous firmware reset has not completed, aborting half open\n");
rc = -ENODEV;
goto half_open_err;
}
rc = bnxt_alloc_mem(bp, false); rc = bnxt_alloc_mem(bp, false);
if (rc) { if (rc) {
netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc); netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
...@@ -10256,9 +10276,16 @@ static int bnxt_open(struct net_device *dev) ...@@ -10256,9 +10276,16 @@ static int bnxt_open(struct net_device *dev)
rc = bnxt_hwrm_if_change(bp, true); rc = bnxt_hwrm_if_change(bp, true);
if (rc) if (rc)
return rc; return rc;
if (bnxt_ptp_init(bp)) {
netdev_warn(dev, "PTP initialization failed.\n");
kfree(bp->ptp_cfg);
bp->ptp_cfg = NULL;
}
rc = __bnxt_open_nic(bp, true, true); rc = __bnxt_open_nic(bp, true, true);
if (rc) { if (rc) {
bnxt_hwrm_if_change(bp, false); bnxt_hwrm_if_change(bp, false);
bnxt_ptp_clear(bp);
} else { } else {
if (test_and_clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state)) { if (test_and_clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state)) {
if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
...@@ -10349,6 +10376,7 @@ static int bnxt_close(struct net_device *dev) ...@@ -10349,6 +10376,7 @@ static int bnxt_close(struct net_device *dev)
{ {
struct bnxt *bp = netdev_priv(dev); struct bnxt *bp = netdev_priv(dev);
bnxt_ptp_clear(bp);
bnxt_hwmon_close(bp); bnxt_hwmon_close(bp);
bnxt_close_nic(bp, true, true); bnxt_close_nic(bp, true, true);
bnxt_hwrm_shutdown_link(bp); bnxt_hwrm_shutdown_link(bp);
...@@ -11335,6 +11363,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp) ...@@ -11335,6 +11363,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp)
bnxt_clear_int_mode(bp); bnxt_clear_int_mode(bp);
pci_disable_device(bp->pdev); pci_disable_device(bp->pdev);
} }
bnxt_ptp_clear(bp);
__bnxt_close_nic(bp, true, false); __bnxt_close_nic(bp, true, false);
bnxt_vf_reps_free(bp); bnxt_vf_reps_free(bp);
bnxt_clear_int_mode(bp); bnxt_clear_int_mode(bp);
...@@ -11959,10 +11988,21 @@ static bool bnxt_fw_reset_timeout(struct bnxt *bp) ...@@ -11959,10 +11988,21 @@ static bool bnxt_fw_reset_timeout(struct bnxt *bp)
(bp->fw_reset_max_dsecs * HZ / 10)); (bp->fw_reset_max_dsecs * HZ / 10));
} }
static void bnxt_fw_reset_abort(struct bnxt *bp, int rc)
{
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
if (bp->fw_reset_state != BNXT_FW_RESET_STATE_POLL_VF) {
bnxt_ulp_start(bp, rc);
bnxt_dl_health_status_update(bp, false);
}
bp->fw_reset_state = 0;
dev_close(bp->dev);
}
static void bnxt_fw_reset_task(struct work_struct *work) static void bnxt_fw_reset_task(struct work_struct *work)
{ {
struct bnxt *bp = container_of(work, struct bnxt, fw_reset_task.work); struct bnxt *bp = container_of(work, struct bnxt, fw_reset_task.work);
int rc; int rc = 0;
if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
netdev_err(bp->dev, "bnxt_fw_reset_task() called when not in fw reset mode!\n"); netdev_err(bp->dev, "bnxt_fw_reset_task() called when not in fw reset mode!\n");
...@@ -11992,6 +12032,11 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -11992,6 +12032,11 @@ static void bnxt_fw_reset_task(struct work_struct *work)
} }
bp->fw_reset_timestamp = jiffies; bp->fw_reset_timestamp = jiffies;
rtnl_lock(); rtnl_lock();
if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
bnxt_fw_reset_abort(bp, rc);
rtnl_unlock();
return;
}
bnxt_fw_reset_close(bp); bnxt_fw_reset_close(bp);
if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) { if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) {
bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW_DOWN; bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW_DOWN;
...@@ -12039,6 +12084,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12039,6 +12084,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
if (val == 0xffff) { if (val == 0xffff) {
if (bnxt_fw_reset_timeout(bp)) { if (bnxt_fw_reset_timeout(bp)) {
netdev_err(bp->dev, "Firmware reset aborted, PCI config space invalid\n"); netdev_err(bp->dev, "Firmware reset aborted, PCI config space invalid\n");
rc = -ETIMEDOUT;
goto fw_reset_abort; goto fw_reset_abort;
} }
bnxt_queue_fw_reset_work(bp, HZ / 1000); bnxt_queue_fw_reset_work(bp, HZ / 1000);
...@@ -12048,6 +12094,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12048,6 +12094,7 @@ 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 (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;
goto fw_reset_abort; goto fw_reset_abort;
} }
pci_set_master(bp->pdev); pci_set_master(bp->pdev);
...@@ -12074,9 +12121,10 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12074,9 +12121,10 @@ static void bnxt_fw_reset_task(struct work_struct *work)
} }
rc = bnxt_open(bp->dev); rc = bnxt_open(bp->dev);
if (rc) { if (rc) {
netdev_err(bp->dev, "bnxt_open_nic() failed\n"); netdev_err(bp->dev, "bnxt_open() failed during FW reset\n");
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); bnxt_fw_reset_abort(bp, rc);
dev_close(bp->dev); rtnl_unlock();
return;
} }
bp->fw_reset_state = 0; bp->fw_reset_state = 0;
...@@ -12103,12 +12151,8 @@ static void bnxt_fw_reset_task(struct work_struct *work) ...@@ -12103,12 +12151,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)
netdev_err(bp->dev, "fw_health_status 0x%x\n", sts); netdev_err(bp->dev, "fw_health_status 0x%x\n", sts);
} }
fw_reset_abort: fw_reset_abort:
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
if (bp->fw_reset_state != BNXT_FW_RESET_STATE_POLL_VF)
bnxt_dl_health_status_update(bp, false);
bp->fw_reset_state = 0;
rtnl_lock(); rtnl_lock();
dev_close(bp->dev); bnxt_fw_reset_abort(bp, rc);
rtnl_unlock(); rtnl_unlock();
} }
...@@ -12662,7 +12706,6 @@ static void bnxt_remove_one(struct pci_dev *pdev) ...@@ -12662,7 +12706,6 @@ static void bnxt_remove_one(struct pci_dev *pdev)
if (BNXT_PF(bp)) if (BNXT_PF(bp))
devlink_port_type_clear(&bp->dl_port); devlink_port_type_clear(&bp->dl_port);
bnxt_ptp_clear(bp);
pci_disable_pcie_error_reporting(pdev); pci_disable_pcie_error_reporting(pdev);
unregister_netdev(dev); unregister_netdev(dev);
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
...@@ -13246,11 +13289,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -13246,11 +13289,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc); rc);
} }
if (bnxt_ptp_init(bp)) {
netdev_warn(dev, "PTP initialization failed.\n");
kfree(bp->ptp_cfg);
bp->ptp_cfg = NULL;
}
bnxt_inv_fw_health_reg(bp); bnxt_inv_fw_health_reg(bp);
bnxt_dl_register(bp); bnxt_dl_register(bp);
...@@ -13436,7 +13474,8 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev, ...@@ -13436,7 +13474,8 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
if (netif_running(netdev)) if (netif_running(netdev))
bnxt_close(netdev); bnxt_close(netdev);
pci_disable_device(pdev); if (pci_is_enabled(pdev))
pci_disable_device(pdev);
bnxt_free_ctx_mem(bp); bnxt_free_ctx_mem(bp);
kfree(bp->ctx); kfree(bp->ctx);
bp->ctx = NULL; bp->ctx = NULL;
......
...@@ -433,6 +433,7 @@ static int bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt *bp, struct dcb_app *app, ...@@ -433,6 +433,7 @@ static int bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt *bp, struct dcb_app *app,
static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc) static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
{ {
int total_ets_bw = 0; int total_ets_bw = 0;
bool zero = false;
u8 max_tc = 0; u8 max_tc = 0;
int i; int i;
...@@ -453,13 +454,20 @@ static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc) ...@@ -453,13 +454,20 @@ static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
break; break;
case IEEE_8021QAZ_TSA_ETS: case IEEE_8021QAZ_TSA_ETS:
total_ets_bw += ets->tc_tx_bw[i]; total_ets_bw += ets->tc_tx_bw[i];
zero = zero || !ets->tc_tx_bw[i];
break; break;
default: default:
return -ENOTSUPP; return -ENOTSUPP;
} }
} }
if (total_ets_bw > 100) if (total_ets_bw > 100) {
netdev_warn(bp->dev, "rejecting ETS config exceeding available bandwidth\n");
return -EINVAL; return -EINVAL;
}
if (zero && total_ets_bw == 100) {
netdev_warn(bp->dev, "rejecting ETS config starving a TC\n");
return -EINVAL;
}
if (max_tc >= bp->max_tc) if (max_tc >= bp->max_tc)
*tc = bp->max_tc; *tc = bp->max_tc;
......
...@@ -385,22 +385,6 @@ int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts) ...@@ -385,22 +385,6 @@ int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts)
return 0; return 0;
} }
void bnxt_ptp_start(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
if (!ptp)
return;
if (bp->flags & BNXT_FLAG_CHIP_P5) {
spin_lock_bh(&ptp->ptp_lock);
ptp->current_time = bnxt_refclk_read(bp, NULL);
WRITE_ONCE(ptp->old_time, ptp->current_time);
spin_unlock_bh(&ptp->ptp_lock);
ptp_schedule_worker(ptp->ptp_clock, 0);
}
}
static const struct ptp_clock_info bnxt_ptp_caps = { static const struct ptp_clock_info bnxt_ptp_caps = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "bnxt clock", .name = "bnxt clock",
...@@ -450,7 +434,13 @@ int bnxt_ptp_init(struct bnxt *bp) ...@@ -450,7 +434,13 @@ int bnxt_ptp_init(struct bnxt *bp)
bnxt_unmap_ptp_regs(bp); bnxt_unmap_ptp_regs(bp);
return err; return err;
} }
if (bp->flags & BNXT_FLAG_CHIP_P5) {
spin_lock_bh(&ptp->ptp_lock);
ptp->current_time = bnxt_refclk_read(bp, NULL);
WRITE_ONCE(ptp->old_time, ptp->current_time);
spin_unlock_bh(&ptp->ptp_lock);
ptp_schedule_worker(ptp->ptp_clock, 0);
}
return 0; return 0;
} }
......
...@@ -75,7 +75,6 @@ int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr); ...@@ -75,7 +75,6 @@ int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr);
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr); int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr);
int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb); int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb);
int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts); int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts);
void bnxt_ptp_start(struct bnxt *bp);
int bnxt_ptp_init(struct bnxt *bp); int bnxt_ptp_init(struct bnxt *bp);
void bnxt_ptp_clear(struct bnxt *bp); void bnxt_ptp_clear(struct bnxt *bp);
#endif #endif
...@@ -479,16 +479,17 @@ struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev) ...@@ -479,16 +479,17 @@ struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
if (!edev) if (!edev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
edev->en_ops = &bnxt_en_ops_tbl; edev->en_ops = &bnxt_en_ops_tbl;
if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
edev->net = dev; edev->net = dev;
edev->pdev = bp->pdev; edev->pdev = bp->pdev;
edev->l2_db_size = bp->db_size; edev->l2_db_size = bp->db_size;
edev->l2_db_size_nc = bp->db_size; edev->l2_db_size_nc = bp->db_size;
bp->edev = edev; bp->edev = edev;
} }
edev->flags &= ~BNXT_EN_FLAG_ROCE_CAP;
if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
return bp->edev; return bp->edev;
} }
EXPORT_SYMBOL(bnxt_ulp_probe); EXPORT_SYMBOL(bnxt_ulp_probe);
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