[PATCH] gianfar: Fix setup of RX time stamping
Previously the RCTRL_TS_ENABLE bit was set unconditionally. However, if the RCTRL_TS_ENABLE is set without TMR_CTRL[TE], the driver does not work properly on some boards (Anton had problems with the MPC8313ERDB and MPC8568EMDS). With this patch the bit will only be set if requested from user space with the SIOCSHWTSTAMP ioctl command, meaning that time stamping is disabled during normal operation. Users who are not interested in time stamps will not experience problems with buggy CPU revisions or performance drops any more. The setting of TMR_CTRL[TE] is still up to the user. This is considered safe because users wanting HW timestamps must initialize the eTSEC clock first anyway, e.g. with the recently submitted PTP clock driver. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 21 + 1 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 46c69cd..227b628 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -381,10 +381,14 @@ static void gfar_init_mac(struct net_device *ndev) /* Insert receive time stamps into padding alignment bytes */ if (priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER) { rctrl = ~RCTRL_PAL_MASK; - rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8); + rctrl |= RCTRL_PADDING(8); priv-padding = 8; } + /* Enable HW time stamping if requested from user space */ + if (priv-hwts_rx_en) + rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; + /* keep vlan related bits if it's enabled */ if (priv-vlgrp) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; @@ -747,7 +751,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | + FSL_GIANFAR_DEV_HAS_TIMER; ctype = of_get_property(np, phy-connection-type, NULL); @@ -805,12 +810,20 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - priv-hwts_rx_en = 0; + if (priv-hwts_rx_en) { + stop_gfar(netdev); + priv-hwts_rx_en = 0; + startup_gfar(netdev); + } break; default: if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; - priv-hwts_rx_en = 1; + if (!priv-hwts_rx_en) { + stop_gfar(netdev); + priv-hwts_rx_en = 1; + startup_gfar(netdev); + } config.rx_filter = HWTSTAMP_FILTER_ALL; break; } -- 1.6.3.3 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 net-next 0/2] timestamping support for gianfar
On 2010-04-07 Manfred Rudigier wrote: this patch series adds support for hardware time stamping to gianfar. It uses the new SO_TIMESTAMPING infrastructure to deliver raw hardware timestamps to user space applications. Freescale CPUs with an eTSEC are able to time stamp all incoming network packets and can also time stamp transmit packets when instructed. The time stamps are generated by the eTSEC timer clock module which is running either from an external oscillator or internal clock. The submitted patches do not initialize the timer clock module since the oscillator frequency might be different from board to board. Thus the user must configure the timer clock module by hand at the moment - otherwise no time stamps will be reported. Below is a simple example code which shows how to configure the timer clock module on the P2020DS/RDB. It can be used to quickly try out the patches. Testing was done with the time stamping program from Patrick Ohly which can be found in the kernel sources under Documentation/networking/timestamping. I have verified the functionality on the MPC8313RDB, P2020DS and P2020RDB board with the latest net-2.6 kernel. Send and receive time stamps could be retrieved on all eTSEC ports. Hello, I've modified the patches according to your comments so far. Version 2 changes: - Only two instead of four patches so every patch adds some useful functionality - hwts_rx_en and hwts_tx_en are no bitfields any more Manfred ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 net-next 1/2] 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.rudig...@omicron.at --- drivers/net/gianfar.c | 66 +--- drivers/net/gianfar.h |5 +++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 080d1ce..552e10d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -82,6 +82,7 @@ #include linux/tcp.h #include linux/udp.h #include linux/in.h +#include linux/net_tstamp.h #include asm/io.h #include asm/irq.h @@ -377,6 +378,13 @@ static void gfar_init_mac(struct net_device *ndev) rctrl |= RCTRL_PADDING(priv-padding); } + /* Insert receive time stamps into padding alignment bytes */ + if (priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER) { + rctrl = ~RCTRL_PAL_MASK; + rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8); + priv-padding = 8; + } + /* keep vlan related bits if it's enabled */ if (priv-vlgrp) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; @@ -501,7 +509,8 @@ void unlock_tx_qs(struct gfar_private *priv) /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return priv-vlgrp || priv-rx_csum_enable; + return priv-vlgrp || priv-rx_csum_enable || + (priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER); } static 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) FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | + FSL_GIANFAR_DEV_HAS_TIMER; ctype = of_get_property(np, phy-connection-type, NULL); @@ -772,6 +782,38 @@ err_grp_init: return err; } +static int gfar_hwtstamp_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct hwtstamp_config config; + struct gfar_private *priv = netdev_priv(netdev); + + if (copy_from_user(config, ifr-ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + if (config.tx_type) + return -ERANGE; + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + priv-hwts_rx_en = 0; + break; + default: + if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) + return -ERANGE; + priv-hwts_rx_en = 1; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + } + + return copy_to_user(ifr-ifr_data, config, sizeof(config)) ? + -EFAULT : 0; +} + /* Ioctl MII Interface */ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -780,6 +822,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!netif_running(dev)) return -EINVAL; + if (cmd == SIOCSHWTSTAMP) + return gfar_hwtstamp_ioctl(dev, rq, cmd); + if (!priv-phydev) return -ENODEV; @@ -982,7 +1027,8 @@ static int gfar_probe(struct of_device *ofdev, else priv-padding = 0; - if (dev-features NETIF_F_IP_CSUM) + if (dev-features NETIF_F_IP_CSUM || + priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER) dev-hard_header_len += GMAC_FCB_LEN; /* 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, skb_pull(skb, amount_pull); } + /* Get receive timestamp from the skb */ + if (priv-hwts_rx_en) { + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + u64 *ns = (u64 *) skb-data; + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps-hwtstamp = ns_to_ktime(*ns); + } + + if (priv-padding) + skb_pull(skb, priv-padding); + if (priv-rx_csum_enable) gfar_rx_checksum(skb, fcb
[PATCH v2 net-next 2/2] gianfar: Add hardware TX timestamping support
If a packet has the skb_shared_tx-hardware flag set the device is instructed to generate a TX timestamp and write it back to memory after the frame is transmitted. During the clean_tx_ring operation the timestamp will be extracted and copied into the skb_shared_hwtstamps struct of the skb. TX timestamping is enabled by setting the tx_type to something else than HWTSTAMP_TX_OFF with the SIOCSHWTSTAMP ioctl command. It is only supported by eTSEC devices. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 118 + drivers/net/gianfar.h |3 +- 2 files changed, 101 insertions(+), 20 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 552e10d..becc3f3 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -795,8 +795,18 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, if (config.flags) return -EINVAL; - if (config.tx_type) + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv-hwts_tx_en = 0; + break; + case HWTSTAMP_TX_ON: + if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) + return -ERANGE; + priv-hwts_tx_en = 1; + break; + default: return -ERANGE; + } switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: @@ -1972,23 +1982,29 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) struct netdev_queue *txq; struct gfar __iomem *regs = NULL; struct txfcb *fcb = NULL; - struct txbd8 *txbdp, *txbdp_start, *base; + struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL; u32 lstatus; - int i, rq = 0; + int i, rq = 0, do_tstamp = 0; u32 bufaddr; unsigned long flags; - unsigned int nr_frags, length; - + unsigned int nr_frags, nr_txbds, length; + union skb_shared_tx *shtx; rq = skb-queue_mapping; tx_queue = priv-tx_queue[rq]; txq = netdev_get_tx_queue(dev, rq); base = tx_queue-tx_bd_base; regs = tx_queue-grp-regs; + shtx = skb_tx(skb); + + /* check if time stamp should be generated */ + if (unlikely(shtx-hardware priv-hwts_tx_en)) + do_tstamp = 1; /* make space for additional header when fcb is needed */ if (((skb-ip_summed == CHECKSUM_PARTIAL) || - (priv-vlgrp vlan_tx_tag_present(skb))) + (priv-vlgrp vlan_tx_tag_present(skb)) || + unlikely(do_tstamp)) (skb_headroom(skb) GMAC_FCB_LEN)) { struct sk_buff *skb_new; @@ -2005,8 +2021,14 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* total number of fragments in the SKB */ nr_frags = skb_shinfo(skb)-nr_frags; + /* calculate the required number of TxBDs for this skb */ + if (unlikely(do_tstamp)) + nr_txbds = nr_frags + 2; + else + nr_txbds = nr_frags + 1; + /* check if there is space to queue this packet */ - if ((nr_frags+1) tx_queue-num_txbdfree) { + if (nr_txbds tx_queue-num_txbdfree) { /* no space, stop the queue */ netif_tx_stop_queue(txq); dev-stats.tx_fifo_errors++; @@ -2018,9 +2040,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txq-tx_packets ++; txbdp = txbdp_start = tx_queue-cur_tx; + lstatus = txbdp-lstatus; + + /* Time stamp insertion requires one additional TxBD */ + if (unlikely(do_tstamp)) + txbdp_tstamp = txbdp = next_txbd(txbdp, base, + tx_queue-tx_ring_size); if (nr_frags == 0) { - lstatus = txbdp-lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + if (unlikely(do_tstamp)) + txbdp_tstamp-lstatus |= BD_LFLAG(TXBD_LAST | + TXBD_INTERRUPT); + else + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); } else { /* Place the fragment addresses and lengths into the TxBDs */ for (i = 0; i nr_frags; i++) { @@ -2066,11 +2098,32 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) gfar_tx_vlan(skb, fcb); } - /* setup the TxBD length and buffer pointer for the first BD */ + /* Setup tx hardware time stamping if requested */ + if (unlikely(do_tstamp)) { + shtx-in_progress = 1; + if (fcb == NULL) + fcb = gfar_add_fcb(skb); + fcb-ptp = 1; + lstatus |= BD_LFLAG(TXBD_TOE); + } + txbdp_start-bufPtr = dma_map_single(priv-ofdev-dev
[RFC PATCH net-next 1/4] gianfar: Added stub support for SIOCSHWTSTAMP
This ioctl command is required for enabling hardware time stamping support for network packets, see Documentation/networking/timestamping.txt. At the moment nothing will be done for all requests that enable time stamping and thus ERANGE will be returned. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 36 1 files changed, 36 insertions(+), 0 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 080d1ce..309bab0 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -82,6 +82,7 @@ #include linux/tcp.h #include linux/udp.h #include linux/in.h +#include linux/net_tstamp.h #include asm/io.h #include asm/irq.h @@ -772,6 +773,38 @@ err_grp_init: return err; } +static int gfar_hwtstamp_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct hwtstamp_config config; + + if (copy_from_user(config, ifr-ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + break; + case HWTSTAMP_TX_ON: + return -ERANGE; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + break; + default: + return -ERANGE; + } + + return copy_to_user(ifr-ifr_data, config, sizeof(config)) ? + -EFAULT : 0; +} + /* Ioctl MII Interface */ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -780,6 +813,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!netif_running(dev)) return -EINVAL; + if (cmd == SIOCSHWTSTAMP) + return gfar_hwtstamp_ioctl(dev, rq, cmd); + if (!priv-phydev) return -ENODEV; -- 1.6.3.3 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH net-next 2/4] gianfar: Added timer feature for eTSEC
The timer clock module is an intrinsic feature of every eTSEC. It supports hardware time stamping of all incoming and outgoing network packets. This patch checks if the underlying hardware is an eTSEC and adds the new FSL_GIANFAR_DEV_HAS_TIMER flag to the device flags. This flag is then used in the SIOCSHWTSTAMP ioctl command to determine if HW time stamping support is available. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 12 +++- drivers/net/gianfar.h |3 +++ 2 files changed, 14 insertions(+), 1 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 309bab0..41e7726 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -743,7 +743,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | + FSL_GIANFAR_DEV_HAS_TIMER; ctype = of_get_property(np, phy-connection-type, NULL); @@ -777,6 +778,7 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct hwtstamp_config config; + struct gfar_private *priv = netdev_priv(netdev); if (copy_from_user(config, ifr-ifr_data, sizeof(config))) return -EFAULT; @@ -787,8 +789,12 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, switch (config.tx_type) { case HWTSTAMP_TX_OFF: + priv-hwts_tx_en = 0; break; case HWTSTAMP_TX_ON: + if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) + return -ERANGE; + priv-hwts_tx_en = 1; return -ERANGE; default: return -ERANGE; @@ -796,8 +802,12 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: + priv-hwts_rx_en = 0; break; default: + if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) + return -ERANGE; + priv-hwts_rx_en = 1; return -ERANGE; } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 17d25e7..380ea48 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -885,6 +885,7 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x0100 #define FSL_GIANFAR_DEV_HAS_BD_STASHING0x0200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x0400 +#define FSL_GIANFAR_DEV_HAS_TIMER 0x0800 #if (MAXGROUPS == 2) #define DEFAULT_MAPPING0xAA @@ -1084,6 +1085,8 @@ struct gfar_private { extended_hash:1, bd_stash_en:1, rx_filer_enable:1, + hwts_tx_en:1, /* HW time stamping enabled for TX packets */ + hwts_rx_en:1, /* HW time stamping enabled for RX packets */ wol_en:1; /* Wake-on-LAN enabled */ unsigned short padding; -- 1.6.3.3 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH net-next 3/4] gianfar: Added raw hardware receive time stamp generation
This patch configures the eTSEC to insert time stamps into all received packets as padding alignment bytes. During the clean_rx_ring operation these raw time stamps are extracted and copied into the skb_shared_hwtstamps struct of the skb if required. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 30 +- drivers/net/gianfar.h |1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 41e7726..9119879 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -378,6 +378,13 @@ static void gfar_init_mac(struct net_device *ndev) rctrl |= RCTRL_PADDING(priv-padding); } + /* Insert receive time stamps into padding alignment bytes */ + if (priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER) { + rctrl = ~RCTRL_PAL_MASK; + rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8); + priv-padding = 8; + } + /* keep vlan related bits if it's enabled */ if (priv-vlgrp) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; @@ -502,7 +509,8 @@ void unlock_tx_qs(struct gfar_private *priv) /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return priv-vlgrp || priv-rx_csum_enable; + return priv-vlgrp || priv-rx_csum_enable || + (priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER); } static void free_tx_pointers(struct gfar_private *priv) @@ -808,7 +816,8 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; priv-hwts_rx_en = 1; - return -ERANGE; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; } return copy_to_user(ifr-ifr_data, config, sizeof(config)) ? @@ -1028,7 +1037,8 @@ static int gfar_probe(struct of_device *ofdev, else priv-padding = 0; - if (dev-features NETIF_F_IP_CSUM) + if (dev-features NETIF_F_IP_CSUM || + priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER) dev-hard_header_len += GMAC_FCB_LEN; /* Program the isrg regs only if number of grps 1 */ @@ -2520,6 +2530,17 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, skb_pull(skb, amount_pull); } + /* Get receive timestamp from the skb */ + if (priv-hwts_rx_en) { + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + u64 *ns = (u64 *) skb-data; + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps-hwtstamp = ns_to_ktime(*ns); + } + + if (priv-padding) + skb_pull(skb, priv-padding); + if (priv-rx_csum_enable) gfar_rx_checksum(skb, fcb); @@ -2556,8 +2577,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) bdp = rx_queue-cur_rx; base = rx_queue-rx_bd_base; - amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) + - priv-padding; + amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0); while (!((bdp-status RXBD_EMPTY) || (--rx_work_limit 0))) { struct sk_buff *newskb; diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 380ea48..cba2756 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -262,6 +262,7 @@ extern const char gfar_driver_version[]; #define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size) +#define RCTRL_TS_ENABLE0x0100 #define RCTRL_PAL_MASK 0x001f #define RCTRL_VLEX 0x2000 #define RCTRL_FILREN 0x1000 -- 1.6.3.3 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH net-next 0/4] timestamping support for gianfar
Hello, this patch series adds support for hardware time stamping to gianfar. It uses the new SO_TIMESTAMPING infrastructure to deliver raw hardware timestamps to user space applications. Freescale CPUs with an eTSEC are able to time stamp all incoming network packets and can also time stamp transmit packets when instructed. The time stamps are generated by the eTSEC timer clock module which is running either from an external oscillator or internal clock. The submitted patches do not initialize the timer clock module since the oscillator frequency might be different from board to board. Thus the user must configure the timer clock module by hand at the moment - otherwise no time stamps will be reported. Below is a simple example code which shows how to configure the timer clock module on the P2020DS/RDB. It can be used to quickly try out the patches. Testing was done with the time stamping program from Patrick Ohly which can be found in the kernel sources under Documentation/networking/timestamping. I have verified the functionality on the MPC8313RDB, P2020DS and P2020RDB board with the latest net-2.6 kernel. Send and receive time stamps could be retrieved on all eTSEC ports. Comments and suggestions are welcome. Thanks, Manfred /** * @file etsec_tmr.c * * This simple kernel module demonstrates how to initialize the eTSEC timer * clock module for hardware timestamping on the P2020. It uses the eTSEC * internal clock (300Mhz) as clock source and programs the timer clock module * to count in nanoseconds. The timer resolution is 5ns. Further it configures * the eTSEC to insert transmit time stamps into the packet data after sending. * * For testing the timestamping.c program from the Linux kernel sources under * Documentation/networking/timestamping can be used. Time stamps will not be * reported until this module has been loaded. * * Usage example: * * [r...@p2020ds root]# insmod etsec_tmr.ko * [r...@p2020ds root]# ./timestamping eth0 SOF_TIMESTAMPING_TX_HARDWARE * SOF_TIMESTAMPING_RX_HARDWARE SOF_TIMESTAMPING_RAW_HARDWARE * * Copyright (C) 2010 OMICRON electronics * Author: Manfred Rudigier manfred.rudig...@omicron.at * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA */ #include linux/init.h #include linux/module.h #include linux/mm.h MODULE_LICENSE(GPL); #define TMR_BASE 0xffe24e00 /* Timer base address of P2020 */ #define REG_SIZE 0x00b0 /* Timer register size */ #define TMR_CTRL 0x /* Timer control register */ #define TMR_ADD0x0020 /* Timer drift compensation addend register */ #define TMR_PRSC 0x0028 /* Timer prescale register */ static void* regs; static int etsec_tmr_init(void) { printk(KERN_INFO etsec tmr init\n); if (!request_mem_region(TMR_BASE, REG_SIZE, etsec_tmr)) { printk(KERN_ERR request_mem_region failed); return -1; } regs = ioremap(TMR_BASE, REG_SIZE); if (!regs) { printk(KERN_ERR ioremap failed); release_mem_region(TMR_BASE, REG_SIZE); return -1; } out_be32(regs + TMR_ADD, 0xaaab); out_be32(regs + TMR_PRSC, 200); out_be32(regs + TMR_CTRL, 0x00058005); return 0; } static void etsec_tmr_exit(void) { out_be32(regs + TMR_CTRL, 0x00010001); iounmap(regs); release_mem_region(TMR_BASE, REG_SIZE); printk(KERN_INFO etsec tmr release\n); } module_init(etsec_tmr_init); module_exit(etsec_tmr_exit); ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH net-next 4/4] gianfar: Added raw hardware transmit time stamp generation
This patch configures the eTSEC to time stamps outgoing packets that have the skb_shared_tx-hardware flag set. The eTSEC is configured to write the time stamps back to memory after the frame is transmitted. During the clean_tx_ring operation these time stamps will be extracted and copied into the skb_shared_hwtstamps struct of the skb if required. Signed-off-by: Manfred Rudigier manfred.rudig...@omicron.at --- drivers/net/gianfar.c | 108 - drivers/net/gianfar.h |2 +- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 9119879..becc3f3 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -803,7 +803,7 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, if (!(priv-device_flags FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; priv-hwts_tx_en = 1; - return -ERANGE; + break; default: return -ERANGE; } @@ -1982,23 +1982,29 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) struct netdev_queue *txq; struct gfar __iomem *regs = NULL; struct txfcb *fcb = NULL; - struct txbd8 *txbdp, *txbdp_start, *base; + struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL; u32 lstatus; - int i, rq = 0; + int i, rq = 0, do_tstamp = 0; u32 bufaddr; unsigned long flags; - unsigned int nr_frags, length; - + unsigned int nr_frags, nr_txbds, length; + union skb_shared_tx *shtx; rq = skb-queue_mapping; tx_queue = priv-tx_queue[rq]; txq = netdev_get_tx_queue(dev, rq); base = tx_queue-tx_bd_base; regs = tx_queue-grp-regs; + shtx = skb_tx(skb); + + /* check if time stamp should be generated */ + if (unlikely(shtx-hardware priv-hwts_tx_en)) + do_tstamp = 1; /* make space for additional header when fcb is needed */ if (((skb-ip_summed == CHECKSUM_PARTIAL) || - (priv-vlgrp vlan_tx_tag_present(skb))) + (priv-vlgrp vlan_tx_tag_present(skb)) || + unlikely(do_tstamp)) (skb_headroom(skb) GMAC_FCB_LEN)) { struct sk_buff *skb_new; @@ -2015,8 +2021,14 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* total number of fragments in the SKB */ nr_frags = skb_shinfo(skb)-nr_frags; + /* calculate the required number of TxBDs for this skb */ + if (unlikely(do_tstamp)) + nr_txbds = nr_frags + 2; + else + nr_txbds = nr_frags + 1; + /* check if there is space to queue this packet */ - if ((nr_frags+1) tx_queue-num_txbdfree) { + if (nr_txbds tx_queue-num_txbdfree) { /* no space, stop the queue */ netif_tx_stop_queue(txq); dev-stats.tx_fifo_errors++; @@ -2028,9 +2040,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txq-tx_packets ++; txbdp = txbdp_start = tx_queue-cur_tx; + lstatus = txbdp-lstatus; + + /* Time stamp insertion requires one additional TxBD */ + if (unlikely(do_tstamp)) + txbdp_tstamp = txbdp = next_txbd(txbdp, base, + tx_queue-tx_ring_size); if (nr_frags == 0) { - lstatus = txbdp-lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + if (unlikely(do_tstamp)) + txbdp_tstamp-lstatus |= BD_LFLAG(TXBD_LAST | + TXBD_INTERRUPT); + else + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); } else { /* Place the fragment addresses and lengths into the TxBDs */ for (i = 0; i nr_frags; i++) { @@ -2076,11 +2098,32 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) gfar_tx_vlan(skb, fcb); } - /* setup the TxBD length and buffer pointer for the first BD */ + /* Setup tx hardware time stamping if requested */ + if (unlikely(do_tstamp)) { + shtx-in_progress = 1; + if (fcb == NULL) + fcb = gfar_add_fcb(skb); + fcb-ptp = 1; + lstatus |= BD_LFLAG(TXBD_TOE); + } + txbdp_start-bufPtr = dma_map_single(priv-ofdev-dev, skb-data, skb_headlen(skb), DMA_TO_DEVICE); - lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); + /* +* If time stamping is requested one additional TxBD must be set up. The +* first TxBD points to the FCB and must have a data length of +* GMAC_FCB_LEN. The second TxBD points to the actual frame data