diff options
author | Mike McCormack <mikem@ring3k.org> | 2010-02-12 01:58:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-12 19:21:02 -0500 |
commit | 200ac492b3c366346fcabd11897fadbd1a7a6599 (patch) | |
tree | 1dbf91be83168ca6ec6d3612544d58ca3f96fac6 /drivers/net | |
parent | 39ef110ba859f44efeb9a88d0e85316cd1bbecda (diff) |
sky2: Allocate initial skbs in sky2_alloc_buffers
Allocate everything in one place so there's a single point
of failure in sky2_up, and sky2_rx_start can no longer fail.
Don't leave the hardware in a partially initialized state in the
case rx ring allocation fails.
As with the old code, the rx ring still needs to be fully
allocated for sky2_up to succeed.
Signed-off-by: Mike McCormack <mikem@ring3k.org>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c5de65c6f6e1..493a82018cbd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1363,8 +1363,32 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq) | |||
1363 | sky2_put_idx(sky2->hw, rxq, sky2->rx_put); | 1363 | sky2_put_idx(sky2->hw, rxq, sky2->rx_put); |
1364 | } | 1364 | } |
1365 | 1365 | ||
1366 | static int sky2_alloc_rx_skbs(struct sky2_port *sky2) | ||
1367 | { | ||
1368 | struct sky2_hw *hw = sky2->hw; | ||
1369 | unsigned i; | ||
1370 | |||
1371 | sky2->rx_data_size = sky2_get_rx_data_size(sky2); | ||
1372 | |||
1373 | /* Fill Rx ring */ | ||
1374 | for (i = 0; i < sky2->rx_pending; i++) { | ||
1375 | struct rx_ring_info *re = sky2->rx_ring + i; | ||
1376 | |||
1377 | re->skb = sky2_rx_alloc(sky2); | ||
1378 | if (!re->skb) | ||
1379 | return -ENOMEM; | ||
1380 | |||
1381 | if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) { | ||
1382 | dev_kfree_skb(re->skb); | ||
1383 | re->skb = NULL; | ||
1384 | return -ENOMEM; | ||
1385 | } | ||
1386 | } | ||
1387 | return 0; | ||
1388 | } | ||
1389 | |||
1366 | /* | 1390 | /* |
1367 | * Allocate and setup receiver buffer pool. | 1391 | * Setup receiver buffer pool. |
1368 | * Normal case this ends up creating one list element for skb | 1392 | * Normal case this ends up creating one list element for skb |
1369 | * in the receive ring. Worst case if using large MTU and each | 1393 | * in the receive ring. Worst case if using large MTU and each |
1370 | * allocation falls on a different 64 bit region, that results | 1394 | * allocation falls on a different 64 bit region, that results |
@@ -1372,7 +1396,7 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq) | |||
1372 | * One element is used for checksum enable/disable, and one | 1396 | * One element is used for checksum enable/disable, and one |
1373 | * extra to avoid wrap. | 1397 | * extra to avoid wrap. |
1374 | */ | 1398 | */ |
1375 | static int sky2_rx_start(struct sky2_port *sky2) | 1399 | static void sky2_rx_start(struct sky2_port *sky2) |
1376 | { | 1400 | { |
1377 | struct sky2_hw *hw = sky2->hw; | 1401 | struct sky2_hw *hw = sky2->hw; |
1378 | struct rx_ring_info *re; | 1402 | struct rx_ring_info *re; |
@@ -1398,22 +1422,9 @@ static int sky2_rx_start(struct sky2_port *sky2) | |||
1398 | if (!(hw->flags & SKY2_HW_NEW_LE)) | 1422 | if (!(hw->flags & SKY2_HW_NEW_LE)) |
1399 | rx_set_checksum(sky2); | 1423 | rx_set_checksum(sky2); |
1400 | 1424 | ||
1401 | sky2->rx_data_size = sky2_get_rx_data_size(sky2); | 1425 | /* submit Rx ring */ |
1402 | |||
1403 | /* Fill Rx ring */ | ||
1404 | for (i = 0; i < sky2->rx_pending; i++) { | 1426 | for (i = 0; i < sky2->rx_pending; i++) { |
1405 | re = sky2->rx_ring + i; | 1427 | re = sky2->rx_ring + i; |
1406 | |||
1407 | re->skb = sky2_rx_alloc(sky2); | ||
1408 | if (!re->skb) | ||
1409 | goto nomem; | ||
1410 | |||
1411 | if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) { | ||
1412 | dev_kfree_skb(re->skb); | ||
1413 | re->skb = NULL; | ||
1414 | goto nomem; | ||
1415 | } | ||
1416 | |||
1417 | sky2_rx_submit(sky2, re); | 1428 | sky2_rx_submit(sky2, re); |
1418 | } | 1429 | } |
1419 | 1430 | ||
@@ -1455,13 +1466,6 @@ static int sky2_rx_start(struct sky2_port *sky2) | |||
1455 | sky2_write32(hw, Q_ADDR(txqaddr[sky2->port], Q_TEST), | 1466 | sky2_write32(hw, Q_ADDR(txqaddr[sky2->port], Q_TEST), |
1456 | TBMU_TEST_HOME_ADD_FIX_EN | TBMU_TEST_ROUTING_ADD_FIX_EN); | 1467 | TBMU_TEST_HOME_ADD_FIX_EN | TBMU_TEST_ROUTING_ADD_FIX_EN); |
1457 | } | 1468 | } |
1458 | |||
1459 | |||
1460 | |||
1461 | return 0; | ||
1462 | nomem: | ||
1463 | sky2_rx_clean(sky2); | ||
1464 | return -ENOMEM; | ||
1465 | } | 1469 | } |
1466 | 1470 | ||
1467 | static int sky2_alloc_buffers(struct sky2_port *sky2) | 1471 | static int sky2_alloc_buffers(struct sky2_port *sky2) |
@@ -1492,7 +1496,7 @@ static int sky2_alloc_buffers(struct sky2_port *sky2) | |||
1492 | if (!sky2->rx_ring) | 1496 | if (!sky2->rx_ring) |
1493 | goto nomem; | 1497 | goto nomem; |
1494 | 1498 | ||
1495 | return 0; | 1499 | return sky2_alloc_rx_skbs(sky2); |
1496 | nomem: | 1500 | nomem: |
1497 | return -ENOMEM; | 1501 | return -ENOMEM; |
1498 | } | 1502 | } |
@@ -1501,6 +1505,8 @@ static void sky2_free_buffers(struct sky2_port *sky2) | |||
1501 | { | 1505 | { |
1502 | struct sky2_hw *hw = sky2->hw; | 1506 | struct sky2_hw *hw = sky2->hw; |
1503 | 1507 | ||
1508 | sky2_rx_clean(sky2); | ||
1509 | |||
1504 | if (sky2->rx_le) { | 1510 | if (sky2->rx_le) { |
1505 | pci_free_consistent(hw->pdev, RX_LE_BYTES, | 1511 | pci_free_consistent(hw->pdev, RX_LE_BYTES, |
1506 | sky2->rx_le, sky2->rx_le_map); | 1512 | sky2->rx_le, sky2->rx_le_map); |
@@ -1590,9 +1596,7 @@ static int sky2_up(struct net_device *dev) | |||
1590 | sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); | 1596 | sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); |
1591 | #endif | 1597 | #endif |
1592 | 1598 | ||
1593 | err = sky2_rx_start(sky2); | 1599 | sky2_rx_start(sky2); |
1594 | if (err) | ||
1595 | goto err_out; | ||
1596 | 1600 | ||
1597 | /* Enable interrupts from phy/mac for port */ | 1601 | /* Enable interrupts from phy/mac for port */ |
1598 | imask = sky2_read32(hw, B0_IMSK); | 1602 | imask = sky2_read32(hw, B0_IMSK); |
@@ -1960,8 +1964,6 @@ static int sky2_down(struct net_device *dev) | |||
1960 | /* Free any pending frames stuck in HW queue */ | 1964 | /* Free any pending frames stuck in HW queue */ |
1961 | sky2_tx_complete(sky2, sky2->tx_prod); | 1965 | sky2_tx_complete(sky2, sky2->tx_prod); |
1962 | 1966 | ||
1963 | sky2_rx_clean(sky2); | ||
1964 | |||
1965 | sky2_free_buffers(sky2); | 1967 | sky2_free_buffers(sky2); |
1966 | 1968 | ||
1967 | return 0; | 1969 | return 0; |
@@ -2257,7 +2259,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) | |||
2257 | 2259 | ||
2258 | sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD); | 2260 | sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD); |
2259 | 2261 | ||
2260 | err = sky2_rx_start(sky2); | 2262 | err = sky2_alloc_rx_skbs(sky2); |
2263 | if (!err) | ||
2264 | sky2_rx_start(sky2); | ||
2265 | else | ||
2266 | sky2_rx_clean(sky2); | ||
2261 | sky2_write32(hw, B0_IMSK, imask); | 2267 | sky2_write32(hw, B0_IMSK, imask); |
2262 | 2268 | ||
2263 | sky2_read32(hw, B0_Y2_SP_LISR); | 2269 | sky2_read32(hw, B0_Y2_SP_LISR); |