aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuval Mintz <yuvalmin@broadcom.com>2013-03-20 01:21:28 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-20 13:27:28 -0400
commit7fa6f34081f168975af72be51715bdc6601931f7 (patch)
tree5b69dcc7f444fee1eb678ae4b8146ac00c82d736
parent47a5247fddf30a1c0d1f5a1afb3bd17e8715075e (diff)
bnx2x: AER revised
Revised bnx2x implementation of PCI Express Advanced Error Recovery - stop and free driver resources according to the AER flow (instead of the currently implemented `hope-for-the-best' release approach), and do not make any assumptions on the HW state after slot reset. Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com> Signed-off-by: Ariel Elior <ariele@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c149
4 files changed, 130 insertions, 30 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index a4729c73ab80..c59da2d7b065 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1226,10 +1226,11 @@ enum {
1226 1226
1227 1227
1228struct bnx2x_prev_path_list { 1228struct bnx2x_prev_path_list {
1229 struct list_head list;
1229 u8 bus; 1230 u8 bus;
1230 u8 slot; 1231 u8 slot;
1231 u8 path; 1232 u8 path;
1232 struct list_head list; 1233 u8 aer;
1233 u8 undi; 1234 u8 undi;
1234}; 1235};
1235 1236
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index db6912b09997..3f5cd7c9f103 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -2010,7 +2010,7 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
2010 * Cleans the object that have internal lists without sending 2010 * Cleans the object that have internal lists without sending
2011 * ramrods. Should be run when interrutps are disabled. 2011 * ramrods. Should be run when interrutps are disabled.
2012 */ 2012 */
2013static void bnx2x_squeeze_objects(struct bnx2x *bp) 2013void bnx2x_squeeze_objects(struct bnx2x *bp)
2014{ 2014{
2015 int rc; 2015 int rc;
2016 unsigned long ramrod_flags = 0, vlan_mac_flags = 0; 2016 unsigned long ramrod_flags = 0, vlan_mac_flags = 0;
@@ -2775,7 +2775,7 @@ load_error0:
2775#endif /* ! BNX2X_STOP_ON_ERROR */ 2775#endif /* ! BNX2X_STOP_ON_ERROR */
2776} 2776}
2777 2777
2778static int bnx2x_drain_tx_queues(struct bnx2x *bp) 2778int bnx2x_drain_tx_queues(struct bnx2x *bp)
2779{ 2779{
2780 u8 rc = 0, cos, i; 2780 u8 rc = 0, cos, i;
2781 2781
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index f9098d8fc25b..54e1b149acb3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1402,4 +1402,8 @@ static inline bool bnx2x_is_valid_ether_addr(struct bnx2x *bp, u8 *addr)
1402 * 1402 *
1403 */ 1403 */
1404void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len); 1404void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
1405
1406int bnx2x_drain_tx_queues(struct bnx2x *bp);
1407void bnx2x_squeeze_objects(struct bnx2x *bp);
1408
1405#endif /* BNX2X_CMN_H */ 1409#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 4902d1eb3d1e..10b0748a2d72 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9718,6 +9718,31 @@ static struct bnx2x_prev_path_list *
9718 return NULL; 9718 return NULL;
9719} 9719}
9720 9720
9721static int bnx2x_prev_path_mark_eeh(struct bnx2x *bp)
9722{
9723 struct bnx2x_prev_path_list *tmp_list;
9724 int rc;
9725
9726 rc = down_interruptible(&bnx2x_prev_sem);
9727 if (rc) {
9728 BNX2X_ERR("Received %d when tried to take lock\n", rc);
9729 return rc;
9730 }
9731
9732 tmp_list = bnx2x_prev_path_get_entry(bp);
9733 if (tmp_list) {
9734 tmp_list->aer = 1;
9735 rc = 0;
9736 } else {
9737 BNX2X_ERR("path %d: Entry does not exist for eeh; Flow occurs before initial insmod is over ?\n",
9738 BP_PATH(bp));
9739 }
9740
9741 up(&bnx2x_prev_sem);
9742
9743 return rc;
9744}
9745
9721static bool bnx2x_prev_is_path_marked(struct bnx2x *bp) 9746static bool bnx2x_prev_is_path_marked(struct bnx2x *bp)
9722{ 9747{
9723 struct bnx2x_prev_path_list *tmp_list; 9748 struct bnx2x_prev_path_list *tmp_list;
@@ -9726,14 +9751,15 @@ static bool bnx2x_prev_is_path_marked(struct bnx2x *bp)
9726 if (down_trylock(&bnx2x_prev_sem)) 9751 if (down_trylock(&bnx2x_prev_sem))
9727 return false; 9752 return false;
9728 9753
9729 list_for_each_entry(tmp_list, &bnx2x_prev_list, list) { 9754 tmp_list = bnx2x_prev_path_get_entry(bp);
9730 if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot && 9755 if (tmp_list) {
9731 bp->pdev->bus->number == tmp_list->bus && 9756 if (tmp_list->aer) {
9732 BP_PATH(bp) == tmp_list->path) { 9757 DP(NETIF_MSG_HW, "Path %d was marked by AER\n",
9758 BP_PATH(bp));
9759 } else {
9733 rc = true; 9760 rc = true;
9734 BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n", 9761 BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n",
9735 BP_PATH(bp)); 9762 BP_PATH(bp));
9736 break;
9737 } 9763 }
9738 } 9764 }
9739 9765
@@ -9747,6 +9773,28 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
9747 struct bnx2x_prev_path_list *tmp_list; 9773 struct bnx2x_prev_path_list *tmp_list;
9748 int rc; 9774 int rc;
9749 9775
9776 rc = down_interruptible(&bnx2x_prev_sem);
9777 if (rc) {
9778 BNX2X_ERR("Received %d when tried to take lock\n", rc);
9779 return rc;
9780 }
9781
9782 /* Check whether the entry for this path already exists */
9783 tmp_list = bnx2x_prev_path_get_entry(bp);
9784 if (tmp_list) {
9785 if (!tmp_list->aer) {
9786 BNX2X_ERR("Re-Marking the path.\n");
9787 } else {
9788 DP(NETIF_MSG_HW, "Removing AER indication from path %d\n",
9789 BP_PATH(bp));
9790 tmp_list->aer = 0;
9791 }
9792 up(&bnx2x_prev_sem);
9793 return 0;
9794 }
9795 up(&bnx2x_prev_sem);
9796
9797 /* Create an entry for this path and add it */
9750 tmp_list = kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL); 9798 tmp_list = kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL);
9751 if (!tmp_list) { 9799 if (!tmp_list) {
9752 BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n"); 9800 BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n");
@@ -9756,6 +9804,7 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
9756 tmp_list->bus = bp->pdev->bus->number; 9804 tmp_list->bus = bp->pdev->bus->number;
9757 tmp_list->slot = PCI_SLOT(bp->pdev->devfn); 9805 tmp_list->slot = PCI_SLOT(bp->pdev->devfn);
9758 tmp_list->path = BP_PATH(bp); 9806 tmp_list->path = BP_PATH(bp);
9807 tmp_list->aer = 0;
9759 tmp_list->undi = after_undi ? (1 << BP_PORT(bp)) : 0; 9808 tmp_list->undi = after_undi ? (1 << BP_PORT(bp)) : 0;
9760 9809
9761 rc = down_interruptible(&bnx2x_prev_sem); 9810 rc = down_interruptible(&bnx2x_prev_sem);
@@ -9763,8 +9812,8 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
9763 BNX2X_ERR("Received %d when tried to take lock\n", rc); 9812 BNX2X_ERR("Received %d when tried to take lock\n", rc);
9764 kfree(tmp_list); 9813 kfree(tmp_list);
9765 } else { 9814 } else {
9766 BNX2X_DEV_INFO("Marked path [%d] - finished previous unload\n", 9815 DP(NETIF_MSG_HW, "Marked path [%d] - finished previous unload\n",
9767 BP_PATH(bp)); 9816 BP_PATH(bp));
9768 list_add(&tmp_list->list, &bnx2x_prev_list); 9817 list_add(&tmp_list->list, &bnx2x_prev_list);
9769 up(&bnx2x_prev_sem); 9818 up(&bnx2x_prev_sem);
9770 } 9819 }
@@ -10003,6 +10052,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
10003 } 10052 }
10004 10053
10005 do { 10054 do {
10055 int aer = 0;
10006 /* Lock MCP using an unload request */ 10056 /* Lock MCP using an unload request */
10007 fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0); 10057 fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
10008 if (!fw) { 10058 if (!fw) {
@@ -10011,7 +10061,18 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
10011 break; 10061 break;
10012 } 10062 }
10013 10063
10014 if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON) { 10064 rc = down_interruptible(&bnx2x_prev_sem);
10065 if (rc) {
10066 BNX2X_ERR("Cannot check for AER; Received %d when tried to take lock\n",
10067 rc);
10068 } else {
10069 /* If Path is marked by EEH, ignore unload status */
10070 aer = !!(bnx2x_prev_path_get_entry(bp) &&
10071 bnx2x_prev_path_get_entry(bp)->aer);
10072 }
10073 up(&bnx2x_prev_sem);
10074
10075 if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON || aer) {
10015 rc = bnx2x_prev_unload_common(bp); 10076 rc = bnx2x_prev_unload_common(bp);
10016 break; 10077 break;
10017 } 10078 }
@@ -12632,9 +12693,7 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
12632 12693
12633static int bnx2x_eeh_nic_unload(struct bnx2x *bp) 12694static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
12634{ 12695{
12635 int i; 12696 bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
12636
12637 bp->state = BNX2X_STATE_ERROR;
12638 12697
12639 bp->rx_mode = BNX2X_RX_MODE_NONE; 12698 bp->rx_mode = BNX2X_RX_MODE_NONE;
12640 12699
@@ -12643,29 +12702,21 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
12643 12702
12644 /* Stop Tx */ 12703 /* Stop Tx */
12645 bnx2x_tx_disable(bp); 12704 bnx2x_tx_disable(bp);
12646
12647 bnx2x_netif_stop(bp, 0);
12648 /* Delete all NAPI objects */ 12705 /* Delete all NAPI objects */
12649 bnx2x_del_all_napi(bp); 12706 bnx2x_del_all_napi(bp);
12650 if (CNIC_LOADED(bp)) 12707 if (CNIC_LOADED(bp))
12651 bnx2x_del_all_napi_cnic(bp); 12708 bnx2x_del_all_napi_cnic(bp);
12709 netdev_reset_tc(bp->dev);
12652 12710
12653 del_timer_sync(&bp->timer); 12711 del_timer_sync(&bp->timer);
12712 cancel_delayed_work(&bp->sp_task);
12713 cancel_delayed_work(&bp->period_task);
12654 12714
12655 bnx2x_stats_handle(bp, STATS_EVENT_STOP); 12715 spin_lock_bh(&bp->stats_lock);
12656 12716 bp->stats_state = STATS_STATE_DISABLED;
12657 /* Release IRQs */ 12717 spin_unlock_bh(&bp->stats_lock);
12658 bnx2x_free_irq(bp);
12659
12660 /* Free SKBs, SGEs, TPA pool and driver internals */
12661 bnx2x_free_skbs(bp);
12662
12663 for_each_rx_queue(bp, i)
12664 bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
12665
12666 bnx2x_free_mem(bp);
12667 12718
12668 bp->state = BNX2X_STATE_CLOSED; 12719 bnx2x_save_statistics(bp);
12669 12720
12670 netif_carrier_off(bp->dev); 12721 netif_carrier_off(bp->dev);
12671 12722
@@ -12701,6 +12752,8 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
12701 12752
12702 rtnl_lock(); 12753 rtnl_lock();
12703 12754
12755 BNX2X_ERR("IO error detected\n");
12756
12704 netif_device_detach(dev); 12757 netif_device_detach(dev);
12705 12758
12706 if (state == pci_channel_io_perm_failure) { 12759 if (state == pci_channel_io_perm_failure) {
@@ -12711,6 +12764,8 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
12711 if (netif_running(dev)) 12764 if (netif_running(dev))
12712 bnx2x_eeh_nic_unload(bp); 12765 bnx2x_eeh_nic_unload(bp);
12713 12766
12767 bnx2x_prev_path_mark_eeh(bp);
12768
12714 pci_disable_device(pdev); 12769 pci_disable_device(pdev);
12715 12770
12716 rtnl_unlock(); 12771 rtnl_unlock();
@@ -12729,9 +12784,10 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
12729{ 12784{
12730 struct net_device *dev = pci_get_drvdata(pdev); 12785 struct net_device *dev = pci_get_drvdata(pdev);
12731 struct bnx2x *bp = netdev_priv(dev); 12786 struct bnx2x *bp = netdev_priv(dev);
12787 int i;
12732 12788
12733 rtnl_lock(); 12789 rtnl_lock();
12734 12790 BNX2X_ERR("IO slot reset initializing...\n");
12735 if (pci_enable_device(pdev)) { 12791 if (pci_enable_device(pdev)) {
12736 dev_err(&pdev->dev, 12792 dev_err(&pdev->dev,
12737 "Cannot re-enable PCI device after reset\n"); 12793 "Cannot re-enable PCI device after reset\n");
@@ -12745,6 +12801,42 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
12745 if (netif_running(dev)) 12801 if (netif_running(dev))
12746 bnx2x_set_power_state(bp, PCI_D0); 12802 bnx2x_set_power_state(bp, PCI_D0);
12747 12803
12804 if (netif_running(dev)) {
12805 BNX2X_ERR("IO slot reset --> driver unload\n");
12806 if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
12807 u32 v;
12808
12809 v = SHMEM2_RD(bp,
12810 drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
12811 SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
12812 v & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
12813 }
12814 bnx2x_drain_tx_queues(bp);
12815 bnx2x_send_unload_req(bp, UNLOAD_RECOVERY);
12816 bnx2x_netif_stop(bp, 1);
12817 bnx2x_free_irq(bp);
12818
12819 /* Report UNLOAD_DONE to MCP */
12820 bnx2x_send_unload_done(bp, true);
12821
12822 bp->sp_state = 0;
12823 bp->port.pmf = 0;
12824
12825 bnx2x_prev_unload(bp);
12826
12827 /* We should have resetted the engine, so It's fair to
12828 * assume the FW will no longer write to the bnx2x driver.
12829 */
12830 bnx2x_squeeze_objects(bp);
12831 bnx2x_free_skbs(bp);
12832 for_each_rx_queue(bp, i)
12833 bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
12834 bnx2x_free_fp_mem(bp);
12835 bnx2x_free_mem(bp);
12836
12837 bp->state = BNX2X_STATE_CLOSED;
12838 }
12839
12748 rtnl_unlock(); 12840 rtnl_unlock();
12749 12841
12750 return PCI_ERS_RESULT_RECOVERED; 12842 return PCI_ERS_RESULT_RECOVERED;
@@ -12771,6 +12863,9 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
12771 12863
12772 bnx2x_eeh_recover(bp); 12864 bnx2x_eeh_recover(bp);
12773 12865
12866 bp->fw_seq = SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
12867 DRV_MSG_SEQ_NUMBER_MASK;
12868
12774 if (netif_running(dev)) 12869 if (netif_running(dev))
12775 bnx2x_nic_load(bp, LOAD_NORMAL); 12870 bnx2x_nic_load(bp, LOAD_NORMAL);
12776 12871