diff options
-rw-r--r-- | drivers/net/ethernet/freescale/fec.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 100 |
2 files changed, 106 insertions, 4 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index eb4372962839..d44f65bac1d4 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h | |||
@@ -52,6 +52,7 @@ | |||
52 | #define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */ | 52 | #define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */ |
53 | #define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */ | 53 | #define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */ |
54 | #define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */ | 54 | #define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */ |
55 | #define FEC_RACC 0x1C4 /* Receive Accelerator function */ | ||
55 | #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ | 56 | #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ |
56 | #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ | 57 | #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ |
57 | 58 | ||
@@ -164,9 +165,11 @@ struct bufdesc_ex { | |||
164 | #define BD_ENET_TX_CSL ((ushort)0x0001) | 165 | #define BD_ENET_TX_CSL ((ushort)0x0001) |
165 | #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ | 166 | #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ |
166 | 167 | ||
167 | /*enhanced buffer desciptor control/status used by Ethernet transmit*/ | 168 | /*enhanced buffer descriptor control/status used by Ethernet transmit*/ |
168 | #define BD_ENET_TX_INT 0x40000000 | 169 | #define BD_ENET_TX_INT 0x40000000 |
169 | #define BD_ENET_TX_TS 0x20000000 | 170 | #define BD_ENET_TX_TS 0x20000000 |
171 | #define BD_ENET_TX_PINS 0x10000000 | ||
172 | #define BD_ENET_TX_IINS 0x08000000 | ||
170 | 173 | ||
171 | 174 | ||
172 | /* This device has up to three irqs on some platforms */ | 175 | /* This device has up to three irqs on some platforms */ |
@@ -190,6 +193,10 @@ struct bufdesc_ex { | |||
190 | 193 | ||
191 | #define BD_ENET_RX_INT 0x00800000 | 194 | #define BD_ENET_RX_INT 0x00800000 |
192 | #define BD_ENET_RX_PTP ((ushort)0x0400) | 195 | #define BD_ENET_RX_PTP ((ushort)0x0400) |
196 | #define BD_ENET_RX_ICE 0x00000020 | ||
197 | #define BD_ENET_RX_PCR 0x00000010 | ||
198 | #define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) | ||
199 | #define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) | ||
193 | 200 | ||
194 | /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and | 201 | /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and |
195 | * tx_bd_base always point to the base of the buffer descriptors. The | 202 | * tx_bd_base always point to the base of the buffer descriptors. The |
@@ -247,6 +254,7 @@ struct fec_enet_private { | |||
247 | int pause_flag; | 254 | int pause_flag; |
248 | 255 | ||
249 | struct napi_struct napi; | 256 | struct napi_struct napi; |
257 | int csum_flags; | ||
250 | 258 | ||
251 | struct ptp_clock *ptp_clock; | 259 | struct ptp_clock *ptp_clock; |
252 | struct ptp_clock_info ptp_caps; | 260 | struct ptp_clock_info ptp_caps; |
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 | ||
250 | static int | ||
251 | fec_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 | |||
239 | static netdev_tx_t | 265 | static netdev_tx_t |
240 | fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 266 | fec_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 | ||
1676 | static 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 | |||
1617 | static const struct net_device_ops fec_netdev_ops = { | 1703 | static 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; |