diff options
author | Dai Haruki <dai.haruki@freescale.com> | 2008-12-17 19:51:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-17 19:51:04 -0500 |
commit | 4669bc907488f5a3ee399ced132deb6165e489a3 (patch) | |
tree | 916d6d5ecca6f989aa02791fbbcb224e0c6c7ecd /drivers | |
parent | 8882d9a60028a9937e9c5652cfb80d4399ce5242 (diff) |
gianfar: Add Scatter Gather support
Scatter Gather support in gianfar driver to handle fragmented frames on
the transmit side.
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: Dai Haruki <dai.haruki@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/gianfar.c | 217 | ||||
-rw-r--r-- | drivers/net/gianfar.h | 1 | ||||
-rw-r--r-- | drivers/net/gianfar_ethtool.c | 2 |
3 files changed, 149 insertions, 71 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a6efabc28dc8..dbbeee372ef8 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -368,7 +368,7 @@ static int gfar_probe(struct of_device *ofdev, | |||
368 | 368 | ||
369 | if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { | 369 | if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { |
370 | priv->rx_csum_enable = 1; | 370 | priv->rx_csum_enable = 1; |
371 | dev->features |= NETIF_F_IP_CSUM; | 371 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; |
372 | } else | 372 | } else |
373 | priv->rx_csum_enable = 0; | 373 | priv->rx_csum_enable = 0; |
374 | 374 | ||
@@ -426,6 +426,7 @@ static int gfar_probe(struct of_device *ofdev, | |||
426 | priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; | 426 | priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; |
427 | priv->tx_ring_size = DEFAULT_TX_RING_SIZE; | 427 | priv->tx_ring_size = DEFAULT_TX_RING_SIZE; |
428 | priv->rx_ring_size = DEFAULT_RX_RING_SIZE; | 428 | priv->rx_ring_size = DEFAULT_RX_RING_SIZE; |
429 | priv->num_txbdfree = DEFAULT_TX_RING_SIZE; | ||
429 | 430 | ||
430 | priv->txcoalescing = DEFAULT_TX_COALESCE; | 431 | priv->txcoalescing = DEFAULT_TX_COALESCE; |
431 | priv->txic = DEFAULT_TXIC; | 432 | priv->txic = DEFAULT_TXIC; |
@@ -819,22 +820,26 @@ static void free_skb_resources(struct gfar_private *priv) | |||
819 | { | 820 | { |
820 | struct rxbd8 *rxbdp; | 821 | struct rxbd8 *rxbdp; |
821 | struct txbd8 *txbdp; | 822 | struct txbd8 *txbdp; |
822 | int i; | 823 | int i, j; |
823 | 824 | ||
824 | /* Go through all the buffer descriptors and free their data buffers */ | 825 | /* Go through all the buffer descriptors and free their data buffers */ |
825 | txbdp = priv->tx_bd_base; | 826 | txbdp = priv->tx_bd_base; |
826 | 827 | ||
827 | for (i = 0; i < priv->tx_ring_size; i++) { | 828 | for (i = 0; i < priv->tx_ring_size; i++) { |
829 | if (!priv->tx_skbuff[i]) | ||
830 | continue; | ||
828 | 831 | ||
829 | if (priv->tx_skbuff[i]) { | 832 | dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, |
830 | dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, | 833 | txbdp->length, DMA_TO_DEVICE); |
831 | txbdp->length, | 834 | txbdp->lstatus = 0; |
832 | DMA_TO_DEVICE); | 835 | for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) { |
833 | dev_kfree_skb_any(priv->tx_skbuff[i]); | 836 | txbdp++; |
834 | priv->tx_skbuff[i] = NULL; | 837 | dma_unmap_page(&priv->dev->dev, txbdp->bufPtr, |
838 | txbdp->length, DMA_TO_DEVICE); | ||
835 | } | 839 | } |
836 | |||
837 | txbdp++; | 840 | txbdp++; |
841 | dev_kfree_skb_any(priv->tx_skbuff[i]); | ||
842 | priv->tx_skbuff[i] = NULL; | ||
838 | } | 843 | } |
839 | 844 | ||
840 | kfree(priv->tx_skbuff); | 845 | kfree(priv->tx_skbuff); |
@@ -967,6 +972,7 @@ int startup_gfar(struct net_device *dev) | |||
967 | priv->rx_skbuff[i] = NULL; | 972 | priv->rx_skbuff[i] = NULL; |
968 | 973 | ||
969 | /* Initialize some variables in our dev structure */ | 974 | /* Initialize some variables in our dev structure */ |
975 | priv->num_txbdfree = priv->tx_ring_size; | ||
970 | priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; | 976 | priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; |
971 | priv->cur_rx = priv->rx_bd_base; | 977 | priv->cur_rx = priv->rx_bd_base; |
972 | priv->skb_curtx = priv->skb_dirtytx = 0; | 978 | priv->skb_curtx = priv->skb_dirtytx = 0; |
@@ -1207,28 +1213,84 @@ void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) | |||
1207 | fcb->vlctl = vlan_tx_tag_get(skb); | 1213 | fcb->vlctl = vlan_tx_tag_get(skb); |
1208 | } | 1214 | } |
1209 | 1215 | ||
1216 | static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride, | ||
1217 | struct txbd8 *base, int ring_size) | ||
1218 | { | ||
1219 | struct txbd8 *new_bd = bdp + stride; | ||
1220 | |||
1221 | return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd; | ||
1222 | } | ||
1223 | |||
1224 | static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base, | ||
1225 | int ring_size) | ||
1226 | { | ||
1227 | return skip_txbd(bdp, 1, base, ring_size); | ||
1228 | } | ||
1229 | |||
1210 | /* This is called by the kernel when a frame is ready for transmission. */ | 1230 | /* This is called by the kernel when a frame is ready for transmission. */ |
1211 | /* It is pointed to by the dev->hard_start_xmit function pointer */ | 1231 | /* It is pointed to by the dev->hard_start_xmit function pointer */ |
1212 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | 1232 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) |
1213 | { | 1233 | { |
1214 | struct gfar_private *priv = netdev_priv(dev); | 1234 | struct gfar_private *priv = netdev_priv(dev); |
1215 | struct txfcb *fcb = NULL; | 1235 | struct txfcb *fcb = NULL; |
1216 | struct txbd8 *txbdp, *base; | 1236 | struct txbd8 *txbdp, *txbdp_start, *base; |
1217 | u32 lstatus; | 1237 | u32 lstatus; |
1238 | int i; | ||
1239 | u32 bufaddr; | ||
1218 | unsigned long flags; | 1240 | unsigned long flags; |
1241 | unsigned int nr_frags, length; | ||
1242 | |||
1243 | base = priv->tx_bd_base; | ||
1244 | |||
1245 | /* total number of fragments in the SKB */ | ||
1246 | nr_frags = skb_shinfo(skb)->nr_frags; | ||
1247 | |||
1248 | spin_lock_irqsave(&priv->txlock, flags); | ||
1249 | |||
1250 | /* check if there is space to queue this packet */ | ||
1251 | if (nr_frags > priv->num_txbdfree) { | ||
1252 | /* no space, stop the queue */ | ||
1253 | netif_stop_queue(dev); | ||
1254 | dev->stats.tx_fifo_errors++; | ||
1255 | spin_unlock_irqrestore(&priv->txlock, flags); | ||
1256 | return NETDEV_TX_BUSY; | ||
1257 | } | ||
1219 | 1258 | ||
1220 | /* Update transmit stats */ | 1259 | /* Update transmit stats */ |
1221 | dev->stats.tx_bytes += skb->len; | 1260 | dev->stats.tx_bytes += skb->len; |
1222 | 1261 | ||
1223 | /* Lock priv now */ | 1262 | txbdp = txbdp_start = priv->cur_tx; |
1224 | spin_lock_irqsave(&priv->txlock, flags); | ||
1225 | 1263 | ||
1226 | /* Point at the first free tx descriptor */ | 1264 | if (nr_frags == 0) { |
1227 | txbdp = priv->cur_tx; | 1265 | lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); |
1228 | base = priv->tx_bd_base; | 1266 | } else { |
1267 | /* Place the fragment addresses and lengths into the TxBDs */ | ||
1268 | for (i = 0; i < nr_frags; i++) { | ||
1269 | /* Point at the next BD, wrapping as needed */ | ||
1270 | txbdp = next_txbd(txbdp, base, priv->tx_ring_size); | ||
1271 | |||
1272 | length = skb_shinfo(skb)->frags[i].size; | ||
1273 | |||
1274 | lstatus = txbdp->lstatus | length | | ||
1275 | BD_LFLAG(TXBD_READY); | ||
1276 | |||
1277 | /* Handle the last BD specially */ | ||
1278 | if (i == nr_frags - 1) | ||
1279 | lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); | ||
1280 | |||
1281 | bufaddr = dma_map_page(&dev->dev, | ||
1282 | skb_shinfo(skb)->frags[i].page, | ||
1283 | skb_shinfo(skb)->frags[i].page_offset, | ||
1284 | length, | ||
1285 | DMA_TO_DEVICE); | ||
1286 | |||
1287 | /* set the TxBD length and buffer pointer */ | ||
1288 | txbdp->bufPtr = bufaddr; | ||
1289 | txbdp->lstatus = lstatus; | ||
1290 | } | ||
1229 | 1291 | ||
1230 | /* Clear all but the WRAP status flags */ | 1292 | lstatus = txbdp_start->lstatus; |
1231 | lstatus = txbdp->lstatus & BD_LFLAG(TXBD_WRAP); | 1293 | } |
1232 | 1294 | ||
1233 | /* Set up checksumming */ | 1295 | /* Set up checksumming */ |
1234 | if (CHECKSUM_PARTIAL == skb->ip_summed) { | 1296 | if (CHECKSUM_PARTIAL == skb->ip_summed) { |
@@ -1246,48 +1308,45 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1246 | gfar_tx_vlan(skb, fcb); | 1308 | gfar_tx_vlan(skb, fcb); |
1247 | } | 1309 | } |
1248 | 1310 | ||
1249 | /* Set buffer length and pointer */ | 1311 | /* setup the TxBD length and buffer pointer for the first BD */ |
1250 | txbdp->bufPtr = dma_map_single(&dev->dev, skb->data, | ||
1251 | skb->len, DMA_TO_DEVICE); | ||
1252 | |||
1253 | /* Save the skb pointer so we can free it later */ | ||
1254 | priv->tx_skbuff[priv->skb_curtx] = skb; | 1312 | priv->tx_skbuff[priv->skb_curtx] = skb; |
1313 | txbdp_start->bufPtr = dma_map_single(&dev->dev, skb->data, | ||
1314 | skb_headlen(skb), DMA_TO_DEVICE); | ||
1255 | 1315 | ||
1256 | /* Update the current skb pointer (wrapping if this was the last) */ | 1316 | lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); |
1257 | priv->skb_curtx = | ||
1258 | (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); | ||
1259 | |||
1260 | /* Flag the BD as ready, interrupt-causing, last, and in need of CRC */ | ||
1261 | lstatus |= | ||
1262 | BD_LFLAG(TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT) | | ||
1263 | skb->len; | ||
1264 | |||
1265 | dev->trans_start = jiffies; | ||
1266 | 1317 | ||
1267 | /* The powerpc-specific eieio() is used, as wmb() has too strong | 1318 | /* |
1319 | * The powerpc-specific eieio() is used, as wmb() has too strong | ||
1268 | * semantics (it requires synchronization between cacheable and | 1320 | * semantics (it requires synchronization between cacheable and |
1269 | * uncacheable mappings, which eieio doesn't provide and which we | 1321 | * uncacheable mappings, which eieio doesn't provide and which we |
1270 | * don't need), thus requiring a more expensive sync instruction. At | 1322 | * don't need), thus requiring a more expensive sync instruction. At |
1271 | * some point, the set of architecture-independent barrier functions | 1323 | * some point, the set of architecture-independent barrier functions |
1272 | * should be expanded to include weaker barriers. | 1324 | * should be expanded to include weaker barriers. |
1273 | */ | 1325 | */ |
1274 | |||
1275 | eieio(); | 1326 | eieio(); |
1276 | txbdp->lstatus = lstatus; | ||
1277 | 1327 | ||
1278 | txbdp = next_bd(txbdp, base, priv->tx_ring_size); | 1328 | txbdp_start->lstatus = lstatus; |
1329 | |||
1330 | /* Update the current skb pointer to the next entry we will use | ||
1331 | * (wrapping if necessary) */ | ||
1332 | priv->skb_curtx = (priv->skb_curtx + 1) & | ||
1333 | TX_RING_MOD_MASK(priv->tx_ring_size); | ||
1334 | |||
1335 | priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size); | ||
1336 | |||
1337 | /* reduce TxBD free count */ | ||
1338 | priv->num_txbdfree -= (nr_frags + 1); | ||
1339 | |||
1340 | dev->trans_start = jiffies; | ||
1279 | 1341 | ||
1280 | /* If the next BD still needs to be cleaned up, then the bds | 1342 | /* If the next BD still needs to be cleaned up, then the bds |
1281 | are full. We need to tell the kernel to stop sending us stuff. */ | 1343 | are full. We need to tell the kernel to stop sending us stuff. */ |
1282 | if (txbdp == priv->dirty_tx) { | 1344 | if (!priv->num_txbdfree) { |
1283 | netif_stop_queue(dev); | 1345 | netif_stop_queue(dev); |
1284 | 1346 | ||
1285 | dev->stats.tx_fifo_errors++; | 1347 | dev->stats.tx_fifo_errors++; |
1286 | } | 1348 | } |
1287 | 1349 | ||
1288 | /* Update the current txbd to the next one */ | ||
1289 | priv->cur_tx = txbdp; | ||
1290 | |||
1291 | /* Tell the DMA to go go go */ | 1350 | /* Tell the DMA to go go go */ |
1292 | gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); | 1351 | gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); |
1293 | 1352 | ||
@@ -1461,50 +1520,66 @@ static void gfar_timeout(struct net_device *dev) | |||
1461 | /* Interrupt Handler for Transmit complete */ | 1520 | /* Interrupt Handler for Transmit complete */ |
1462 | static int gfar_clean_tx_ring(struct net_device *dev) | 1521 | static int gfar_clean_tx_ring(struct net_device *dev) |
1463 | { | 1522 | { |
1464 | struct txbd8 *bdp, *base; | ||
1465 | struct gfar_private *priv = netdev_priv(dev); | 1523 | struct gfar_private *priv = netdev_priv(dev); |
1524 | struct txbd8 *bdp; | ||
1525 | struct txbd8 *lbdp = NULL; | ||
1526 | struct txbd8 *base = priv->tx_bd_base; | ||
1527 | struct sk_buff *skb; | ||
1528 | int skb_dirtytx; | ||
1529 | int tx_ring_size = priv->tx_ring_size; | ||
1530 | int frags = 0; | ||
1531 | int i; | ||
1466 | int howmany = 0; | 1532 | int howmany = 0; |
1533 | u32 lstatus; | ||
1467 | 1534 | ||
1468 | bdp = priv->dirty_tx; | 1535 | bdp = priv->dirty_tx; |
1469 | base = priv->tx_bd_base; | 1536 | skb_dirtytx = priv->skb_dirtytx; |
1470 | while ((bdp->status & TXBD_READY) == 0) { | ||
1471 | /* If dirty_tx and cur_tx are the same, then either the */ | ||
1472 | /* ring is empty or full now (it could only be full in the beginning, */ | ||
1473 | /* obviously). If it is empty, we are done. */ | ||
1474 | if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) | ||
1475 | break; | ||
1476 | 1537 | ||
1477 | howmany++; | 1538 | while ((skb = priv->tx_skbuff[skb_dirtytx])) { |
1539 | frags = skb_shinfo(skb)->nr_frags; | ||
1540 | lbdp = skip_txbd(bdp, frags, base, tx_ring_size); | ||
1478 | 1541 | ||
1479 | /* Deferred means some collisions occurred during transmit, */ | 1542 | lstatus = lbdp->lstatus; |
1480 | /* but we eventually sent the packet. */ | ||
1481 | if (bdp->status & TXBD_DEF) | ||
1482 | dev->stats.collisions++; | ||
1483 | 1543 | ||
1484 | /* Unmap the DMA memory */ | 1544 | /* Only clean completed frames */ |
1485 | dma_unmap_single(&priv->dev->dev, bdp->bufPtr, | 1545 | if ((lstatus & BD_LFLAG(TXBD_READY)) && |
1486 | bdp->length, DMA_TO_DEVICE); | 1546 | (lstatus & BD_LENGTH_MASK)) |
1547 | break; | ||
1548 | |||
1549 | dma_unmap_single(&dev->dev, | ||
1550 | bdp->bufPtr, | ||
1551 | bdp->length, | ||
1552 | DMA_TO_DEVICE); | ||
1487 | 1553 | ||
1488 | /* Free the sk buffer associated with this TxBD */ | 1554 | bdp->lstatus &= BD_LFLAG(TXBD_WRAP); |
1489 | dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); | 1555 | bdp = next_txbd(bdp, base, tx_ring_size); |
1490 | 1556 | ||
1491 | priv->tx_skbuff[priv->skb_dirtytx] = NULL; | 1557 | for (i = 0; i < frags; i++) { |
1492 | priv->skb_dirtytx = | 1558 | dma_unmap_page(&dev->dev, |
1493 | (priv->skb_dirtytx + | 1559 | bdp->bufPtr, |
1494 | 1) & TX_RING_MOD_MASK(priv->tx_ring_size); | 1560 | bdp->length, |
1561 | DMA_TO_DEVICE); | ||
1562 | bdp->lstatus &= BD_LFLAG(TXBD_WRAP); | ||
1563 | bdp = next_txbd(bdp, base, tx_ring_size); | ||
1564 | } | ||
1495 | 1565 | ||
1496 | /* Clean BD length for empty detection */ | 1566 | dev_kfree_skb_any(skb); |
1497 | bdp->length = 0; | 1567 | priv->tx_skbuff[skb_dirtytx] = NULL; |
1498 | 1568 | ||
1499 | bdp = next_bd(bdp, base, priv->tx_ring_size); | 1569 | skb_dirtytx = (skb_dirtytx + 1) & |
1570 | TX_RING_MOD_MASK(tx_ring_size); | ||
1571 | |||
1572 | howmany++; | ||
1573 | priv->num_txbdfree += frags + 1; | ||
1574 | } | ||
1500 | 1575 | ||
1501 | /* Move dirty_tx to be the next bd */ | 1576 | /* If we freed a buffer, we can restart transmission, if necessary */ |
1502 | priv->dirty_tx = bdp; | 1577 | if (netif_queue_stopped(dev) && priv->num_txbdfree) |
1578 | netif_wake_queue(dev); | ||
1503 | 1579 | ||
1504 | /* We freed a buffer, so now we can restart transmission */ | 1580 | /* Update dirty indicators */ |
1505 | if (netif_queue_stopped(dev)) | 1581 | priv->skb_dirtytx = skb_dirtytx; |
1506 | netif_wake_queue(dev); | 1582 | priv->dirty_tx = bdp; |
1507 | } /* while ((bdp->status & TXBD_READY) == 0) */ | ||
1508 | 1583 | ||
1509 | dev->stats.tx_packets += howmany; | 1584 | dev->stats.tx_packets += howmany; |
1510 | 1585 | ||
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 9c8974dc8dd5..7ef3cc5cabe9 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h | |||
@@ -728,6 +728,7 @@ struct gfar_private { | |||
728 | struct txbd8 *dirty_tx; /* First buffer in line | 728 | struct txbd8 *dirty_tx; /* First buffer in line |
729 | to be transmitted */ | 729 | to be transmitted */ |
730 | unsigned int tx_ring_size; | 730 | unsigned int tx_ring_size; |
731 | unsigned int num_txbdfree; /* number of TxBDs free */ | ||
731 | 732 | ||
732 | /* RX Locked fields */ | 733 | /* RX Locked fields */ |
733 | spinlock_t rxlock; | 734 | spinlock_t rxlock; |
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 3021057d54ae..59b3b5d98efe 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c | |||
@@ -475,6 +475,7 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva | |||
475 | /* Change the size */ | 475 | /* Change the size */ |
476 | priv->rx_ring_size = rvals->rx_pending; | 476 | priv->rx_ring_size = rvals->rx_pending; |
477 | priv->tx_ring_size = rvals->tx_pending; | 477 | priv->tx_ring_size = rvals->tx_pending; |
478 | priv->num_txbdfree = priv->tx_ring_size; | ||
478 | 479 | ||
479 | /* Rebuild the rings with the new size */ | 480 | /* Rebuild the rings with the new size */ |
480 | if (dev->flags & IFF_UP) { | 481 | if (dev->flags & IFF_UP) { |
@@ -623,6 +624,7 @@ const struct ethtool_ops gfar_ethtool_ops = { | |||
623 | .get_tx_csum = gfar_get_tx_csum, | 624 | .get_tx_csum = gfar_get_tx_csum, |
624 | .set_rx_csum = gfar_set_rx_csum, | 625 | .set_rx_csum = gfar_set_rx_csum, |
625 | .set_tx_csum = gfar_set_tx_csum, | 626 | .set_tx_csum = gfar_set_tx_csum, |
627 | .set_sg = ethtool_op_set_sg, | ||
626 | .get_msglevel = gfar_get_msglevel, | 628 | .get_msglevel = gfar_get_msglevel, |
627 | .set_msglevel = gfar_set_msglevel, | 629 | .set_msglevel = gfar_set_msglevel, |
628 | #ifdef CONFIG_PM | 630 | #ifdef CONFIG_PM |