aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb4
diff options
context:
space:
mode:
authorDimitris Michailidis <dm@chelsio.com>2010-06-18 06:05:29 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-19 01:08:36 -0400
commit204dc3c0b1bea10a7d811970fd41ceabaef31267 (patch)
treee2d3879455ff3c6226ffea439275a21f4edefb39 /drivers/net/cxgb4
parent02b5fb8e14923ff9111de1a00004ccd593adaedb (diff)
cxgb4: implement EEH
Implement the pci_error_handlers methods for EEH. Signed-off-by: Dimitris Michailidis <dm@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cxgb4')
-rw-r--r--drivers/net/cxgb4/cxgb4.h1
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c108
-rw-r--r--drivers/net/cxgb4/l2t.c7
-rw-r--r--drivers/net/cxgb4/t4_hw.c11
4 files changed, 124 insertions, 3 deletions
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index bfa136622f10..5e37c1e67fe9 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -650,6 +650,7 @@ void t4_intr_disable(struct adapter *adapter);
650void t4_intr_clear(struct adapter *adapter); 650void t4_intr_clear(struct adapter *adapter);
651int t4_slow_intr_handler(struct adapter *adapter); 651int t4_slow_intr_handler(struct adapter *adapter);
652 652
653int t4_wait_dev_ready(struct adapter *adap);
653int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, 654int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
654 struct link_config *lc); 655 struct link_config *lc);
655int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); 656int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 60f6ea05167a..baf4f0a31362 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -2483,6 +2483,7 @@ static void cxgb_down(struct adapter *adapter)
2483 t4_intr_disable(adapter); 2483 t4_intr_disable(adapter);
2484 cancel_work_sync(&adapter->tid_release_task); 2484 cancel_work_sync(&adapter->tid_release_task);
2485 adapter->tid_release_task_busy = false; 2485 adapter->tid_release_task_busy = false;
2486 adapter->tid_release_head = NULL;
2486 2487
2487 if (adapter->flags & USING_MSIX) { 2488 if (adapter->flags & USING_MSIX) {
2488 free_msix_queue_irqs(adapter); 2489 free_msix_queue_irqs(adapter);
@@ -2907,6 +2908,108 @@ bye: if (ret != -ETIMEDOUT && ret != -EIO)
2907 return ret; 2908 return ret;
2908} 2909}
2909 2910
2911/* EEH callbacks */
2912
2913static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
2914 pci_channel_state_t state)
2915{
2916 int i;
2917 struct adapter *adap = pci_get_drvdata(pdev);
2918
2919 if (!adap)
2920 goto out;
2921
2922 rtnl_lock();
2923 adap->flags &= ~FW_OK;
2924 notify_ulds(adap, CXGB4_STATE_START_RECOVERY);
2925 for_each_port(adap, i) {
2926 struct net_device *dev = adap->port[i];
2927
2928 netif_device_detach(dev);
2929 netif_carrier_off(dev);
2930 }
2931 if (adap->flags & FULL_INIT_DONE)
2932 cxgb_down(adap);
2933 rtnl_unlock();
2934 pci_disable_device(pdev);
2935out: return state == pci_channel_io_perm_failure ?
2936 PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
2937}
2938
2939static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
2940{
2941 int i, ret;
2942 struct fw_caps_config_cmd c;
2943 struct adapter *adap = pci_get_drvdata(pdev);
2944
2945 if (!adap) {
2946 pci_restore_state(pdev);
2947 pci_save_state(pdev);
2948 return PCI_ERS_RESULT_RECOVERED;
2949 }
2950
2951 if (pci_enable_device(pdev)) {
2952 dev_err(&pdev->dev, "cannot reenable PCI device after reset\n");
2953 return PCI_ERS_RESULT_DISCONNECT;
2954 }
2955
2956 pci_set_master(pdev);
2957 pci_restore_state(pdev);
2958 pci_save_state(pdev);
2959 pci_cleanup_aer_uncorrect_error_status(pdev);
2960
2961 if (t4_wait_dev_ready(adap) < 0)
2962 return PCI_ERS_RESULT_DISCONNECT;
2963 if (t4_fw_hello(adap, 0, 0, MASTER_MUST, NULL))
2964 return PCI_ERS_RESULT_DISCONNECT;
2965 adap->flags |= FW_OK;
2966 if (adap_init1(adap, &c))
2967 return PCI_ERS_RESULT_DISCONNECT;
2968
2969 for_each_port(adap, i) {
2970 struct port_info *p = adap2pinfo(adap, i);
2971
2972 ret = t4_alloc_vi(adap, 0, p->tx_chan, 0, 0, 1, NULL, NULL);
2973 if (ret < 0)
2974 return PCI_ERS_RESULT_DISCONNECT;
2975 p->viid = ret;
2976 p->xact_addr_filt = -1;
2977 }
2978
2979 t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
2980 adap->params.b_wnd);
2981 if (cxgb_up(adap))
2982 return PCI_ERS_RESULT_DISCONNECT;
2983 return PCI_ERS_RESULT_RECOVERED;
2984}
2985
2986static void eeh_resume(struct pci_dev *pdev)
2987{
2988 int i;
2989 struct adapter *adap = pci_get_drvdata(pdev);
2990
2991 if (!adap)
2992 return;
2993
2994 rtnl_lock();
2995 for_each_port(adap, i) {
2996 struct net_device *dev = adap->port[i];
2997
2998 if (netif_running(dev)) {
2999 link_start(dev);
3000 cxgb_set_rxmode(dev);
3001 }
3002 netif_device_attach(dev);
3003 }
3004 rtnl_unlock();
3005}
3006
3007static struct pci_error_handlers cxgb4_eeh = {
3008 .error_detected = eeh_err_detected,
3009 .slot_reset = eeh_slot_reset,
3010 .resume = eeh_resume,
3011};
3012
2910static inline bool is_10g_port(const struct link_config *lc) 3013static inline bool is_10g_port(const struct link_config *lc)
2911{ 3014{
2912 return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; 3015 return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
@@ -3154,8 +3257,10 @@ static int __devinit init_one(struct pci_dev *pdev,
3154 3257
3155 /* We control everything through PF 0 */ 3258 /* We control everything through PF 0 */
3156 func = PCI_FUNC(pdev->devfn); 3259 func = PCI_FUNC(pdev->devfn);
3157 if (func > 0) 3260 if (func > 0) {
3261 pci_save_state(pdev); /* to restore SR-IOV later */
3158 goto sriov; 3262 goto sriov;
3263 }
3159 3264
3160 err = pci_enable_device(pdev); 3265 err = pci_enable_device(pdev);
3161 if (err) { 3266 if (err) {
@@ -3396,6 +3501,7 @@ static struct pci_driver cxgb4_driver = {
3396 .id_table = cxgb4_pci_tbl, 3501 .id_table = cxgb4_pci_tbl,
3397 .probe = init_one, 3502 .probe = init_one,
3398 .remove = __devexit_p(remove_one), 3503 .remove = __devexit_p(remove_one),
3504 .err_handler = &cxgb4_eeh,
3399}; 3505};
3400 3506
3401static int __init cxgb4_init_module(void) 3507static int __init cxgb4_init_module(void)
diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c
index 9f96724a133a..5b990d24cca9 100644
--- a/drivers/net/cxgb4/l2t.c
+++ b/drivers/net/cxgb4/l2t.c
@@ -310,6 +310,13 @@ static void t4_l2e_free(struct l2t_entry *e)
310 neigh_release(e->neigh); 310 neigh_release(e->neigh);
311 e->neigh = NULL; 311 e->neigh = NULL;
312 } 312 }
313 while (e->arpq_head) {
314 struct sk_buff *skb = e->arpq_head;
315
316 e->arpq_head = skb->next;
317 kfree(skb);
318 }
319 e->arpq_tail = NULL;
313 } 320 }
314 spin_unlock_bh(&e->lock); 321 spin_unlock_bh(&e->lock);
315 322
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index 5c81c558ce62..0c8a84a258f3 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -221,6 +221,13 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
221 if ((size & 15) || size > MBOX_LEN) 221 if ((size & 15) || size > MBOX_LEN)
222 return -EINVAL; 222 return -EINVAL;
223 223
224 /*
225 * If the device is off-line, as in EEH, commands will time out.
226 * Fail them early so we don't waste time waiting.
227 */
228 if (adap->pdev->error_state != pci_channel_io_normal)
229 return -EIO;
230
224 v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); 231 v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
225 for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) 232 for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
226 v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); 233 v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
@@ -3045,7 +3052,7 @@ static void __devinit init_link_config(struct link_config *lc,
3045 } 3052 }
3046} 3053}
3047 3054
3048static int __devinit wait_dev_ready(struct adapter *adap) 3055int t4_wait_dev_ready(struct adapter *adap)
3049{ 3056{
3050 if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff) 3057 if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff)
3051 return 0; 3058 return 0;
@@ -3093,7 +3100,7 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
3093{ 3100{
3094 int ret; 3101 int ret;
3095 3102
3096 ret = wait_dev_ready(adapter); 3103 ret = t4_wait_dev_ready(adapter);
3097 if (ret < 0) 3104 if (ret < 0)
3098 return ret; 3105 return ret;
3099 3106