[PATCH] gianfar: Fix setup of RX time stamping

2010-06-11 Thread Manfred Rudigier
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

2010-04-09 Thread Manfred Rudigier
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

2010-04-09 Thread Manfred Rudigier
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

2010-04-09 Thread Manfred Rudigier
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

2010-04-07 Thread Manfred Rudigier
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

2010-04-07 Thread Manfred Rudigier
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

2010-04-07 Thread Manfred Rudigier
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

2010-04-07 Thread Manfred Rudigier
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

2010-04-07 Thread Manfred Rudigier
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