diff options
| author | Li Yang <leoli@freescale.com> | 2009-03-24 19:15:33 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-03-25 20:21:19 -0400 |
| commit | 93c1285c5d92c31f9bcc20355f1e86e95bec165e (patch) | |
| tree | ef24903fe05abdb9796ed4636d3a05f357b5c238 | |
| parent | 8ca51986be0c19c8a48ef8f36568c5a3c2c0ac50 (diff) | |
gianfar: reallocate skb when headroom is not enough for fcb
Gianfar uses a hardware header FCB for offloading. However when used
with bridging or IP forwarding, TX skb might not have enough headroom
for the FCB. Reallocate skb for such cases.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/gianfar.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 8a51df045e84..9d81e7a48dba 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
| @@ -1239,10 +1239,19 @@ 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 *skb) | 1242 | static inline struct txfcb *gfar_add_fcb(struct sk_buff **skbp) |
| 1243 | { | 1243 | { |
| 1244 | struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN); | 1244 | struct txfcb *fcb; |
| 1245 | 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); | ||
| 1246 | cacheable_memzero(fcb, GMAC_FCB_LEN); | 1255 | cacheable_memzero(fcb, GMAC_FCB_LEN); |
| 1247 | 1256 | ||
| 1248 | return fcb; | 1257 | return fcb; |
| @@ -1363,18 +1372,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1363 | 1372 | ||
| 1364 | /* Set up checksumming */ | 1373 | /* Set up checksumming */ |
| 1365 | if (CHECKSUM_PARTIAL == skb->ip_summed) { | 1374 | if (CHECKSUM_PARTIAL == skb->ip_summed) { |
| 1366 | fcb = gfar_add_fcb(skb); | 1375 | fcb = gfar_add_fcb(&skb); |
| 1367 | lstatus |= BD_LFLAG(TXBD_TOE); | 1376 | if (likely(fcb != NULL)) { |
| 1368 | gfar_tx_checksum(skb, fcb); | 1377 | lstatus |= BD_LFLAG(TXBD_TOE); |
| 1378 | gfar_tx_checksum(skb, fcb); | ||
| 1379 | } | ||
| 1369 | } | 1380 | } |
| 1370 | 1381 | ||
| 1371 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { | 1382 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { |
| 1372 | if (unlikely(NULL == fcb)) { | 1383 | if (unlikely(NULL == fcb)) |
| 1373 | fcb = gfar_add_fcb(skb); | 1384 | fcb = gfar_add_fcb(&skb); |
| 1385 | if (likely(fcb != NULL)) { | ||
| 1374 | lstatus |= BD_LFLAG(TXBD_TOE); | 1386 | lstatus |= BD_LFLAG(TXBD_TOE); |
| 1387 | gfar_tx_vlan(skb, fcb); | ||
| 1375 | } | 1388 | } |
| 1376 | |||
| 1377 | gfar_tx_vlan(skb, fcb); | ||
| 1378 | } | 1389 | } |
| 1379 | 1390 | ||
| 1380 | /* setup the TxBD length and buffer pointer for the first BD */ | 1391 | /* setup the TxBD length and buffer pointer for the first BD */ |
