aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/atheros
diff options
context:
space:
mode:
authorHuang, Xiong <xiong@qca.qualcomm.com>2012-04-30 11:38:56 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-30 21:44:15 -0400
commit5e5c0964d9b93debb040431b5036d28fe8b19136 (patch)
treed0fb8d55bb621b064b64d573c1aa7705365c75be /drivers/net/ethernet/atheros
parent0aa76ce3324e324d3091aef0c3e22c249ae4b693 (diff)
atl1c: do MAC-reset when PHY link down
There may be tx-skbs still pending in HW when PHY link down. Reset MAC will make the DMA engine go to the start point. and release all pending skbs. Note: Reset MAC will clear any interrupt status and mask. Signed-off-by: xiong <xiong@qca.qualcomm.com> Tested-by: Liu David <dwliu@qca.qualcomm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/atheros')
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c74
1 files changed, 47 insertions, 27 deletions
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index b95ef4505115..e6c62d0aff05 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -60,6 +60,10 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter,
60 int *work_done, int work_to_do); 60 int *work_done, int work_to_do);
61static int atl1c_up(struct atl1c_adapter *adapter); 61static int atl1c_up(struct atl1c_adapter *adapter);
62static void atl1c_down(struct atl1c_adapter *adapter); 62static void atl1c_down(struct atl1c_adapter *adapter);
63static int atl1c_reset_mac(struct atl1c_hw *hw);
64static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter);
65static int atl1c_configure(struct atl1c_adapter *adapter);
66static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter);
63 67
64static const u16 atl1c_pay_load_size[] = { 68static const u16 atl1c_pay_load_size[] = {
65 128, 256, 512, 1024, 2048, 4096, 69 128, 256, 512, 1024, 2048, 4096,
@@ -256,14 +260,16 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
256 260
257 if ((phy_data & BMSR_LSTATUS) == 0) { 261 if ((phy_data & BMSR_LSTATUS) == 0) {
258 /* link down */ 262 /* link down */
263 netif_carrier_off(netdev);
264 netif_stop_queue(netdev);
259 hw->hibernate = true; 265 hw->hibernate = true;
260 if (atl1c_stop_mac(hw) != 0) 266 if (atl1c_reset_mac(hw) != 0)
261 if (netif_msg_hw(adapter)) 267 if (netif_msg_hw(adapter))
262 dev_warn(&pdev->dev, "stop mac failed\n"); 268 dev_warn(&pdev->dev, "reset mac failed\n");
263 atl1c_set_aspm(hw, SPEED_0); 269 atl1c_set_aspm(hw, SPEED_0);
264 atl1c_post_phy_linkchg(hw, SPEED_0); 270 atl1c_post_phy_linkchg(hw, SPEED_0);
265 netif_carrier_off(netdev); 271 atl1c_reset_dma_ring(adapter);
266 netif_stop_queue(netdev); 272 atl1c_configure(adapter);
267 } else { 273 } else {
268 /* Link Up */ 274 /* Link Up */
269 hw->hibernate = false; 275 hw->hibernate = false;
@@ -341,8 +347,11 @@ static void atl1c_common_task(struct work_struct *work)
341 } 347 }
342 348
343 if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, 349 if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE,
344 &adapter->work_event)) 350 &adapter->work_event)) {
351 atl1c_irq_disable(adapter);
345 atl1c_check_link_status(adapter); 352 atl1c_check_link_status(adapter);
353 atl1c_irq_enable(adapter);
354 }
346} 355}
347 356
348 357
@@ -1230,9 +1239,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
1230 struct pci_dev *pdev = adapter->pdev; 1239 struct pci_dev *pdev = adapter->pdev;
1231 u32 ctrl_data = 0; 1240 u32 ctrl_data = 0;
1232 1241
1233 AT_WRITE_REG(hw, REG_IMR, 0);
1234 AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
1235
1236 atl1c_stop_mac(hw); 1242 atl1c_stop_mac(hw);
1237 /* 1243 /*
1238 * Issue Soft Reset to the MAC. This will reset the chip's 1244 * Issue Soft Reset to the MAC. This will reset the chip's
@@ -1371,7 +1377,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed)
1371 * 1377 *
1372 * Configure the Tx /Rx unit of the MAC after a reset. 1378 * Configure the Tx /Rx unit of the MAC after a reset.
1373 */ 1379 */
1374static int atl1c_configure(struct atl1c_adapter *adapter) 1380static int atl1c_configure_mac(struct atl1c_adapter *adapter)
1375{ 1381{
1376 struct atl1c_hw *hw = &adapter->hw; 1382 struct atl1c_hw *hw = &adapter->hw;
1377 u32 master_ctrl_data = 0; 1383 u32 master_ctrl_data = 0;
@@ -1434,6 +1440,25 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
1434 return 0; 1440 return 0;
1435} 1441}
1436 1442
1443static int atl1c_configure(struct atl1c_adapter *adapter)
1444{
1445 struct net_device *netdev = adapter->netdev;
1446 int num;
1447
1448 atl1c_init_ring_ptrs(adapter);
1449 atl1c_set_multi(netdev);
1450 atl1c_restore_vlan(adapter);
1451
1452 num = atl1c_alloc_rx_buffer(adapter);
1453 if (unlikely(num == 0))
1454 return -ENOMEM;
1455
1456 if (atl1c_configure_mac(adapter))
1457 return -EIO;
1458
1459 return 0;
1460}
1461
1437static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) 1462static void atl1c_update_hw_stats(struct atl1c_adapter *adapter)
1438{ 1463{
1439 u16 hw_reg_addr = 0; 1464 u16 hw_reg_addr = 0;
@@ -2194,41 +2219,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter)
2194 return err; 2219 return err;
2195} 2220}
2196 2221
2222
2223static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter)
2224{
2225 /* release tx-pending skbs and reset tx/rx ring index */
2226 atl1c_clean_tx_ring(adapter, atl1c_trans_normal);
2227 atl1c_clean_tx_ring(adapter, atl1c_trans_high);
2228 atl1c_clean_rx_ring(adapter);
2229}
2230
2197static int atl1c_up(struct atl1c_adapter *adapter) 2231static int atl1c_up(struct atl1c_adapter *adapter)
2198{ 2232{
2199 struct net_device *netdev = adapter->netdev; 2233 struct net_device *netdev = adapter->netdev;
2200 int num;
2201 int err; 2234 int err;
2202 2235
2203 netif_carrier_off(netdev); 2236 netif_carrier_off(netdev);
2204 atl1c_init_ring_ptrs(adapter);
2205 atl1c_set_multi(netdev);
2206 atl1c_restore_vlan(adapter);
2207 2237
2208 num = atl1c_alloc_rx_buffer(adapter); 2238 err = atl1c_configure(adapter);
2209 if (unlikely(num == 0)) { 2239 if (unlikely(err))
2210 err = -ENOMEM;
2211 goto err_alloc_rx;
2212 }
2213
2214 if (atl1c_configure(adapter)) {
2215 err = -EIO;
2216 goto err_up; 2240 goto err_up;
2217 }
2218 2241
2219 err = atl1c_request_irq(adapter); 2242 err = atl1c_request_irq(adapter);
2220 if (unlikely(err)) 2243 if (unlikely(err))
2221 goto err_up; 2244 goto err_up;
2222 2245
2246 atl1c_check_link_status(adapter);
2223 clear_bit(__AT_DOWN, &adapter->flags); 2247 clear_bit(__AT_DOWN, &adapter->flags);
2224 napi_enable(&adapter->napi); 2248 napi_enable(&adapter->napi);
2225 atl1c_irq_enable(adapter); 2249 atl1c_irq_enable(adapter);
2226 atl1c_check_link_status(adapter);
2227 netif_start_queue(netdev); 2250 netif_start_queue(netdev);
2228 return err; 2251 return err;
2229 2252
2230err_up: 2253err_up:
2231err_alloc_rx:
2232 atl1c_clean_rx_ring(adapter); 2254 atl1c_clean_rx_ring(adapter);
2233 return err; 2255 return err;
2234} 2256}
@@ -2254,9 +2276,7 @@ static void atl1c_down(struct atl1c_adapter *adapter)
2254 2276
2255 adapter->link_speed = SPEED_0; 2277 adapter->link_speed = SPEED_0;
2256 adapter->link_duplex = -1; 2278 adapter->link_duplex = -1;
2257 atl1c_clean_tx_ring(adapter, atl1c_trans_normal); 2279 atl1c_reset_dma_ring(adapter);
2258 atl1c_clean_tx_ring(adapter, atl1c_trans_high);
2259 atl1c_clean_rx_ring(adapter);
2260} 2280}
2261 2281
2262/* 2282/*