aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDai Haruki <dai.haruki@freescale.com>2008-12-17 19:51:04 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-17 19:51:04 -0500
commit4669bc907488f5a3ee399ced132deb6165e489a3 (patch)
tree916d6d5ecca6f989aa02791fbbcb224e0c6c7ecd
parent8882d9a60028a9937e9c5652cfb80d4399ce5242 (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>
-rw-r--r--drivers/net/gianfar.c217
-rw-r--r--drivers/net/gianfar.h1
-rw-r--r--drivers/net/gianfar_ethtool.c2
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
1216static 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
1224static 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 */
1212static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) 1232static 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 */
1462static int gfar_clean_tx_ring(struct net_device *dev) 1521static 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