aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/arm
diff options
context:
space:
mode:
authorRichard Cochran <richardcochran@gmail.com>2011-04-22 06:04:31 -0400
committerJohn Stultz <john.stultz@linaro.org>2011-05-23 16:10:19 -0400
commit32bd93e8f924c23b8cc2e2a12fef0d8cc9cda0c5 (patch)
treede808d7b959459c741b9999444dfc4a4460b1d2f /drivers/net/arm
parentc78275f366c687b5b3ead3d99fc96d1f02d38a8e (diff)
ptp: Added a clock driver for the IXP46x.
This patch adds a driver for the hardware time stamping unit found on the IXP465. The basic clock operations and an external trigger are implemented. Signed-off-by: Richard Cochran <richard.cochran@omicron.at> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: David S. Miller <davem@davemloft.net> Acked-by: John Stultz <john.stultz@linaro.org> Acked-by: Krzysztof Halasa <khc@pm.waw.pl> Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'drivers/net/arm')
-rw-r--r--drivers/net/arm/ixp4xx_eth.c195
1 files changed, 192 insertions, 3 deletions
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 9eb9b98a7ae3..de51e8453c13 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -30,9 +30,12 @@
30#include <linux/etherdevice.h> 30#include <linux/etherdevice.h>
31#include <linux/io.h> 31#include <linux/io.h>
32#include <linux/kernel.h> 32#include <linux/kernel.h>
33#include <linux/net_tstamp.h>
33#include <linux/phy.h> 34#include <linux/phy.h>
34#include <linux/platform_device.h> 35#include <linux/platform_device.h>
36#include <linux/ptp_classify.h>
35#include <linux/slab.h> 37#include <linux/slab.h>
38#include <mach/ixp46x_ts.h>
36#include <mach/npe.h> 39#include <mach/npe.h>
37#include <mach/qmgr.h> 40#include <mach/qmgr.h>
38 41
@@ -67,6 +70,10 @@
67#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26) 70#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
68#define TXDONE_QUEUE 31 71#define TXDONE_QUEUE 31
69 72
73#define PTP_SLAVE_MODE 1
74#define PTP_MASTER_MODE 2
75#define PORT2CHANNEL(p) NPE_ID(p->id)
76
70/* TX Control Registers */ 77/* TX Control Registers */
71#define TX_CNTRL0_TX_EN 0x01 78#define TX_CNTRL0_TX_EN 0x01
72#define TX_CNTRL0_HALFDUPLEX 0x02 79#define TX_CNTRL0_HALFDUPLEX 0x02
@@ -171,6 +178,8 @@ struct port {
171 int id; /* logical port ID */ 178 int id; /* logical port ID */
172 int speed, duplex; 179 int speed, duplex;
173 u8 firmware[4]; 180 u8 firmware[4];
181 int hwts_tx_en;
182 int hwts_rx_en;
174}; 183};
175 184
176/* NPE message structure */ 185/* NPE message structure */
@@ -246,6 +255,172 @@ static int ports_open;
246static struct port *npe_port_tab[MAX_NPES]; 255static struct port *npe_port_tab[MAX_NPES];
247static struct dma_pool *dma_pool; 256static struct dma_pool *dma_pool;
248 257
258static struct sock_filter ptp_filter[] = {
259 PTP_FILTER
260};
261
262static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
263{
264 u8 *data = skb->data;
265 unsigned int offset;
266 u16 *hi, *id;
267 u32 lo;
268
269 if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
270 return 0;
271
272 offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
273
274 if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
275 return 0;
276
277 hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
278 id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
279
280 memcpy(&lo, &hi[1], sizeof(lo));
281
282 return (uid_hi == ntohs(*hi) &&
283 uid_lo == ntohl(lo) &&
284 seqid == ntohs(*id));
285}
286
287static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb)
288{
289 struct skb_shared_hwtstamps *shhwtstamps;
290 struct ixp46x_ts_regs *regs;
291 u64 ns;
292 u32 ch, hi, lo, val;
293 u16 uid, seq;
294
295 if (!port->hwts_rx_en)
296 return;
297
298 ch = PORT2CHANNEL(port);
299
300 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
301
302 val = __raw_readl(&regs->channel[ch].ch_event);
303
304 if (!(val & RX_SNAPSHOT_LOCKED))
305 return;
306
307 lo = __raw_readl(&regs->channel[ch].src_uuid_lo);
308 hi = __raw_readl(&regs->channel[ch].src_uuid_hi);
309
310 uid = hi & 0xffff;
311 seq = (hi >> 16) & 0xffff;
312
313 if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
314 goto out;
315
316 lo = __raw_readl(&regs->channel[ch].rx_snap_lo);
317 hi = __raw_readl(&regs->channel[ch].rx_snap_hi);
318 ns = ((u64) hi) << 32;
319 ns |= lo;
320 ns <<= TICKS_NS_SHIFT;
321
322 shhwtstamps = skb_hwtstamps(skb);
323 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
324 shhwtstamps->hwtstamp = ns_to_ktime(ns);
325out:
326 __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
327}
328
329static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
330{
331 struct skb_shared_hwtstamps shhwtstamps;
332 struct ixp46x_ts_regs *regs;
333 struct skb_shared_info *shtx;
334 u64 ns;
335 u32 ch, cnt, hi, lo, val;
336
337 shtx = skb_shinfo(skb);
338 if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en))
339 shtx->tx_flags |= SKBTX_IN_PROGRESS;
340 else
341 return;
342
343 ch = PORT2CHANNEL(port);
344
345 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
346
347 /*
348 * This really stinks, but we have to poll for the Tx time stamp.
349 * Usually, the time stamp is ready after 4 to 6 microseconds.
350 */
351 for (cnt = 0; cnt < 100; cnt++) {
352 val = __raw_readl(&regs->channel[ch].ch_event);
353 if (val & TX_SNAPSHOT_LOCKED)
354 break;
355 udelay(1);
356 }
357 if (!(val & TX_SNAPSHOT_LOCKED)) {
358 shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
359 return;
360 }
361
362 lo = __raw_readl(&regs->channel[ch].tx_snap_lo);
363 hi = __raw_readl(&regs->channel[ch].tx_snap_hi);
364 ns = ((u64) hi) << 32;
365 ns |= lo;
366 ns <<= TICKS_NS_SHIFT;
367
368 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
369 shhwtstamps.hwtstamp = ns_to_ktime(ns);
370 skb_tstamp_tx(skb, &shhwtstamps);
371
372 __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
373}
374
375static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
376{
377 struct hwtstamp_config cfg;
378 struct ixp46x_ts_regs *regs;
379 struct port *port = netdev_priv(netdev);
380 int ch;
381
382 if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
383 return -EFAULT;
384
385 if (cfg.flags) /* reserved for future extensions */
386 return -EINVAL;
387
388 ch = PORT2CHANNEL(port);
389 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
390
391 switch (cfg.tx_type) {
392 case HWTSTAMP_TX_OFF:
393 port->hwts_tx_en = 0;
394 break;
395 case HWTSTAMP_TX_ON:
396 port->hwts_tx_en = 1;
397 break;
398 default:
399 return -ERANGE;
400 }
401
402 switch (cfg.rx_filter) {
403 case HWTSTAMP_FILTER_NONE:
404 port->hwts_rx_en = 0;
405 break;
406 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
407 port->hwts_rx_en = PTP_SLAVE_MODE;
408 __raw_writel(0, &regs->channel[ch].ch_control);
409 break;
410 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
411 port->hwts_rx_en = PTP_MASTER_MODE;
412 __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control);
413 break;
414 default:
415 return -ERANGE;
416 }
417
418 /* Clear out any old time stamps. */
419 __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
420 &regs->channel[ch].ch_event);
421
422 return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
423}
249 424
250static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, 425static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
251 int write, u16 cmd) 426 int write, u16 cmd)
@@ -573,6 +748,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
573 748
574 debug_pkt(dev, "eth_poll", skb->data, skb->len); 749 debug_pkt(dev, "eth_poll", skb->data, skb->len);
575 750
751 ixp_rx_timestamp(port, skb);
576 skb->protocol = eth_type_trans(skb, dev); 752 skb->protocol = eth_type_trans(skb, dev);
577 dev->stats.rx_packets++; 753 dev->stats.rx_packets++;
578 dev->stats.rx_bytes += skb->len; 754 dev->stats.rx_bytes += skb->len;
@@ -679,14 +855,12 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
679 return NETDEV_TX_OK; 855 return NETDEV_TX_OK;
680 } 856 }
681 memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); 857 memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
682 dev_kfree_skb(skb);
683#endif 858#endif
684 859
685 phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); 860 phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
686 if (dma_mapping_error(&dev->dev, phys)) { 861 if (dma_mapping_error(&dev->dev, phys)) {
687#ifdef __ARMEB__
688 dev_kfree_skb(skb); 862 dev_kfree_skb(skb);
689#else 863#ifndef __ARMEB__
690 kfree(mem); 864 kfree(mem);
691#endif 865#endif
692 dev->stats.tx_dropped++; 866 dev->stats.tx_dropped++;
@@ -728,6 +902,13 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
728#if DEBUG_TX 902#if DEBUG_TX
729 printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name); 903 printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
730#endif 904#endif
905
906 ixp_tx_timestamp(port, skb);
907 skb_tx_timestamp(skb);
908
909#ifndef __ARMEB__
910 dev_kfree_skb(skb);
911#endif
731 return NETDEV_TX_OK; 912 return NETDEV_TX_OK;
732} 913}
733 914
@@ -783,6 +964,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
783 if (!netif_running(dev)) 964 if (!netif_running(dev))
784 return -EINVAL; 965 return -EINVAL;
785 966
967 if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
968 return hwtstamp_ioctl(dev, req, cmd);
969
786 return phy_mii_ioctl(port->phydev, req, cmd); 970 return phy_mii_ioctl(port->phydev, req, cmd);
787} 971}
788 972
@@ -1171,6 +1355,11 @@ static int __devinit eth_init_one(struct platform_device *pdev)
1171 char phy_id[MII_BUS_ID_SIZE + 3]; 1355 char phy_id[MII_BUS_ID_SIZE + 3];
1172 int err; 1356 int err;
1173 1357
1358 if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
1359 pr_err("ixp4xx_eth: bad ptp filter\n");
1360 return -EINVAL;
1361 }
1362
1174 if (!(dev = alloc_etherdev(sizeof(struct port)))) 1363 if (!(dev = alloc_etherdev(sizeof(struct port))))
1175 return -ENOMEM; 1364 return -ENOMEM;
1176 1365