aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale/fec_main.c
diff options
context:
space:
mode:
authorJim Baxter <jim_baxter@mentor.com>2013-04-19 04:10:49 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-25 03:58:26 -0400
commit4c09eed9dc422e980fabdb25434ef68e599b704c (patch)
treea00da8b76aed9cc916649eafdaf9504e27038b03 /drivers/net/ethernet/freescale/fec_main.c
parentcf62cb72d63944f4dcc7376efd84959afc9366cb (diff)
net: fec: Enable imx6 enet checksum acceleration.
Enables hardware generation of IP header and protocol specific checksums for transmitted packets. Enabled hardware discarding of received packets with invalid IP header or protocol specific checksums. The feature is enabled by default but can be enabled/disabled by ethtool. Signed-off-by: Fugang Duan <B38611@freescale.com> Signed-off-by: Jim Baxter <jim_baxter@mentor.com> Reviewed-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c100
1 files changed, 97 insertions, 3 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2451ab1b5a83..b9748f14ea78 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -34,6 +34,12 @@
34#include <linux/netdevice.h> 34#include <linux/netdevice.h>
35#include <linux/etherdevice.h> 35#include <linux/etherdevice.h>
36#include <linux/skbuff.h> 36#include <linux/skbuff.h>
37#include <linux/in.h>
38#include <linux/ip.h>
39#include <net/ip.h>
40#include <linux/tcp.h>
41#include <linux/udp.h>
42#include <linux/icmp.h>
37#include <linux/spinlock.h> 43#include <linux/spinlock.h>
38#include <linux/workqueue.h> 44#include <linux/workqueue.h>
39#include <linux/bitops.h> 45#include <linux/bitops.h>
@@ -176,6 +182,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
176#define PKT_MINBUF_SIZE 64 182#define PKT_MINBUF_SIZE 64
177#define PKT_MAXBLR_SIZE 1520 183#define PKT_MAXBLR_SIZE 1520
178 184
185/* FEC receive acceleration */
186#define FEC_RACC_IPDIS (1 << 1)
187#define FEC_RACC_PRODIS (1 << 2)
188#define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS)
189
179/* 190/*
180 * The 5270/5271/5280/5282/532x RX control register also contains maximum frame 191 * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
181 * size bits. Other FEC hardware does not, so we need to take that into 192 * size bits. Other FEC hardware does not, so we need to take that into
@@ -236,6 +247,21 @@ static void *swap_buffer(void *bufaddr, int len)
236 return bufaddr; 247 return bufaddr;
237} 248}
238 249
250static int
251fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
252{
253 /* Only run for packets requiring a checksum. */
254 if (skb->ip_summed != CHECKSUM_PARTIAL)
255 return 0;
256
257 if (unlikely(skb_cow_head(skb, 0)))
258 return -1;
259
260 *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0;
261
262 return 0;
263}
264
239static netdev_tx_t 265static netdev_tx_t
240fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) 266fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
241{ 267{
@@ -248,7 +274,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
248 unsigned int index; 274 unsigned int index;
249 275
250 if (!fep->link) { 276 if (!fep->link) {
251 /* Link is down or autonegotiation is in progress. */ 277 /* Link is down or auto-negotiation is in progress. */
252 return NETDEV_TX_BUSY; 278 return NETDEV_TX_BUSY;
253 } 279 }
254 280
@@ -265,6 +291,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
265 return NETDEV_TX_BUSY; 291 return NETDEV_TX_BUSY;
266 } 292 }
267 293
294 /* Protocol checksum off-load for TCP and UDP. */
295 if (fec_enet_clear_csum(skb, ndev)) {
296 kfree_skb(skb);
297 return NETDEV_TX_OK;
298 }
299
268 /* Clear all of the status flags */ 300 /* Clear all of the status flags */
269 status &= ~BD_ENET_TX_STATS; 301 status &= ~BD_ENET_TX_STATS;
270 302
@@ -321,8 +353,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
321 ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); 353 ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
322 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 354 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
323 } else { 355 } else {
324
325 ebdp->cbd_esc = BD_ENET_TX_INT; 356 ebdp->cbd_esc = BD_ENET_TX_INT;
357
358 /* Enable protocol checksum flags
359 * We do not bother with the IP Checksum bits as they
360 * are done by the kernel
361 */
362 if (skb->ip_summed == CHECKSUM_PARTIAL)
363 ebdp->cbd_esc |= BD_ENET_TX_PINS;
326 } 364 }
327 } 365 }
328 /* If this was the last BD in the ring, start at the beginning again. */ 366 /* If this was the last BD in the ring, start at the beginning again. */
@@ -402,6 +440,7 @@ fec_restart(struct net_device *ndev, int duplex)
402 const struct platform_device_id *id_entry = 440 const struct platform_device_id *id_entry =
403 platform_get_device_id(fep->pdev); 441 platform_get_device_id(fep->pdev);
404 int i; 442 int i;
443 u32 val;
405 u32 temp_mac[2]; 444 u32 temp_mac[2];
406 u32 rcntl = OPT_FRAME_SIZE | 0x04; 445 u32 rcntl = OPT_FRAME_SIZE | 0x04;
407 u32 ecntl = 0x2; /* ETHEREN */ 446 u32 ecntl = 0x2; /* ETHEREN */
@@ -468,6 +507,14 @@ fec_restart(struct net_device *ndev, int duplex)
468 /* Set MII speed */ 507 /* Set MII speed */
469 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 508 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
470 509
510 /* set RX checksum */
511 val = readl(fep->hwp + FEC_RACC);
512 if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
513 val |= FEC_RACC_OPTIONS;
514 else
515 val &= ~FEC_RACC_OPTIONS;
516 writel(val, fep->hwp + FEC_RACC);
517
471 /* 518 /*
472 * The phy interface and speed need to get configured 519 * The phy interface and speed need to get configured
473 * differently on enet-mac. 520 * differently on enet-mac.
@@ -525,7 +572,7 @@ fec_restart(struct net_device *ndev, int duplex)
525 fep->phy_dev && fep->phy_dev->pause)) { 572 fep->phy_dev && fep->phy_dev->pause)) {
526 rcntl |= FEC_ENET_FCE; 573 rcntl |= FEC_ENET_FCE;
527 574
528 /* set FIFO thresh hold parameter to reduce overrun */ 575 /* set FIFO threshold parameter to reduce overrun */
529 writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); 576 writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
530 writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL); 577 writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
531 writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM); 578 writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
@@ -813,6 +860,18 @@ fec_enet_rx(struct net_device *ndev, int budget)
813 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 860 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
814 } 861 }
815 862
863 if (fep->bufdesc_ex &&
864 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
865 struct bufdesc_ex *ebdp =
866 (struct bufdesc_ex *)bdp;
867 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
868 /* don't check it */
869 skb->ip_summed = CHECKSUM_UNNECESSARY;
870 } else {
871 skb_checksum_none_assert(skb);
872 }
873 }
874
816 if (!skb_defer_rx_timestamp(skb)) 875 if (!skb_defer_rx_timestamp(skb))
817 napi_gro_receive(&fep->napi, skb); 876 napi_gro_receive(&fep->napi, skb);
818 } 877 }
@@ -1614,6 +1673,33 @@ static void fec_poll_controller(struct net_device *dev)
1614} 1673}
1615#endif 1674#endif
1616 1675
1676static int fec_set_features(struct net_device *netdev,
1677 netdev_features_t features)
1678{
1679 struct fec_enet_private *fep = netdev_priv(netdev);
1680 netdev_features_t changed = features ^ netdev->features;
1681
1682 netdev->features = features;
1683
1684 /* Receive checksum has been changed */
1685 if (changed & NETIF_F_RXCSUM) {
1686 if (features & NETIF_F_RXCSUM)
1687 fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
1688 else
1689 fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
1690
1691 if (netif_running(netdev)) {
1692 fec_stop(netdev);
1693 fec_restart(netdev, fep->phy_dev->duplex);
1694 netif_wake_queue(netdev);
1695 } else {
1696 fec_restart(netdev, fep->phy_dev->duplex);
1697 }
1698 }
1699
1700 return 0;
1701}
1702
1617static const struct net_device_ops fec_netdev_ops = { 1703static const struct net_device_ops fec_netdev_ops = {
1618 .ndo_open = fec_enet_open, 1704 .ndo_open = fec_enet_open,
1619 .ndo_stop = fec_enet_close, 1705 .ndo_stop = fec_enet_close,
@@ -1627,6 +1713,7 @@ static const struct net_device_ops fec_netdev_ops = {
1627#ifdef CONFIG_NET_POLL_CONTROLLER 1713#ifdef CONFIG_NET_POLL_CONTROLLER
1628 .ndo_poll_controller = fec_poll_controller, 1714 .ndo_poll_controller = fec_poll_controller,
1629#endif 1715#endif
1716 .ndo_set_features = fec_set_features,
1630}; 1717};
1631 1718
1632 /* 1719 /*
@@ -1668,6 +1755,13 @@ static int fec_enet_init(struct net_device *ndev)
1668 writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); 1755 writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
1669 netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); 1756 netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
1670 1757
1758 /* enable hw accelerator */
1759 ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
1760 | NETIF_F_RXCSUM);
1761 ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
1762 | NETIF_F_RXCSUM);
1763 fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
1764
1671 fec_restart(ndev, 0); 1765 fec_restart(ndev, 0);
1672 1766
1673 return 0; 1767 return 0;