Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tile: support PTP using the tilegx mPIPE (IEEE 1588)

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Chris Metcalf and committed by
David S. Miller
9ab5ec59 84e181ba

+266 -4
+19
arch/tile/gxio/iorpc_mpipe.c
··· 475 475 476 476 EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux); 477 477 478 + struct adjust_timestamp_freq_param { 479 + int32_t ppb; 480 + }; 481 + 482 + int 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 + 495 + EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq); 496 + 478 497 struct config_edma_ring_blks_param { 479 498 unsigned int ering; 480 499 unsigned int max_blks;
+7 -3
arch/tile/include/gxio/iorpc_mpipe.h
··· 46 46 #define GXIO_MPIPE_OP_LINK_CLOSE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212) 47 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) 50 - #define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121f) 51 - #define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1220) 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, 0x121f) 51 + #define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1220) 52 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 54 #define GXIO_MPIPE_OP_ARM_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000) 54 55 #define GXIO_MPIPE_OP_CLOSE_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001) 55 56 #define GXIO_MPIPE_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) ··· 128 127 129 128 int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context, 130 129 int64_t nsec); 130 + 131 + int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context, 132 + int32_t ppb); 131 133 132 134 int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie); 133 135
+14
arch/tile/include/gxio/mpipe.h
··· 1854 1854 extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context, 1855 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 + */ 1868 + extern int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t* context, 1869 + int32_t ppb); 1870 + 1857 1871 #endif /* !_GXIO_MPIPE_H_ */
+11
drivers/net/ethernet/tile/Kconfig
··· 15 15 16 16 To compile this driver as a module, choose M here: the module 17 17 will be called tile_net. 18 + 19 + config 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.
+215 -1
drivers/net/ethernet/tile/tilegx.c
··· 38 38 #include <linux/ip.h> 39 39 #include <linux/ipv6.h> 40 40 #include <linux/tcp.h> 41 + #include <linux/net_tstamp.h> 42 + #include <linux/ptp_clock_kernel.h> 41 43 42 44 #include <asm/checksum.h> 43 45 #include <asm/homecache.h> ··· 187 185 int echannel; 188 186 /* mPIPE instance, 0 or 1. */ 189 187 int instance; 188 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 189 + /* The timestamp config. */ 190 + struct hwtstamp_config stamp_cfg; 191 + #endif 190 192 }; 191 193 192 194 static struct mpipe_data { ··· 228 222 /* The buckets. */ 229 223 int first_bucket; 230 224 int num_buckets; 225 + 226 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 227 + /* PTP-specific data. */ 228 + struct ptp_clock *ptp_clock; 229 + struct ptp_clock_info caps; 230 + 231 + /* Lock for ptp accessors. */ 232 + struct mutex ptp_lock; 233 + #endif 231 234 232 235 } mpipe_data[NR_MPIPE_MAX] = { 233 236 [0 ... (NR_MPIPE_MAX - 1)] { ··· 447 432 } 448 433 } 449 434 435 + /* Get RX timestamp, and store it in the skb. */ 436 + static void tile_rx_timestamp(struct tile_net_priv *priv, struct sk_buff *skb, 437 + gxio_mpipe_idesc_t *idesc) 438 + { 439 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 440 + if (unlikely(priv->stamp_cfg.rx_filter != HWTSTAMP_FILTER_NONE)) { 441 + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); 442 + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 443 + shhwtstamps->hwtstamp = ktime_set(idesc->time_stamp_sec, 444 + idesc->time_stamp_ns); 445 + } 446 + #endif 447 + } 448 + 449 + /* Get TX timestamp, and store it in the skb. */ 450 + static void tile_tx_timestamp(struct sk_buff *skb, int instance) 451 + { 452 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 453 + struct skb_shared_info *shtx = skb_shinfo(skb); 454 + if (unlikely((shtx->tx_flags & SKBTX_HW_TSTAMP) != 0)) { 455 + struct mpipe_data *md = &mpipe_data[instance]; 456 + struct skb_shared_hwtstamps shhwtstamps; 457 + struct timespec ts; 458 + 459 + shtx->tx_flags |= SKBTX_IN_PROGRESS; 460 + gxio_mpipe_get_timestamp(&md->context, &ts); 461 + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 462 + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 463 + skb_tstamp_tx(skb, &shhwtstamps); 464 + } 465 + #endif 466 + } 467 + 468 + /* Use ioctl() to enable or disable TX or RX timestamping. */ 469 + static int tile_hwtstamp_ioctl(struct net_device *dev, struct ifreq *rq, 470 + int cmd) 471 + { 472 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 473 + struct hwtstamp_config config; 474 + struct tile_net_priv *priv = netdev_priv(dev); 475 + 476 + if (copy_from_user(&config, rq->ifr_data, sizeof(config))) 477 + return -EFAULT; 478 + 479 + if (config.flags) /* reserved for future extensions */ 480 + return -EINVAL; 481 + 482 + switch (config.tx_type) { 483 + case HWTSTAMP_TX_OFF: 484 + case HWTSTAMP_TX_ON: 485 + break; 486 + default: 487 + return -ERANGE; 488 + } 489 + 490 + switch (config.rx_filter) { 491 + case HWTSTAMP_FILTER_NONE: 492 + break; 493 + case HWTSTAMP_FILTER_ALL: 494 + case HWTSTAMP_FILTER_SOME: 495 + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 496 + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 497 + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 498 + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 499 + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 500 + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 501 + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 502 + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 503 + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 504 + case HWTSTAMP_FILTER_PTP_V2_EVENT: 505 + case HWTSTAMP_FILTER_PTP_V2_SYNC: 506 + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 507 + config.rx_filter = HWTSTAMP_FILTER_ALL; 508 + break; 509 + default: 510 + return -ERANGE; 511 + } 512 + 513 + if (copy_to_user(rq->ifr_data, &config, sizeof(config))) 514 + return -EFAULT; 515 + 516 + priv->stamp_cfg = config; 517 + return 0; 518 + #else 519 + return -EOPNOTSUPP; 520 + #endif 521 + } 522 + 450 523 static inline bool filter_packet(struct net_device *dev, void *buf) 451 524 { 452 525 /* Filter packets received before we're up. */ ··· 554 451 gxio_mpipe_idesc_t *idesc, unsigned long len) 555 452 { 556 453 struct tile_net_info *info = &__get_cpu_var(per_cpu_info); 557 - int instance = mpipe_instance(dev); 454 + struct tile_net_priv *priv = netdev_priv(dev); 455 + int instance = priv->instance; 558 456 559 457 /* Encode the actual packet length. */ 560 458 skb_put(skb, len); ··· 565 461 /* Acknowledge "good" hardware checksums. */ 566 462 if (idesc->cs && idesc->csum_seed_val == 0xFFFF) 567 463 skb->ip_summed = CHECKSUM_UNNECESSARY; 464 + 465 + /* Get RX timestamp from idesc. */ 466 + tile_rx_timestamp(priv, skb, idesc); 568 467 569 468 napi_gro_receive(&info->mpipe[instance].napi, skb); 570 469 ··· 812 705 local_irq_restore(irqflags); 813 706 814 707 return HRTIMER_NORESTART; 708 + } 709 + 710 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 711 + 712 + /* PTP clock operations. */ 713 + 714 + static int ptp_mpipe_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 715 + { 716 + int ret = 0; 717 + struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps); 718 + mutex_lock(&md->ptp_lock); 719 + if (gxio_mpipe_adjust_timestamp_freq(&md->context, ppb)) 720 + ret = -EINVAL; 721 + mutex_unlock(&md->ptp_lock); 722 + return ret; 723 + } 724 + 725 + static int ptp_mpipe_adjtime(struct ptp_clock_info *ptp, s64 delta) 726 + { 727 + int ret = 0; 728 + struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps); 729 + mutex_lock(&md->ptp_lock); 730 + if (gxio_mpipe_adjust_timestamp(&md->context, delta)) 731 + ret = -EBUSY; 732 + mutex_unlock(&md->ptp_lock); 733 + return ret; 734 + } 735 + 736 + static int ptp_mpipe_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 737 + { 738 + int ret = 0; 739 + struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps); 740 + mutex_lock(&md->ptp_lock); 741 + if (gxio_mpipe_get_timestamp(&md->context, ts)) 742 + ret = -EBUSY; 743 + mutex_unlock(&md->ptp_lock); 744 + return ret; 745 + } 746 + 747 + static int ptp_mpipe_settime(struct ptp_clock_info *ptp, 748 + const struct timespec *ts) 749 + { 750 + int ret = 0; 751 + struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps); 752 + mutex_lock(&md->ptp_lock); 753 + if (gxio_mpipe_set_timestamp(&md->context, ts)) 754 + ret = -EBUSY; 755 + mutex_unlock(&md->ptp_lock); 756 + return ret; 757 + } 758 + 759 + static int ptp_mpipe_enable(struct ptp_clock_info *ptp, 760 + struct ptp_clock_request *request, int on) 761 + { 762 + return -EOPNOTSUPP; 763 + } 764 + 765 + static struct ptp_clock_info ptp_mpipe_caps = { 766 + .owner = THIS_MODULE, 767 + .name = "mPIPE clock", 768 + .max_adj = 999999999, 769 + .n_ext_ts = 0, 770 + .pps = 0, 771 + .adjfreq = ptp_mpipe_adjfreq, 772 + .adjtime = ptp_mpipe_adjtime, 773 + .gettime = ptp_mpipe_gettime, 774 + .settime = ptp_mpipe_settime, 775 + .enable = ptp_mpipe_enable, 776 + }; 777 + 778 + #endif /* CONFIG_PTP_1588_CLOCK_TILEGX */ 779 + 780 + /* Sync mPIPE's timestamp up with Linux system time and register PTP clock. */ 781 + static void register_ptp_clock(struct net_device *dev, struct mpipe_data *md) 782 + { 783 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 784 + struct timespec ts; 785 + 786 + getnstimeofday(&ts); 787 + gxio_mpipe_set_timestamp(&md->context, &ts); 788 + 789 + mutex_init(&md->ptp_lock); 790 + md->caps = ptp_mpipe_caps; 791 + md->ptp_clock = ptp_clock_register(&md->caps, NULL); 792 + if (IS_ERR(md->ptp_clock)) 793 + netdev_err(dev, "ptp_clock_register failed %ld\n", 794 + PTR_ERR(md->ptp_clock)); 795 + #endif 796 + } 797 + 798 + /* Initialize PTP fields in a new device. */ 799 + static void init_ptp_dev(struct tile_net_priv *priv) 800 + { 801 + #ifdef CONFIG_PTP_1588_CLOCK_TILEGX 802 + priv->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE; 803 + priv->stamp_cfg.tx_type = HWTSTAMP_TX_OFF; 804 + #endif 815 805 } 816 806 817 807 /* Helper functions for "tile_net_update()". */ ··· 1352 1148 rc = tile_net_setup_interrupts(dev); 1353 1149 if (rc != 0) 1354 1150 goto fail; 1151 + 1152 + /* Register PTP clock and set mPIPE timestamp, if configured. */ 1153 + register_ptp_clock(dev, md); 1355 1154 1356 1155 return 0; 1357 1156 ··· 2058 1851 for (i = 0; i < num_edescs; i++) 2059 1852 gxio_mpipe_equeue_put_at(equeue, edescs[i], slot++); 2060 1853 1854 + /* Store TX timestamp if needed. */ 1855 + tile_tx_timestamp(skb, instance); 1856 + 2061 1857 /* Add a completion record. */ 2062 1858 add_comp(equeue, comps, slot - 1, skb); 2063 1859 ··· 2095 1885 /* Ioctl commands. */ 2096 1886 static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 2097 1887 { 1888 + if (cmd == SIOCSHWTSTAMP) 1889 + return tile_hwtstamp_ioctl(dev, rq, cmd); 1890 + 2098 1891 return -EOPNOTSUPP; 2099 1892 } 2100 1893 ··· 2218 2005 priv->channel = -1; 2219 2006 priv->loopify_channel = -1; 2220 2007 priv->echannel = -1; 2008 + init_ptp_dev(priv); 2221 2009 2222 2010 /* Get the MAC address and set it in the device struct; this must 2223 2011 * be done before the device is opened. If the MAC is all zeroes,