diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2009-03-27 03:38:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-27 03:38:45 -0400 |
commit | 54dc79fe0d895758bdaa1dcf8512d3d21263d105 (patch) | |
tree | 8a6e73c9e3a227f420bd258d538dd525f3955f9c /drivers/net/gianfar.c | |
parent | 83e0bbcbe2145f160fbaa109b0439dae7f4a38a9 (diff) |
gianfar: fix headroom expansion code
The code that was added to increase headroom was wrong.
It doesn't handle the case where gfar_add_fcb() changes the skb.
Better to do check at start of transmit (outside of lock), where
error handling is better anyway.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r-- | drivers/net/gianfar.c | 46 |
1 files changed, 24 insertions, 22 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 9d81e7a48dba..a7a67376615b 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -1239,19 +1239,9 @@ static int gfar_enet_open(struct net_device *dev) | |||
1239 | return err; | 1239 | return err; |
1240 | } | 1240 | } |
1241 | 1241 | ||
1242 | static inline struct txfcb *gfar_add_fcb(struct sk_buff **skbp) | 1242 | static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) |
1243 | { | 1243 | { |
1244 | struct txfcb *fcb; | 1244 | struct txfcb *fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN); |
1245 | struct sk_buff *skb = *skbp; | ||
1246 | |||
1247 | if (unlikely(skb_headroom(skb) < GMAC_FCB_LEN)) { | ||
1248 | struct sk_buff *old_skb = skb; | ||
1249 | skb = skb_realloc_headroom(old_skb, GMAC_FCB_LEN); | ||
1250 | if (!skb) | ||
1251 | return NULL; | ||
1252 | dev_kfree_skb_any(old_skb); | ||
1253 | } | ||
1254 | fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN); | ||
1255 | cacheable_memzero(fcb, GMAC_FCB_LEN); | 1245 | cacheable_memzero(fcb, GMAC_FCB_LEN); |
1256 | 1246 | ||
1257 | return fcb; | 1247 | return fcb; |
@@ -1320,6 +1310,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1320 | 1310 | ||
1321 | base = priv->tx_bd_base; | 1311 | base = priv->tx_bd_base; |
1322 | 1312 | ||
1313 | /* make space for additional header */ | ||
1314 | if (skb_headroom(skb) < GMAC_FCB_LEN) { | ||
1315 | struct sk_buff *skb_new; | ||
1316 | |||
1317 | skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN); | ||
1318 | if (!skb_new) { | ||
1319 | dev->stats.tx_errors++; | ||
1320 | kfree(skb); | ||
1321 | return NETDEV_TX_OK; | ||
1322 | } | ||
1323 | kfree_skb(skb); | ||
1324 | skb = skb_new; | ||
1325 | } | ||
1326 | |||
1323 | /* total number of fragments in the SKB */ | 1327 | /* total number of fragments in the SKB */ |
1324 | nr_frags = skb_shinfo(skb)->nr_frags; | 1328 | nr_frags = skb_shinfo(skb)->nr_frags; |
1325 | 1329 | ||
@@ -1372,20 +1376,18 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1372 | 1376 | ||
1373 | /* Set up checksumming */ | 1377 | /* Set up checksumming */ |
1374 | if (CHECKSUM_PARTIAL == skb->ip_summed) { | 1378 | if (CHECKSUM_PARTIAL == skb->ip_summed) { |
1375 | fcb = gfar_add_fcb(&skb); | 1379 | fcb = gfar_add_fcb(skb); |
1376 | if (likely(fcb != NULL)) { | 1380 | lstatus |= BD_LFLAG(TXBD_TOE); |
1377 | lstatus |= BD_LFLAG(TXBD_TOE); | 1381 | gfar_tx_checksum(skb, fcb); |
1378 | gfar_tx_checksum(skb, fcb); | ||
1379 | } | ||
1380 | } | 1382 | } |
1381 | 1383 | ||
1382 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { | 1384 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { |
1383 | if (unlikely(NULL == fcb)) | 1385 | if (unlikely(NULL == fcb)) { |
1384 | fcb = gfar_add_fcb(&skb); | 1386 | fcb = gfar_add_fcb(skb); |
1385 | if (likely(fcb != NULL)) { | ||
1386 | lstatus |= BD_LFLAG(TXBD_TOE); | 1387 | lstatus |= BD_LFLAG(TXBD_TOE); |
1387 | gfar_tx_vlan(skb, fcb); | ||
1388 | } | 1388 | } |
1389 | |||
1390 | gfar_tx_vlan(skb, fcb); | ||
1389 | } | 1391 | } |
1390 | 1392 | ||
1391 | /* setup the TxBD length and buffer pointer for the first BD */ | 1393 | /* setup the TxBD length and buffer pointer for the first BD */ |
@@ -1433,7 +1435,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1433 | /* Unlock priv */ | 1435 | /* Unlock priv */ |
1434 | spin_unlock_irqrestore(&priv->txlock, flags); | 1436 | spin_unlock_irqrestore(&priv->txlock, flags); |
1435 | 1437 | ||
1436 | return 0; | 1438 | return NETDEV_TX_OK; |
1437 | } | 1439 | } |
1438 | 1440 | ||
1439 | /* Stops the kernel queue, and halts the controller */ | 1441 | /* Stops the kernel queue, and halts the controller */ |