diff options
author | Huang, Xiong <xiong@qca.qualcomm.com> | 2012-04-30 11:38:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-30 21:44:15 -0400 |
commit | 5e5c0964d9b93debb040431b5036d28fe8b19136 (patch) | |
tree | d0fb8d55bb621b064b64d573c1aa7705365c75be /drivers/net/ethernet/atheros | |
parent | 0aa76ce3324e324d3091aef0c3e22c249ae4b693 (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.c | 74 |
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); |
61 | static int atl1c_up(struct atl1c_adapter *adapter); | 61 | static int atl1c_up(struct atl1c_adapter *adapter); |
62 | static void atl1c_down(struct atl1c_adapter *adapter); | 62 | static void atl1c_down(struct atl1c_adapter *adapter); |
63 | static int atl1c_reset_mac(struct atl1c_hw *hw); | ||
64 | static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter); | ||
65 | static int atl1c_configure(struct atl1c_adapter *adapter); | ||
66 | static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter); | ||
63 | 67 | ||
64 | static const u16 atl1c_pay_load_size[] = { | 68 | static 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 | */ |
1374 | static int atl1c_configure(struct atl1c_adapter *adapter) | 1380 | static 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 | ||
1443 | static 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 | |||
1437 | static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) | 1462 | static 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 | |||
2223 | static 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 | |||
2197 | static int atl1c_up(struct atl1c_adapter *adapter) | 2231 | static 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 | ||
2230 | err_up: | 2253 | err_up: |
2231 | err_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 | /* |