diff options
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r-- | drivers/net/gianfar.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 9d81e7a48dba..6a38800be3f1 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,22 @@ 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 when fcb is needed */ | ||
1314 | if (((skb->ip_summed == CHECKSUM_PARTIAL) || | ||
1315 | (priv->vlgrp && vlan_tx_tag_present(skb))) && | ||
1316 | (skb_headroom(skb) < GMAC_FCB_LEN)) { | ||
1317 | struct sk_buff *skb_new; | ||
1318 | |||
1319 | skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN); | ||
1320 | if (!skb_new) { | ||
1321 | dev->stats.tx_errors++; | ||
1322 | kfree_skb(skb); | ||
1323 | return NETDEV_TX_OK; | ||
1324 | } | ||
1325 | kfree_skb(skb); | ||
1326 | skb = skb_new; | ||
1327 | } | ||
1328 | |||
1323 | /* total number of fragments in the SKB */ | 1329 | /* total number of fragments in the SKB */ |
1324 | nr_frags = skb_shinfo(skb)->nr_frags; | 1330 | nr_frags = skb_shinfo(skb)->nr_frags; |
1325 | 1331 | ||
@@ -1372,20 +1378,18 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1372 | 1378 | ||
1373 | /* Set up checksumming */ | 1379 | /* Set up checksumming */ |
1374 | if (CHECKSUM_PARTIAL == skb->ip_summed) { | 1380 | if (CHECKSUM_PARTIAL == skb->ip_summed) { |
1375 | fcb = gfar_add_fcb(&skb); | 1381 | fcb = gfar_add_fcb(skb); |
1376 | if (likely(fcb != NULL)) { | 1382 | lstatus |= BD_LFLAG(TXBD_TOE); |
1377 | lstatus |= BD_LFLAG(TXBD_TOE); | 1383 | gfar_tx_checksum(skb, fcb); |
1378 | gfar_tx_checksum(skb, fcb); | ||
1379 | } | ||
1380 | } | 1384 | } |
1381 | 1385 | ||
1382 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { | 1386 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { |
1383 | if (unlikely(NULL == fcb)) | 1387 | if (unlikely(NULL == fcb)) { |
1384 | fcb = gfar_add_fcb(&skb); | 1388 | fcb = gfar_add_fcb(skb); |
1385 | if (likely(fcb != NULL)) { | ||
1386 | lstatus |= BD_LFLAG(TXBD_TOE); | 1389 | lstatus |= BD_LFLAG(TXBD_TOE); |
1387 | gfar_tx_vlan(skb, fcb); | ||
1388 | } | 1390 | } |
1391 | |||
1392 | gfar_tx_vlan(skb, fcb); | ||
1389 | } | 1393 | } |
1390 | 1394 | ||
1391 | /* setup the TxBD length and buffer pointer for the first BD */ | 1395 | /* setup the TxBD length and buffer pointer for the first BD */ |
@@ -1433,7 +1437,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1433 | /* Unlock priv */ | 1437 | /* Unlock priv */ |
1434 | spin_unlock_irqrestore(&priv->txlock, flags); | 1438 | spin_unlock_irqrestore(&priv->txlock, flags); |
1435 | 1439 | ||
1436 | return 0; | 1440 | return NETDEV_TX_OK; |
1437 | } | 1441 | } |
1438 | 1442 | ||
1439 | /* Stops the kernel queue, and halts the controller */ | 1443 | /* Stops the kernel queue, and halts the controller */ |