aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/tile/gxio/iorpc_mpipe.c19
-rw-r--r--arch/tile/include/gxio/iorpc_mpipe.h10
-rw-r--r--arch/tile/include/gxio/mpipe.h14
-rw-r--r--drivers/net/ethernet/tile/Kconfig11
-rw-r--r--drivers/net/ethernet/tile/tilegx.c216
5 files changed, 266 insertions, 4 deletions
diff --git a/arch/tile/gxio/iorpc_mpipe.c b/arch/tile/gxio/iorpc_mpipe.c
index c2fb15167aee..4f8f3d619c4a 100644
--- a/arch/tile/gxio/iorpc_mpipe.c
+++ b/arch/tile/gxio/iorpc_mpipe.c
@@ -475,6 +475,25 @@ int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
475 475
476EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux); 476EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux);
477 477
478struct adjust_timestamp_freq_param {
479 int32_t ppb;
480};
481
482int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
483 int32_t ppb)
484{
485 struct adjust_timestamp_freq_param temp;
486 struct adjust_timestamp_freq_param *params = &temp;
487
488 params->ppb = ppb;
489
490 return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
491 sizeof(*params),
492 GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ);
493}
494
495EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq);
496
478struct config_edma_ring_blks_param { 497struct config_edma_ring_blks_param {
479 unsigned int ering; 498 unsigned int ering;
480 unsigned int max_blks; 499 unsigned int max_blks;
diff --git a/arch/tile/include/gxio/iorpc_mpipe.h b/arch/tile/include/gxio/iorpc_mpipe.h
index eef60fdd8525..fdd07f88cfd7 100644
--- a/arch/tile/include/gxio/iorpc_mpipe.h
+++ b/arch/tile/include/gxio/iorpc_mpipe.h
@@ -46,10 +46,11 @@
46#define GXIO_MPIPE_OP_LINK_CLOSE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212) 46#define GXIO_MPIPE_OP_LINK_CLOSE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212)
47#define GXIO_MPIPE_OP_LINK_SET_ATTR_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1213) 47#define GXIO_MPIPE_OP_LINK_SET_ATTR_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1213)
48 48
49#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121e) 49#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121e)
50#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121f) 50#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121f)
51#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1220) 51#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1220)
52#define GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1221) 52#define GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1221)
53#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1222)
53#define GXIO_MPIPE_OP_ARM_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000) 54#define GXIO_MPIPE_OP_ARM_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000)
54#define GXIO_MPIPE_OP_CLOSE_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001) 55#define GXIO_MPIPE_OP_CLOSE_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001)
55#define GXIO_MPIPE_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) 56#define GXIO_MPIPE_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
@@ -128,6 +129,9 @@ int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
128int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context, 129int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
129 int64_t nsec); 130 int64_t nsec);
130 131
132int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
133 int32_t ppb);
134
131int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie); 135int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
132 136
133int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie); 137int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
diff --git a/arch/tile/include/gxio/mpipe.h b/arch/tile/include/gxio/mpipe.h
index eb7fee41c9b6..e37cf4f0cffd 100644
--- a/arch/tile/include/gxio/mpipe.h
+++ b/arch/tile/include/gxio/mpipe.h
@@ -1854,4 +1854,18 @@ extern int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context,
1854extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context, 1854extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context,
1855 int64_t delta); 1855 int64_t delta);
1856 1856
1857/** Adjust the mPIPE timestamp clock frequency.
1858 *
1859 * @param context An initialized mPIPE context.
1860 * @param ppb A 32-bit signed PPB (Parts Per Billion) value to adjust.
1861 * The absolute value of ppb must be less than or equal to 1000000000.
1862 * Values less than about 30000 will generally cause a GXIO_ERR_INVAL
1863 * return due to the granularity of the hardware that converts reference
1864 * clock cycles into seconds and nanoseconds.
1865 * @return If the call was successful, zero; otherwise, a negative error
1866 * code.
1867 */
1868extern int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t* context,
1869 int32_t ppb);
1870
1857#endif /* !_GXIO_MPIPE_H_ */ 1871#endif /* !_GXIO_MPIPE_H_ */
diff --git a/drivers/net/ethernet/tile/Kconfig b/drivers/net/ethernet/tile/Kconfig
index 098b1c42b393..4083ba8839e1 100644
--- a/drivers/net/ethernet/tile/Kconfig
+++ b/drivers/net/ethernet/tile/Kconfig
@@ -15,3 +15,14 @@ config TILE_NET
15 15
16 To compile this driver as a module, choose M here: the module 16 To compile this driver as a module, choose M here: the module
17 will be called tile_net. 17 will be called tile_net.
18
19config PTP_1588_CLOCK_TILEGX
20 tristate "Tilera TILE-Gx mPIPE as PTP clock"
21 select PTP_1588_CLOCK
22 depends on TILE_NET
23 depends on TILEGX
24 ---help---
25 This driver adds support for using the mPIPE as a PTP
26 clock. This clock is only useful if your PTP programs are
27 getting hardware time stamps on the PTP Ethernet packets
28 using the SO_TIMESTAMPING API.
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 0beed7e31f9e..907b5772fd55 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -38,6 +38,8 @@
38#include <linux/ip.h> 38#include <linux/ip.h>
39#include <linux/ipv6.h> 39#include <linux/ipv6.h>
40#include <linux/tcp.h> 40#include <linux/tcp.h>
41#include <linux/net_tstamp.h>
42#include <linux/ptp_clock_kernel.h>
41 43
42#include <asm/checksum.h> 44#include <asm/checksum.h>
43#include <asm/homecache.h> 45#include <asm/homecache.h>
@@ -185,6 +187,10 @@ struct tile_net_priv {
185 int echannel; 187 int echannel;
186 /* mPIPE instance, 0 or 1. */ 188 /* mPIPE instance, 0 or 1. */
187 int instance; 189 int instance;
190#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
191 /* The timestamp config. */
192 struct hwtstamp_config stamp_cfg;
193#endif
188}; 194};
189 195
190static struct mpipe_data { 196static struct mpipe_data {
@@ -223,6 +229,15 @@ static struct mpipe_data {
223 int first_bucket; 229 int first_bucket;
224 int num_buckets; 230 int num_buckets;
225 231
232#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
233 /* PTP-specific data. */
234 struct ptp_clock *ptp_clock;
235 struct ptp_clock_info caps;
236
237 /* Lock for ptp accessors. */
238 struct mutex ptp_lock;
239#endif
240
226} mpipe_data[NR_MPIPE_MAX] = { 241} mpipe_data[NR_MPIPE_MAX] = {
227 [0 ... (NR_MPIPE_MAX - 1)] { 242 [0 ... (NR_MPIPE_MAX - 1)] {
228 .ingress_irq = -1, 243 .ingress_irq = -1,
@@ -432,6 +447,94 @@ static void tile_net_provide_needed_buffers(void)
432 } 447 }
433} 448}
434 449
450/* Get RX timestamp, and store it in the skb. */
451static void tile_rx_timestamp(struct tile_net_priv *priv, struct sk_buff *skb,
452 gxio_mpipe_idesc_t *idesc)
453{
454#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
455 if (unlikely(priv->stamp_cfg.rx_filter != HWTSTAMP_FILTER_NONE)) {
456 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
457 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
458 shhwtstamps->hwtstamp = ktime_set(idesc->time_stamp_sec,
459 idesc->time_stamp_ns);
460 }
461#endif
462}
463
464/* Get TX timestamp, and store it in the skb. */
465static void tile_tx_timestamp(struct sk_buff *skb, int instance)
466{
467#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
468 struct skb_shared_info *shtx = skb_shinfo(skb);
469 if (unlikely((shtx->tx_flags & SKBTX_HW_TSTAMP) != 0)) {
470 struct mpipe_data *md = &mpipe_data[instance];
471 struct skb_shared_hwtstamps shhwtstamps;
472 struct timespec ts;
473
474 shtx->tx_flags |= SKBTX_IN_PROGRESS;
475 gxio_mpipe_get_timestamp(&md->context, &ts);
476 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
477 shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
478 skb_tstamp_tx(skb, &shhwtstamps);
479 }
480#endif
481}
482
483/* Use ioctl() to enable or disable TX or RX timestamping. */
484static int tile_hwtstamp_ioctl(struct net_device *dev, struct ifreq *rq,
485 int cmd)
486{
487#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
488 struct hwtstamp_config config;
489 struct tile_net_priv *priv = netdev_priv(dev);
490
491 if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
492 return -EFAULT;
493
494 if (config.flags) /* reserved for future extensions */
495 return -EINVAL;
496
497 switch (config.tx_type) {
498 case HWTSTAMP_TX_OFF:
499 case HWTSTAMP_TX_ON:
500 break;
501 default:
502 return -ERANGE;
503 }
504
505 switch (config.rx_filter) {
506 case HWTSTAMP_FILTER_NONE:
507 break;
508 case HWTSTAMP_FILTER_ALL:
509 case HWTSTAMP_FILTER_SOME:
510 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
511 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
512 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
513 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
514 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
515 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
516 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
517 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
518 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
519 case HWTSTAMP_FILTER_PTP_V2_EVENT:
520 case HWTSTAMP_FILTER_PTP_V2_SYNC:
521 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
522 config.rx_filter = HWTSTAMP_FILTER_ALL;
523 break;
524 default:
525 return -ERANGE;
526 }
527
528 if (copy_to_user(rq->ifr_data, &config, sizeof(config)))
529 return -EFAULT;
530
531 priv->stamp_cfg = config;
532 return 0;
533#else
534 return -EOPNOTSUPP;
535#endif
536}
537
435static inline bool filter_packet(struct net_device *dev, void *buf) 538static inline bool filter_packet(struct net_device *dev, void *buf)
436{ 539{
437 /* Filter packets received before we're up. */ 540 /* Filter packets received before we're up. */
@@ -451,7 +554,8 @@ static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb,
451 gxio_mpipe_idesc_t *idesc, unsigned long len) 554 gxio_mpipe_idesc_t *idesc, unsigned long len)
452{ 555{
453 struct tile_net_info *info = &__get_cpu_var(per_cpu_info); 556 struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
454 int instance = mpipe_instance(dev); 557 struct tile_net_priv *priv = netdev_priv(dev);
558 int instance = priv->instance;
455 559
456 /* Encode the actual packet length. */ 560 /* Encode the actual packet length. */
457 skb_put(skb, len); 561 skb_put(skb, len);
@@ -462,6 +566,9 @@ static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb,
462 if (idesc->cs && idesc->csum_seed_val == 0xFFFF) 566 if (idesc->cs && idesc->csum_seed_val == 0xFFFF)
463 skb->ip_summed = CHECKSUM_UNNECESSARY; 567 skb->ip_summed = CHECKSUM_UNNECESSARY;
464 568
569 /* Get RX timestamp from idesc. */
570 tile_rx_timestamp(priv, skb, idesc);
571
465 napi_gro_receive(&info->mpipe[instance].napi, skb); 572 napi_gro_receive(&info->mpipe[instance].napi, skb);
466 573
467 /* Update stats. */ 574 /* Update stats. */
@@ -707,6 +814,103 @@ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t)
707 return HRTIMER_NORESTART; 814 return HRTIMER_NORESTART;
708} 815}
709 816
817#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
818
819/* PTP clock operations. */
820
821static int ptp_mpipe_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
822{
823 int ret = 0;
824 struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
825 mutex_lock(&md->ptp_lock);
826 if (gxio_mpipe_adjust_timestamp_freq(&md->context, ppb))
827 ret = -EINVAL;
828 mutex_unlock(&md->ptp_lock);
829 return ret;
830}
831
832static int ptp_mpipe_adjtime(struct ptp_clock_info *ptp, s64 delta)
833{
834 int ret = 0;
835 struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
836 mutex_lock(&md->ptp_lock);
837 if (gxio_mpipe_adjust_timestamp(&md->context, delta))
838 ret = -EBUSY;
839 mutex_unlock(&md->ptp_lock);
840 return ret;
841}
842
843static int ptp_mpipe_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
844{
845 int ret = 0;
846 struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
847 mutex_lock(&md->ptp_lock);
848 if (gxio_mpipe_get_timestamp(&md->context, ts))
849 ret = -EBUSY;
850 mutex_unlock(&md->ptp_lock);
851 return ret;
852}
853
854static int ptp_mpipe_settime(struct ptp_clock_info *ptp,
855 const struct timespec *ts)
856{
857 int ret = 0;
858 struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
859 mutex_lock(&md->ptp_lock);
860 if (gxio_mpipe_set_timestamp(&md->context, ts))
861 ret = -EBUSY;
862 mutex_unlock(&md->ptp_lock);
863 return ret;
864}
865
866static int ptp_mpipe_enable(struct ptp_clock_info *ptp,
867 struct ptp_clock_request *request, int on)
868{
869 return -EOPNOTSUPP;
870}
871
872static struct ptp_clock_info ptp_mpipe_caps = {
873 .owner = THIS_MODULE,
874 .name = "mPIPE clock",
875 .max_adj = 999999999,
876 .n_ext_ts = 0,
877 .pps = 0,
878 .adjfreq = ptp_mpipe_adjfreq,
879 .adjtime = ptp_mpipe_adjtime,
880 .gettime = ptp_mpipe_gettime,
881 .settime = ptp_mpipe_settime,
882 .enable = ptp_mpipe_enable,
883};
884
885#endif /* CONFIG_PTP_1588_CLOCK_TILEGX */
886
887/* Sync mPIPE's timestamp up with Linux system time and register PTP clock. */
888static void register_ptp_clock(struct net_device *dev, struct mpipe_data *md)
889{
890#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
891 struct timespec ts;
892
893 getnstimeofday(&ts);
894 gxio_mpipe_set_timestamp(&md->context, &ts);
895
896 mutex_init(&md->ptp_lock);
897 md->caps = ptp_mpipe_caps;
898 md->ptp_clock = ptp_clock_register(&md->caps, NULL);
899 if (IS_ERR(md->ptp_clock))
900 netdev_err(dev, "ptp_clock_register failed %ld\n",
901 PTR_ERR(md->ptp_clock));
902#endif
903}
904
905/* Initialize PTP fields in a new device. */
906static void init_ptp_dev(struct tile_net_priv *priv)
907{
908#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
909 priv->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
910 priv->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
911#endif
912}
913
710/* Helper functions for "tile_net_update()". */ 914/* Helper functions for "tile_net_update()". */
711static void enable_ingress_irq(void *irq) 915static void enable_ingress_irq(void *irq)
712{ 916{
@@ -1149,6 +1353,9 @@ static int tile_net_init_mpipe(struct net_device *dev)
1149 if (rc != 0) 1353 if (rc != 0)
1150 goto fail; 1354 goto fail;
1151 1355
1356 /* Register PTP clock and set mPIPE timestamp, if configured. */
1357 register_ptp_clock(dev, md);
1358
1152 return 0; 1359 return 0;
1153 1360
1154fail: 1361fail:
@@ -1851,6 +2058,9 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
1851 for (i = 0; i < num_edescs; i++) 2058 for (i = 0; i < num_edescs; i++)
1852 gxio_mpipe_equeue_put_at(equeue, edescs[i], slot++); 2059 gxio_mpipe_equeue_put_at(equeue, edescs[i], slot++);
1853 2060
2061 /* Store TX timestamp if needed. */
2062 tile_tx_timestamp(skb, instance);
2063
1854 /* Add a completion record. */ 2064 /* Add a completion record. */
1855 add_comp(equeue, comps, slot - 1, skb); 2065 add_comp(equeue, comps, slot - 1, skb);
1856 2066
@@ -1885,6 +2095,9 @@ static void tile_net_tx_timeout(struct net_device *dev)
1885/* Ioctl commands. */ 2095/* Ioctl commands. */
1886static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 2096static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1887{ 2097{
2098 if (cmd == SIOCSHWTSTAMP)
2099 return tile_hwtstamp_ioctl(dev, rq, cmd);
2100
1888 return -EOPNOTSUPP; 2101 return -EOPNOTSUPP;
1889} 2102}
1890 2103
@@ -2005,6 +2218,7 @@ static void tile_net_dev_init(const char *name, const uint8_t *mac)
2005 priv->channel = -1; 2218 priv->channel = -1;
2006 priv->loopify_channel = -1; 2219 priv->loopify_channel = -1;
2007 priv->echannel = -1; 2220 priv->echannel = -1;
2221 init_ptp_dev(priv);
2008 2222
2009 /* Get the MAC address and set it in the device struct; this must 2223 /* Get the MAC address and set it in the device struct; this must
2010 * be done before the device is opened. If the MAC is all zeroes, 2224 * be done before the device is opened. If the MAC is all zeroes,