diff options
author | xiong <xiong@qca.qualcomm.com> | 2013-01-19 13:15:01 +0800 |
---|---|---|
committer | Luis R. Rodriguez <mcgrof@do-not-panic.com> | 2013-01-24 07:56:06 -0800 |
commit | 4a06ca7ef3adaa2841e2d4ca2e8e42111aff2652 (patch) | |
tree | 0fd067f5c70f77e7fa2b72111b15281fb0083bf1 | |
parent | 1d7338dafc4b77b3d6cd9c561cf0b89c9d394398 (diff) | |
download | alx-4a06ca7ef3adaa2841e2d4ca2e8e42111aff2652.tar.gz |
alx: fix tx-timeout after sleep/resume
tx-timeout after sleep/resume is caused by wrong interrupt mode used
after resume.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
-rw-r--r-- | src/alx_hw.h | 13 | ||||
-rw-r--r-- | src/alx_main.c | 237 |
2 files changed, 136 insertions, 114 deletions
diff --git a/src/alx_hw.h b/src/alx_hw.h index 8790869..2d16aff 100644 --- a/src/alx_hw.h +++ b/src/alx_hw.h @@ -382,6 +382,19 @@ struct alx_hw_stats { (_speed) == SPEED_10 + HALF_DUPLEX ? ADVERTISED_10baseT_Half : \ 0) +#define speed_desc(_s) (\ + (_s) == SPEED_1000 + FULL_DUPLEX ? \ + "1 Gbps Full" : \ + (_s) == SPEED_100 + FULL_DUPLEX ? \ + "100 Mbps Full" : \ + (_s) == SPEED_100 + HALF_DUPLEX ? \ + "100 Mbps Half" : \ + (_s) == SPEED_10 + FULL_DUPLEX ? \ + "10 Mbps Full" : \ + (_s) == SPEED_10 + HALF_DUPLEX ? \ + "10 Mbps Half" : \ + "Unknown speed") + /* for FlowControl */ #define ALX_FC_RX 0x01 #define ALX_FC_TX 0x02 diff --git a/src/alx_main.c b/src/alx_main.c index 60f52e6..322aea3 100644 --- a/src/alx_main.c +++ b/src/alx_main.c @@ -34,7 +34,7 @@ #define DRV_MAJ 1 #define DRV_MIN 2 #define DRV_PATCH 1 -#define DRV_MODULE_VER \ +#define DRV_MODULE_VER \ __stringify(DRV_MAJ) "." __stringify(DRV_MIN) "." \ __stringify(DRV_PATCH) @@ -935,8 +935,6 @@ static int alx_request_irq(struct alx_adapter *adpt) adpt->nr_vec = 1; adpt->nr_hwrxq = 1; alx_configure_rss(hw, false); - netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); - netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); if (!pci_enable_msi(pdev)) ALX_FLAG_SET(adpt, USING_MSI); @@ -968,12 +966,14 @@ static int alx_request_irq(struct alx_adapter *adpt) out: if (likely(!err)) { alx_config_vector_mapping(adpt); - netif_info(adpt, intr, adpt->netdev, + + netif_info(adpt, drv, adpt->netdev, "nr_rxq=%d, nr_txq=%d, nr_napi=%d, nr_vec=%d\n", adpt->nr_rxq, adpt->nr_txq, adpt->nr_napi, adpt->nr_vec); - netif_info(adpt, intr, adpt->netdev, - "Interrupt Mode: %s\n", + netif_info(adpt, drv, adpt->netdev, + "flags=%lX, Interrupt Mode: %s\n", + adpt->flags, ALX_FLAG(adpt, USING_MSIX) ? "MSIX" : ALX_FLAG(adpt, USING_MSI) ? "MSI" : "INTx"); } else @@ -1217,10 +1217,12 @@ static void alx_netif_stop(struct alx_adapter *adpt) int i; adpt->netdev->trans_start = jiffies; - netif_carrier_off(adpt->netdev); - netif_tx_disable(adpt->netdev); - for (i = 0; i < adpt->nr_napi; i++) - napi_disable(&adpt->qnapi[i]->napi); + if (netif_carrier_ok(adpt->netdev)) { + netif_carrier_off(adpt->netdev); + netif_tx_disable(adpt->netdev); + for (i = 0; i < adpt->nr_napi; i++) + napi_disable(&adpt->qnapi[i]->napi); + } } static void alx_netif_start(struct alx_adapter *adpt) @@ -1233,11 +1235,84 @@ static void alx_netif_start(struct alx_adapter *adpt) netif_carrier_on(adpt->netdev); } -static int __alx_open(struct alx_adapter *adpt) +static bool alx_enable_msix(struct alx_adapter *adpt) +{ + int nr_txq, nr_rxq, vec_req; + int i, err; + + nr_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); + nr_rxq = min_t(int, num_online_cpus(), ALX_MAX_RX_QUEUES); + nr_rxq = rounddown_pow_of_two(nr_rxq); + /* one more vector for PHY link change & timer & other events */ + vec_req = max_t(int, nr_txq, nr_rxq) + 1; + + if (vec_req <= 2) { + netif_info(adpt, intr, adpt->netdev, + "cpu core num is less, MSI-X isn't necessary\n"); + return false; + } + + adpt->msix_ent = kcalloc(vec_req, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!adpt->msix_ent) { + netif_warn(adpt, intr, adpt->netdev, + "can't alloc msix entries\n"); + return false; + } + for (i = 0; i < vec_req; i++) + adpt->msix_ent[i].entry = i; + + err = pci_enable_msix(adpt->pdev, adpt->msix_ent, vec_req); + if (err) { + kfree(adpt->msix_ent); + adpt->msix_ent = NULL; + netif_warn(adpt, intr, adpt->netdev, + "can't enable MSI-X interrupt\n"); + return false; + } + + adpt->nr_txq = nr_txq; + adpt->nr_rxq = nr_rxq; + adpt->nr_vec = vec_req; + adpt->nr_napi = vec_req - 1; + adpt->nr_hwrxq = ALX_CAP(&adpt->hw, MRQ) ? adpt->nr_rxq : 1; + + return true; +} + +static void alx_init_intr(struct alx_adapter *adpt) +{ + struct alx_hw *hw = &adpt->hw; + + if ((ALX_CAP(hw, MTQ) || ALX_CAP(hw, RSS)) && ALX_CAP(hw, MSIX)) { + if (alx_enable_msix(adpt)) + ALX_FLAG_SET(adpt, USING_MSIX); + } + if (!ALX_FLAG(adpt, USING_MSIX)) { + adpt->nr_txq = ALX_CAP(hw, MTQ) ? ALX_MAX_TX_QUEUES : 1; + adpt->nr_rxq = 1; + adpt->nr_napi = 1; + adpt->nr_vec = 1; + adpt->nr_hwrxq = 1; + + if (!pci_enable_msi(adpt->pdev)) + ALX_FLAG_SET(adpt, USING_MSI); + } +} + +static int __alx_open(struct alx_adapter *adpt, bool resume) { int err; - netif_carrier_off(adpt->netdev); + /* decide interrupt mode, some resources allocation depend on it */ + alx_init_intr(adpt); + + /* init rss indirection table */ + alx_init_def_rss_idt(adpt); + + if (!resume) + netif_carrier_off(adpt->netdev); /* allocate all memory resources */ err = alx_setup_all_ring_resources(adpt); @@ -1251,6 +1326,14 @@ static int __alx_open(struct alx_adapter *adpt) if (err) goto err_out; + /* netif_set_real_num_tx/rx_queues need rtnl_lock held */ + if (resume) + rtnl_lock(); + netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); + netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); + if (resume) + rtnl_unlock(); + ALX_FLAG_CLEAR(adpt, HALT); /* clear old interrupts */ @@ -1258,7 +1341,8 @@ static int __alx_open(struct alx_adapter *adpt) alx_irq_enable(adpt); - netif_tx_start_all_queues(adpt->netdev); + if (!resume) + netif_tx_start_all_queues(adpt->netdev); ALX_FLAG_SET(adpt, TASK_CHK_LINK); alx_schedule_work(adpt); @@ -1279,7 +1363,11 @@ static void alx_halt(struct alx_adapter *adpt) alx_cancel_work(adpt); alx_netif_stop(adpt); + hw->link_up = false; + hw->link_speed = SPEED_0; + alx_reset_mac(hw); + /* disable l0s/l1 */ alx_enable_aspm(hw, false, false); alx_irq_disable(adpt); @@ -1311,76 +1399,6 @@ static void __alx_stop(struct alx_adapter *adpt) alx_free_all_ring_resources(adpt); } -static bool alx_enable_msix(struct alx_adapter *adpt) -{ - int nr_txq, nr_rxq, vec_req; - int i, err; - - nr_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); - nr_rxq = min_t(int, num_online_cpus(), ALX_MAX_RX_QUEUES); - nr_rxq = rounddown_pow_of_two(nr_rxq); - /* one more vector for PHY link change & timer & other events */ - vec_req = max_t(int, nr_txq, nr_rxq) + 1; - - if (vec_req <= 2) { - netif_info(adpt, intr, adpt->netdev, - "cpu core num is less, MSI-X isn't necessary\n"); - return false; - } - - adpt->msix_ent = kcalloc(vec_req, - sizeof(struct msix_entry), - GFP_KERNEL); - if (!adpt->msix_ent) { - netif_warn(adpt, intr, adpt->netdev, - "can't alloc msix entries\n"); - return false; - } - for (i = 0; i < vec_req; i++) - adpt->msix_ent[i].entry = i; - - err = pci_enable_msix(adpt->pdev, adpt->msix_ent, vec_req); - if (err) { - kfree(adpt->msix_ent); - adpt->msix_ent = NULL; - netif_warn(adpt, intr, adpt->netdev, - "can't enable MSI-X interrupt\n"); - return false; - } - - adpt->nr_txq = nr_txq; - adpt->nr_rxq = nr_rxq; - adpt->nr_vec = vec_req; - adpt->nr_napi = vec_req - 1; - adpt->nr_hwrxq = ALX_CAP(&adpt->hw, MRQ) ? adpt->nr_rxq : 1; - - return true; -} - -static void alx_init_intr(struct alx_adapter *adpt) -{ - struct alx_hw *hw = &adpt->hw; - - if ((ALX_CAP(hw, MTQ) || ALX_CAP(hw, RSS)) && ALX_CAP(hw, MSIX)) { - if (alx_enable_msix(adpt)) - ALX_FLAG_SET(adpt, USING_MSIX); - } - if (!ALX_FLAG(adpt, USING_MSIX)) { - adpt->nr_txq = ALX_CAP(hw, MTQ) ? ALX_MAX_TX_QUEUES : 1; - adpt->nr_rxq = 1; - adpt->nr_napi = 1; - adpt->nr_vec = 1; - adpt->nr_hwrxq = 1; - - if (!pci_enable_msi(adpt->pdev)) - ALX_FLAG_SET(adpt, USING_MSI); - } - - netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); - netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); - -} - static void alx_init_ring_ptrs(struct alx_adapter *adpt) { struct alx_hw *hw = &adpt->hw; @@ -1431,22 +1449,9 @@ static void alx_init_ring_ptrs(struct alx_adapter *adpt) static void alx_show_speed(struct alx_adapter *adpt, u16 speed) { - char *desc; - - desc = speed == SPEED_1000 + FULL_DUPLEX ? - "1 Gbps Duplex Full" : - speed == SPEED_100 + FULL_DUPLEX ? - "100 Mbps Duplex Full" : - speed == SPEED_100 + HALF_DUPLEX ? - "100 Mbps Duplex Half" : - speed == SPEED_10 + FULL_DUPLEX ? - "10 Mbps Duplex Full" : - speed == SPEED_10 + HALF_DUPLEX ? - "10 Mbps Duplex Half" : - "Unknown speed"; netif_info(adpt, link, adpt->netdev, "NIC Link Up: %s\n", - desc); + speed_desc(speed)); } static int alx_reinit_rings(struct alx_adapter *adpt) @@ -1569,13 +1574,7 @@ static int alx_open(struct net_device *netdev) if (ALX_FLAG(adpt, TESTING)) return -EBUSY; - /* decide interrupt mode, some resources allocation depend on it */ - alx_init_intr(adpt); - - /* init rss indirection table */ - alx_init_def_rss_idt(adpt); - - err = __alx_open(adpt); + err = __alx_open(adpt, false); return err; } @@ -1587,8 +1586,6 @@ static int alx_stop(struct net_device *netdev) WARN_ON(ALX_FLAG(adpt, RESETING)); - netif_info(adpt, ifdown, adpt->netdev, "alx_stop\n"); - __alx_stop(adpt); return 0; @@ -1616,14 +1613,18 @@ static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en) if (!err) err = alx_clear_phy_intr(hw); if (!err) - err = alx_config_wol(hw); - if (!err) err = alx_pre_suspend(hw, speed); + if (!err) + err = alx_config_wol(hw); if (err) goto out; *wol_en = false; if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) { + netif_info(adpt, wol, netdev, + "wol: ctrl=%X, speed=%X\n", + hw->sleep_ctrl, speed); + device_set_wakeup_enable(&pdev->dev, true); *wol_en = true; } @@ -1655,7 +1656,6 @@ static void alx_shutdown(struct pci_dev *pdev) } } - #ifdef CONFIG_PM_SLEEP static int alx_suspend(struct device *dev) { @@ -1700,6 +1700,7 @@ static int alx_resume(struct device *dev) hw->link_up = false; hw->link_speed = SPEED_0; + hw->imask = ALX_ISR_MISC; alx_reset_pcie(hw); alx_reset_phy(hw, !hw->hib_patch); @@ -1719,7 +1720,7 @@ static int alx_resume(struct device *dev) } if (netif_running(netdev)) { - err = __alx_open(adpt); + err = __alx_open(adpt, true); if (err) return err; } @@ -2320,8 +2321,8 @@ static void alx_dump_state(struct alx_adapter *adpt) for (i = 0; i < adpt->nr_txq; i++) { txq = adpt->qnapi[i]->txq; - begin = txq->pidx >= 16 ? (txq->pidx - 16) : - (txq->count + txq->pidx - 16); + begin = txq->pidx >= 8 ? (txq->pidx - 8) : + (txq->count + txq->pidx - 8); end = txq->pidx + 4; if (end >= txq->count) end -= txq->count; @@ -2343,8 +2344,8 @@ static void alx_dump_state(struct alx_adapter *adpt) netif_err(adpt, tx_err, adpt->netdev, "---------------dump registers-----------------\n"); - end = 0x2000; - for (begin = 0; begin < end; begin += 16) { + end = 0x1800; + for (begin = 0x1400; begin < end; begin += 16) { u32 v1, v2, v3, v4; ALX_MEM_R32(hw, begin, &v1); @@ -2578,6 +2579,8 @@ alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* reset PHY to a known stable status */ if (!phy_cfged) alx_reset_phy(hw, !hw->hib_patch); + else + dev_info(&pdev->dev, "PHY has been configured.\n"); /* reset mac/dma controller */ err = alx_reset_mac(hw); @@ -2706,6 +2709,8 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, struct net_device *netdev = adpt->netdev; pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; + dev_info(&pdev->dev, "pci error detected\n"); + rtnl_lock(); if (netif_running(netdev)) { @@ -2729,6 +2734,8 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) struct alx_hw *hw = &adpt->hw; pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + dev_info(&pdev->dev, "pci error slot reset\n"); + rtnl_lock(); if (pci_enable_device(pdev)) { @@ -2757,6 +2764,8 @@ static void alx_pci_error_resume(struct pci_dev *pdev) struct alx_adapter *adpt = pci_get_drvdata(pdev); struct net_device *netdev = adpt->netdev; + dev_info(&pdev->dev, "pci error resume\n"); + rtnl_lock(); if (netif_running(netdev)) { |