diff options
author | Pratik Pujar <pratik.pujar@qlogic.com> | 2013-08-30 13:51:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-31 22:34:44 -0400 |
commit | 9ce226fa2352eac89ce79abdea8e465c680d1db0 (patch) | |
tree | 42839e4ed96ffafb90acd9c720c9b222e155837e | |
parent | 4460f2e83c61e21c2e78a28a327b716252b13069 (diff) |
qlcnic: Add AER support for 83xx adapter
Signed-off-by: Pratik Pujar <pratik.pujar@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 59 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 56 |
3 files changed, 121 insertions, 1 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 36223a9df43d..3ef5437b7b59 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
12 | #include <linux/ethtool.h> | 12 | #include <linux/ethtool.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/aer.h> | ||
14 | 15 | ||
15 | #define QLCNIC_MAX_TX_QUEUES 1 | 16 | #define QLCNIC_MAX_TX_QUEUES 1 |
16 | #define RSS_HASHTYPE_IP_TCP 0x3 | 17 | #define RSS_HASHTYPE_IP_TCP 0x3 |
@@ -177,6 +178,10 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { | |||
177 | .get_board_info = qlcnic_83xx_get_port_info, | 178 | .get_board_info = qlcnic_83xx_get_port_info, |
178 | .set_mac_filter_count = qlcnic_83xx_set_mac_filter_count, | 179 | .set_mac_filter_count = qlcnic_83xx_set_mac_filter_count, |
179 | .free_mac_list = qlcnic_82xx_free_mac_list, | 180 | .free_mac_list = qlcnic_82xx_free_mac_list, |
181 | .io_error_detected = qlcnic_83xx_io_error_detected, | ||
182 | .io_slot_reset = qlcnic_83xx_io_slot_reset, | ||
183 | .io_resume = qlcnic_83xx_io_resume, | ||
184 | |||
180 | }; | 185 | }; |
181 | 186 | ||
182 | static struct qlcnic_nic_template qlcnic_83xx_ops = { | 187 | static struct qlcnic_nic_template qlcnic_83xx_ops = { |
@@ -3819,3 +3824,57 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter) | |||
3819 | set_bit(QLC_83XX_MBX_READY, &mbx->status); | 3824 | set_bit(QLC_83XX_MBX_READY, &mbx->status); |
3820 | return 0; | 3825 | return 0; |
3821 | } | 3826 | } |
3827 | |||
3828 | pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, | ||
3829 | pci_channel_state_t state) | ||
3830 | { | ||
3831 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3832 | |||
3833 | if (state == pci_channel_io_perm_failure) | ||
3834 | return PCI_ERS_RESULT_DISCONNECT; | ||
3835 | |||
3836 | if (state == pci_channel_io_normal) | ||
3837 | return PCI_ERS_RESULT_RECOVERED; | ||
3838 | |||
3839 | set_bit(__QLCNIC_AER, &adapter->state); | ||
3840 | set_bit(__QLCNIC_RESETTING, &adapter->state); | ||
3841 | |||
3842 | qlcnic_83xx_aer_stop_poll_work(adapter); | ||
3843 | |||
3844 | pci_save_state(pdev); | ||
3845 | pci_disable_device(pdev); | ||
3846 | |||
3847 | return PCI_ERS_RESULT_NEED_RESET; | ||
3848 | } | ||
3849 | |||
3850 | pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) | ||
3851 | { | ||
3852 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3853 | int err = 0; | ||
3854 | |||
3855 | pdev->error_state = pci_channel_io_normal; | ||
3856 | err = pci_enable_device(pdev); | ||
3857 | if (err) | ||
3858 | goto disconnect; | ||
3859 | |||
3860 | pci_set_power_state(pdev, PCI_D0); | ||
3861 | pci_set_master(pdev); | ||
3862 | pci_restore_state(pdev); | ||
3863 | |||
3864 | err = qlcnic_83xx_aer_reset(adapter); | ||
3865 | if (err == 0) | ||
3866 | return PCI_ERS_RESULT_RECOVERED; | ||
3867 | disconnect: | ||
3868 | clear_bit(__QLCNIC_AER, &adapter->state); | ||
3869 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
3870 | return PCI_ERS_RESULT_DISCONNECT; | ||
3871 | } | ||
3872 | |||
3873 | void qlcnic_83xx_io_resume(struct pci_dev *pdev) | ||
3874 | { | ||
3875 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); | ||
3876 | |||
3877 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
3878 | if (test_and_clear_bit(__QLCNIC_AER, &adapter->state)) | ||
3879 | qlcnic_83xx_aer_start_poll_work(adapter); | ||
3880 | } | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 053a3a1770bb..6752d5890b24 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -657,4 +657,11 @@ int qlcnic_83xx_idc_init(struct qlcnic_adapter *); | |||
657 | int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *); | 657 | int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *); |
658 | int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *); | 658 | int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *); |
659 | int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *); | 659 | int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *); |
660 | void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *); | ||
661 | int qlcnic_83xx_aer_reset(struct qlcnic_adapter *); | ||
662 | void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *); | ||
663 | pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, | ||
664 | pci_channel_state_t); | ||
665 | pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); | ||
666 | void qlcnic_83xx_io_resume(struct pci_dev *); | ||
660 | #endif | 667 | #endif |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 6fac3930cc56..b7eddfe74d8c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | |||
@@ -797,7 +797,6 @@ static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter) | |||
797 | ret = qlcnic_83xx_idc_restart_hw(adapter, 1); | 797 | ret = qlcnic_83xx_idc_restart_hw(adapter, 1); |
798 | } else { | 798 | } else { |
799 | ret = qlcnic_83xx_idc_check_timeout(adapter, timeout); | 799 | ret = qlcnic_83xx_idc_check_timeout(adapter, timeout); |
800 | return ret; | ||
801 | } | 800 | } |
802 | 801 | ||
803 | return ret; | 802 | return ret; |
@@ -2249,3 +2248,58 @@ detach_mbx: | |||
2249 | exit: | 2248 | exit: |
2250 | return err; | 2249 | return err; |
2251 | } | 2250 | } |
2251 | |||
2252 | void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter) | ||
2253 | { | ||
2254 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
2255 | struct qlc_83xx_idc *idc = &ahw->idc; | ||
2256 | |||
2257 | clear_bit(QLC_83XX_MBX_READY, &idc->status); | ||
2258 | cancel_delayed_work_sync(&adapter->fw_work); | ||
2259 | |||
2260 | if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) | ||
2261 | qlcnic_83xx_disable_vnic_mode(adapter, 1); | ||
2262 | |||
2263 | qlcnic_83xx_idc_detach_driver(adapter); | ||
2264 | qlcnic_83xx_register_nic_idc_func(adapter, 0); | ||
2265 | |||
2266 | cancel_delayed_work_sync(&adapter->idc_aen_work); | ||
2267 | } | ||
2268 | |||
2269 | int qlcnic_83xx_aer_reset(struct qlcnic_adapter *adapter) | ||
2270 | { | ||
2271 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
2272 | struct qlc_83xx_idc *idc = &ahw->idc; | ||
2273 | int ret = 0; | ||
2274 | u32 owner; | ||
2275 | |||
2276 | /* Mark the previous IDC state as NEED_RESET so | ||
2277 | * that state_entry() will perform the reattachment | ||
2278 | * and bringup the device | ||
2279 | */ | ||
2280 | idc->prev_state = QLC_83XX_IDC_DEV_NEED_RESET; | ||
2281 | owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); | ||
2282 | if (ahw->pci_func == owner) { | ||
2283 | ret = qlcnic_83xx_restart_hw(adapter); | ||
2284 | if (ret < 0) | ||
2285 | return ret; | ||
2286 | qlcnic_83xx_idc_clear_registers(adapter, 0); | ||
2287 | } | ||
2288 | |||
2289 | ret = idc->state_entry(adapter); | ||
2290 | return ret; | ||
2291 | } | ||
2292 | |||
2293 | void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *adapter) | ||
2294 | { | ||
2295 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
2296 | struct qlc_83xx_idc *idc = &ahw->idc; | ||
2297 | u32 owner; | ||
2298 | |||
2299 | idc->prev_state = QLC_83XX_IDC_DEV_READY; | ||
2300 | owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); | ||
2301 | if (ahw->pci_func == owner) | ||
2302 | qlcnic_83xx_idc_enter_ready_state(adapter, 0); | ||
2303 | |||
2304 | qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state, 0); | ||
2305 | } | ||