diff options
author | Dimitris Michailidis <dm@chelsio.com> | 2010-06-18 06:05:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-19 01:08:36 -0400 |
commit | 204dc3c0b1bea10a7d811970fd41ceabaef31267 (patch) | |
tree | e2d3879455ff3c6226ffea439275a21f4edefb39 /drivers/net/cxgb4 | |
parent | 02b5fb8e14923ff9111de1a00004ccd593adaedb (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.h | 1 | ||||
-rw-r--r-- | drivers/net/cxgb4/cxgb4_main.c | 108 | ||||
-rw-r--r-- | drivers/net/cxgb4/l2t.c | 7 | ||||
-rw-r--r-- | drivers/net/cxgb4/t4_hw.c | 11 |
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); | |||
650 | void t4_intr_clear(struct adapter *adapter); | 650 | void t4_intr_clear(struct adapter *adapter); |
651 | int t4_slow_intr_handler(struct adapter *adapter); | 651 | int t4_slow_intr_handler(struct adapter *adapter); |
652 | 652 | ||
653 | int t4_wait_dev_ready(struct adapter *adap); | ||
653 | int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, | 654 | int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, |
654 | struct link_config *lc); | 655 | struct link_config *lc); |
655 | int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); | 656 | int 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 | |||
2913 | static 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); | ||
2935 | out: return state == pci_channel_io_perm_failure ? | ||
2936 | PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; | ||
2937 | } | ||
2938 | |||
2939 | static 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 | |||
2986 | static 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 | |||
3007 | static struct pci_error_handlers cxgb4_eeh = { | ||
3008 | .error_detected = eeh_err_detected, | ||
3009 | .slot_reset = eeh_slot_reset, | ||
3010 | .resume = eeh_resume, | ||
3011 | }; | ||
3012 | |||
2910 | static inline bool is_10g_port(const struct link_config *lc) | 3013 | static 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 | ||
3401 | static int __init cxgb4_init_module(void) | 3507 | static 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 | ||
3048 | static int __devinit wait_dev_ready(struct adapter *adap) | 3055 | int 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 | ||