aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratik Pujar <pratik.pujar@qlogic.com>2013-08-30 13:51:21 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-31 22:34:44 -0400
commit9ce226fa2352eac89ce79abdea8e465c680d1db0 (patch)
tree42839e4ed96ffafb90acd9c720c9b222e155837e
parent4460f2e83c61e21c2e78a28a327b716252b13069 (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.c59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h7
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c56
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
182static struct qlcnic_nic_template qlcnic_83xx_ops = { 187static 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
3828pci_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
3850pci_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;
3867disconnect:
3868 clear_bit(__QLCNIC_AER, &adapter->state);
3869 clear_bit(__QLCNIC_RESETTING, &adapter->state);
3870 return PCI_ERS_RESULT_DISCONNECT;
3871}
3872
3873void 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 *);
657int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *); 657int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *);
658int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *); 658int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *);
659int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *); 659int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);
660void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *);
661int qlcnic_83xx_aer_reset(struct qlcnic_adapter *);
662void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *);
663pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *,
664 pci_channel_state_t);
665pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *);
666void 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:
2249exit: 2248exit:
2250 return err; 2249 return err;
2251} 2250}
2251
2252void 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
2269int 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
2293void 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}