Commit 4669bc907488f5a3ee399ced132deb6165e489a3
Committed by
David S. Miller
1 parent
8882d9a600
Exists in
master
and in
7 other branches
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>
Showing 3 changed files with 149 additions and 71 deletions Side-by-side Diff
drivers/net/gianfar.c
... | ... | @@ -368,7 +368,7 @@ |
368 | 368 | |
369 | 369 | if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { |
370 | 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 | 372 | } else |
373 | 373 | priv->rx_csum_enable = 0; |
374 | 374 | |
... | ... | @@ -426,6 +426,7 @@ |
426 | 426 | priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; |
427 | 427 | priv->tx_ring_size = DEFAULT_TX_RING_SIZE; |
428 | 428 | priv->rx_ring_size = DEFAULT_RX_RING_SIZE; |
429 | + priv->num_txbdfree = DEFAULT_TX_RING_SIZE; | |
429 | 430 | |
430 | 431 | priv->txcoalescing = DEFAULT_TX_COALESCE; |
431 | 432 | priv->txic = DEFAULT_TXIC; |
432 | 433 | |
433 | 434 | |
434 | 435 | |
435 | 436 | |
... | ... | @@ -819,22 +820,26 @@ |
819 | 820 | { |
820 | 821 | struct rxbd8 *rxbdp; |
821 | 822 | struct txbd8 *txbdp; |
822 | - int i; | |
823 | + int i, j; | |
823 | 824 | |
824 | 825 | /* Go through all the buffer descriptors and free their data buffers */ |
825 | 826 | txbdp = priv->tx_bd_base; |
826 | 827 | |
827 | 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]) { | |
830 | - dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, | |
831 | - txbdp->length, | |
832 | - DMA_TO_DEVICE); | |
833 | - dev_kfree_skb_any(priv->tx_skbuff[i]); | |
834 | - priv->tx_skbuff[i] = NULL; | |
832 | + dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, | |
833 | + txbdp->length, DMA_TO_DEVICE); | |
834 | + txbdp->lstatus = 0; | |
835 | + for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) { | |
836 | + txbdp++; | |
837 | + dma_unmap_page(&priv->dev->dev, txbdp->bufPtr, | |
838 | + txbdp->length, DMA_TO_DEVICE); | |
835 | 839 | } |
836 | - | |
837 | 840 | txbdp++; |
841 | + dev_kfree_skb_any(priv->tx_skbuff[i]); | |
842 | + priv->tx_skbuff[i] = NULL; | |
838 | 843 | } |
839 | 844 | |
840 | 845 | kfree(priv->tx_skbuff); |
... | ... | @@ -967,6 +972,7 @@ |
967 | 972 | priv->rx_skbuff[i] = NULL; |
968 | 973 | |
969 | 974 | /* Initialize some variables in our dev structure */ |
975 | + priv->num_txbdfree = priv->tx_ring_size; | |
970 | 976 | priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; |
971 | 977 | priv->cur_rx = priv->rx_bd_base; |
972 | 978 | priv->skb_curtx = priv->skb_dirtytx = 0; |
973 | 979 | |
974 | 980 | |
975 | 981 | |
976 | 982 | |
977 | 983 | |
978 | 984 | |
979 | 985 | |
980 | 986 | |
... | ... | @@ -1207,29 +1213,85 @@ |
1207 | 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 | 1230 | /* This is called by the kernel when a frame is ready for transmission. */ |
1211 | 1231 | /* It is pointed to by the dev->hard_start_xmit function pointer */ |
1212 | 1232 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) |
1213 | 1233 | { |
1214 | 1234 | struct gfar_private *priv = netdev_priv(dev); |
1215 | 1235 | struct txfcb *fcb = NULL; |
1216 | - struct txbd8 *txbdp, *base; | |
1236 | + struct txbd8 *txbdp, *txbdp_start, *base; | |
1217 | 1237 | u32 lstatus; |
1238 | + int i; | |
1239 | + u32 bufaddr; | |
1218 | 1240 | unsigned long flags; |
1241 | + unsigned int nr_frags, length; | |
1219 | 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 | + } | |
1258 | + | |
1220 | 1259 | /* Update transmit stats */ |
1221 | 1260 | dev->stats.tx_bytes += skb->len; |
1222 | 1261 | |
1223 | - /* Lock priv now */ | |
1224 | - spin_lock_irqsave(&priv->txlock, flags); | |
1262 | + txbdp = txbdp_start = priv->cur_tx; | |
1225 | 1263 | |
1226 | - /* Point at the first free tx descriptor */ | |
1227 | - txbdp = priv->cur_tx; | |
1228 | - base = priv->tx_bd_base; | |
1264 | + if (nr_frags == 0) { | |
1265 | + lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); | |
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); | |
1229 | 1271 | |
1230 | - /* Clear all but the WRAP status flags */ | |
1231 | - lstatus = txbdp->lstatus & BD_LFLAG(TXBD_WRAP); | |
1272 | + length = skb_shinfo(skb)->frags[i].size; | |
1232 | 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 | + } | |
1291 | + | |
1292 | + lstatus = txbdp_start->lstatus; | |
1293 | + } | |
1294 | + | |
1233 | 1295 | /* Set up checksumming */ |
1234 | 1296 | if (CHECKSUM_PARTIAL == skb->ip_summed) { |
1235 | 1297 | fcb = gfar_add_fcb(skb); |
1236 | 1298 | |
1237 | 1299 | |
1238 | 1300 | |
1239 | 1301 | |
1240 | 1302 | |
1241 | 1303 | |
1242 | 1304 | |
1243 | 1305 | |
1244 | 1306 | |
... | ... | @@ -1246,48 +1308,45 @@ |
1246 | 1308 | gfar_tx_vlan(skb, fcb); |
1247 | 1309 | } |
1248 | 1310 | |
1249 | - /* Set buffer length and pointer */ | |
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 */ | |
1311 | + /* setup the TxBD length and buffer pointer for the first BD */ | |
1254 | 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) */ | |
1257 | - priv->skb_curtx = | |
1258 | - (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); | |
1316 | + lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); | |
1259 | 1317 | |
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 | - | |
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 | 1320 | * semantics (it requires synchronization between cacheable and |
1269 | 1321 | * uncacheable mappings, which eieio doesn't provide and which we |
1270 | 1322 | * don't need), thus requiring a more expensive sync instruction. At |
1271 | 1323 | * some point, the set of architecture-independent barrier functions |
1272 | 1324 | * should be expanded to include weaker barriers. |
1273 | 1325 | */ |
1274 | - | |
1275 | 1326 | eieio(); |
1276 | - txbdp->lstatus = lstatus; | |
1277 | 1327 | |
1278 | - txbdp = next_bd(txbdp, base, priv->tx_ring_size); | |
1328 | + txbdp_start->lstatus = lstatus; | |
1279 | 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; | |
1341 | + | |
1280 | 1342 | /* If the next BD still needs to be cleaned up, then the bds |
1281 | 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 | 1345 | netif_stop_queue(dev); |
1284 | 1346 | |
1285 | 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 | 1350 | /* Tell the DMA to go go go */ |
1292 | 1351 | gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); |
1293 | 1352 | |
1294 | 1353 | |
1295 | 1354 | |
1296 | 1355 | |
1297 | 1356 | |
1298 | 1357 | |
1299 | 1358 | |
1300 | 1359 | |
1301 | 1360 | |
1302 | 1361 | |
1303 | 1362 | |
1304 | 1363 | |
1305 | 1364 | |
... | ... | @@ -1461,50 +1520,66 @@ |
1461 | 1520 | /* Interrupt Handler for Transmit complete */ |
1462 | 1521 | static int gfar_clean_tx_ring(struct net_device *dev) |
1463 | 1522 | { |
1464 | - struct txbd8 *bdp, *base; | |
1465 | 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 | 1532 | int howmany = 0; |
1533 | + u32 lstatus; | |
1467 | 1534 | |
1468 | 1535 | bdp = priv->dirty_tx; |
1469 | - base = priv->tx_bd_base; | |
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; | |
1536 | + skb_dirtytx = priv->skb_dirtytx; | |
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, */ | |
1480 | - /* but we eventually sent the packet. */ | |
1481 | - if (bdp->status & TXBD_DEF) | |
1482 | - dev->stats.collisions++; | |
1542 | + lstatus = lbdp->lstatus; | |
1483 | 1543 | |
1484 | - /* Unmap the DMA memory */ | |
1485 | - dma_unmap_single(&priv->dev->dev, bdp->bufPtr, | |
1486 | - bdp->length, DMA_TO_DEVICE); | |
1544 | + /* Only clean completed frames */ | |
1545 | + if ((lstatus & BD_LFLAG(TXBD_READY)) && | |
1546 | + (lstatus & BD_LENGTH_MASK)) | |
1547 | + break; | |
1487 | 1548 | |
1488 | - /* Free the sk buffer associated with this TxBD */ | |
1489 | - dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); | |
1549 | + dma_unmap_single(&dev->dev, | |
1550 | + bdp->bufPtr, | |
1551 | + bdp->length, | |
1552 | + DMA_TO_DEVICE); | |
1490 | 1553 | |
1491 | - priv->tx_skbuff[priv->skb_dirtytx] = NULL; | |
1492 | - priv->skb_dirtytx = | |
1493 | - (priv->skb_dirtytx + | |
1494 | - 1) & TX_RING_MOD_MASK(priv->tx_ring_size); | |
1554 | + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); | |
1555 | + bdp = next_txbd(bdp, base, tx_ring_size); | |
1495 | 1556 | |
1496 | - /* Clean BD length for empty detection */ | |
1497 | - bdp->length = 0; | |
1557 | + for (i = 0; i < frags; i++) { | |
1558 | + dma_unmap_page(&dev->dev, | |
1559 | + bdp->bufPtr, | |
1560 | + bdp->length, | |
1561 | + DMA_TO_DEVICE); | |
1562 | + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); | |
1563 | + bdp = next_txbd(bdp, base, tx_ring_size); | |
1564 | + } | |
1498 | 1565 | |
1499 | - bdp = next_bd(bdp, base, priv->tx_ring_size); | |
1566 | + dev_kfree_skb_any(skb); | |
1567 | + priv->tx_skbuff[skb_dirtytx] = NULL; | |
1500 | 1568 | |
1501 | - /* Move dirty_tx to be the next bd */ | |
1502 | - priv->dirty_tx = bdp; | |
1569 | + skb_dirtytx = (skb_dirtytx + 1) & | |
1570 | + TX_RING_MOD_MASK(tx_ring_size); | |
1503 | 1571 | |
1504 | - /* We freed a buffer, so now we can restart transmission */ | |
1505 | - if (netif_queue_stopped(dev)) | |
1506 | - netif_wake_queue(dev); | |
1507 | - } /* while ((bdp->status & TXBD_READY) == 0) */ | |
1572 | + howmany++; | |
1573 | + priv->num_txbdfree += frags + 1; | |
1574 | + } | |
1575 | + | |
1576 | + /* If we freed a buffer, we can restart transmission, if necessary */ | |
1577 | + if (netif_queue_stopped(dev) && priv->num_txbdfree) | |
1578 | + netif_wake_queue(dev); | |
1579 | + | |
1580 | + /* Update dirty indicators */ | |
1581 | + priv->skb_dirtytx = skb_dirtytx; | |
1582 | + priv->dirty_tx = bdp; | |
1508 | 1583 | |
1509 | 1584 | dev->stats.tx_packets += howmany; |
1510 | 1585 |
drivers/net/gianfar.h
drivers/net/gianfar_ethtool.c
... | ... | @@ -475,6 +475,7 @@ |
475 | 475 | /* Change the size */ |
476 | 476 | priv->rx_ring_size = rvals->rx_pending; |
477 | 477 | priv->tx_ring_size = rvals->tx_pending; |
478 | + priv->num_txbdfree = priv->tx_ring_size; | |
478 | 479 | |
479 | 480 | /* Rebuild the rings with the new size */ |
480 | 481 | if (dev->flags & IFF_UP) { |
... | ... | @@ -623,6 +624,7 @@ |
623 | 624 | .get_tx_csum = gfar_get_tx_csum, |
624 | 625 | .set_rx_csum = gfar_set_rx_csum, |
625 | 626 | .set_tx_csum = gfar_set_tx_csum, |
627 | + .set_sg = ethtool_op_set_sg, | |
626 | 628 | .get_msglevel = gfar_get_msglevel, |
627 | 629 | .set_msglevel = gfar_set_msglevel, |
628 | 630 | #ifdef CONFIG_PM |