aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/gianfar.c
diff options
context:
space:
mode:
authorManfred Rudigier <Manfred.Rudigier@omicron.at>2010-04-08 19:10:03 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-13 04:41:31 -0400
commitcc772ab7cdcaa24d1fae332d92a1602788644f7a (patch)
treeefbcb9bf8c1c9214f612d2044321a30ada230255 /drivers/net/gianfar.c
parente44171f115de3dedf34064646206deb91549865f (diff)
gianfar: Add hardware RX timestamping support
The device is configured to insert hardware timestamps into all received packets. The RX timestamps are extracted from the padding alingment bytes during the clean_rx_ring operation and copied into the skb_shared_hwtstamps struct of the skb. This extraction only happens if the rx_filter was set to something else than HWTSTAMP_FILTER_NONE with the SIOCSHWTSTAMP ioctl command. Hardware timestamping is only supported for eTSEC devices. To indicate device support the new FSL_GIANFAR_DEV_HAS_TIMER flag was introduced. Signed-off-by: Manfred Rudigier <manfred.rudigier@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r--drivers/net/gianfar.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 5175233f11f2..d102484c4b36 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -82,6 +82,7 @@
82#include <linux/tcp.h> 82#include <linux/tcp.h>
83#include <linux/udp.h> 83#include <linux/udp.h>
84#include <linux/in.h> 84#include <linux/in.h>
85#include <linux/net_tstamp.h>
85 86
86#include <asm/io.h> 87#include <asm/io.h>
87#include <asm/irq.h> 88#include <asm/irq.h>
@@ -377,6 +378,13 @@ static void gfar_init_mac(struct net_device *ndev)
377 rctrl |= RCTRL_PADDING(priv->padding); 378 rctrl |= RCTRL_PADDING(priv->padding);
378 } 379 }
379 380
381 /* Insert receive time stamps into padding alignment bytes */
382 if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) {
383 rctrl &= ~RCTRL_PAL_MASK;
384 rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8);
385 priv->padding = 8;
386 }
387
380 /* keep vlan related bits if it's enabled */ 388 /* keep vlan related bits if it's enabled */
381 if (priv->vlgrp) { 389 if (priv->vlgrp) {
382 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; 390 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
@@ -501,7 +509,8 @@ void unlock_tx_qs(struct gfar_private *priv)
501/* Returns 1 if incoming frames use an FCB */ 509/* Returns 1 if incoming frames use an FCB */
502static inline int gfar_uses_fcb(struct gfar_private *priv) 510static inline int gfar_uses_fcb(struct gfar_private *priv)
503{ 511{
504 return priv->vlgrp || priv->rx_csum_enable; 512 return priv->vlgrp || priv->rx_csum_enable ||
513 (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
505} 514}
506 515
507static void free_tx_pointers(struct gfar_private *priv) 516static void free_tx_pointers(struct gfar_private *priv)
@@ -742,7 +751,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
742 FSL_GIANFAR_DEV_HAS_CSUM | 751 FSL_GIANFAR_DEV_HAS_CSUM |
743 FSL_GIANFAR_DEV_HAS_VLAN | 752 FSL_GIANFAR_DEV_HAS_VLAN |
744 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | 753 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
745 FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; 754 FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
755 FSL_GIANFAR_DEV_HAS_TIMER;
746 756
747 ctype = of_get_property(np, "phy-connection-type", NULL); 757 ctype = of_get_property(np, "phy-connection-type", NULL);
748 758
@@ -772,6 +782,38 @@ err_grp_init:
772 return err; 782 return err;
773} 783}
774 784
785static int gfar_hwtstamp_ioctl(struct net_device *netdev,
786 struct ifreq *ifr, int cmd)
787{
788 struct hwtstamp_config config;
789 struct gfar_private *priv = netdev_priv(netdev);
790
791 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
792 return -EFAULT;
793
794 /* reserved for future extensions */
795 if (config.flags)
796 return -EINVAL;
797
798 if (config.tx_type)
799 return -ERANGE;
800
801 switch (config.rx_filter) {
802 case HWTSTAMP_FILTER_NONE:
803 priv->hwts_rx_en = 0;
804 break;
805 default:
806 if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
807 return -ERANGE;
808 priv->hwts_rx_en = 1;
809 config.rx_filter = HWTSTAMP_FILTER_ALL;
810 break;
811 }
812
813 return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
814 -EFAULT : 0;
815}
816
775/* Ioctl MII Interface */ 817/* Ioctl MII Interface */
776static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 818static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
777{ 819{
@@ -780,6 +822,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
780 if (!netif_running(dev)) 822 if (!netif_running(dev))
781 return -EINVAL; 823 return -EINVAL;
782 824
825 if (cmd == SIOCSHWTSTAMP)
826 return gfar_hwtstamp_ioctl(dev, rq, cmd);
827
783 if (!priv->phydev) 828 if (!priv->phydev)
784 return -ENODEV; 829 return -ENODEV;
785 830
@@ -982,7 +1027,8 @@ static int gfar_probe(struct of_device *ofdev,
982 else 1027 else
983 priv->padding = 0; 1028 priv->padding = 0;
984 1029
985 if (dev->features & NETIF_F_IP_CSUM) 1030 if (dev->features & NETIF_F_IP_CSUM ||
1031 priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
986 dev->hard_header_len += GMAC_FCB_LEN; 1032 dev->hard_header_len += GMAC_FCB_LEN;
987 1033
988 /* Program the isrg regs only if number of grps > 1 */ 1034 /* Program the isrg regs only if number of grps > 1 */
@@ -2474,6 +2520,17 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
2474 skb_pull(skb, amount_pull); 2520 skb_pull(skb, amount_pull);
2475 } 2521 }
2476 2522
2523 /* Get receive timestamp from the skb */
2524 if (priv->hwts_rx_en) {
2525 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
2526 u64 *ns = (u64 *) skb->data;
2527 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
2528 shhwtstamps->hwtstamp = ns_to_ktime(*ns);
2529 }
2530
2531 if (priv->padding)
2532 skb_pull(skb, priv->padding);
2533
2477 if (priv->rx_csum_enable) 2534 if (priv->rx_csum_enable)
2478 gfar_rx_checksum(skb, fcb); 2535 gfar_rx_checksum(skb, fcb);
2479 2536
@@ -2510,8 +2567,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
2510 bdp = rx_queue->cur_rx; 2567 bdp = rx_queue->cur_rx;
2511 base = rx_queue->rx_bd_base; 2568 base = rx_queue->rx_bd_base;
2512 2569
2513 amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) + 2570 amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0);
2514 priv->padding;
2515 2571
2516 while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { 2572 while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
2517 struct sk_buff *newskb; 2573 struct sk_buff *newskb;