vxge: add receive hardware timestamping
Jon Mason [Thu, 11 Nov 2010 04:25:58 +0000 (04:25 +0000)]
Add support for enable/disabling hardware timestamping on receive
packets via ioctl call.  When enabled, the hardware timestamp replaces
the FCS in the payload.

Signed-off-by: Jon Mason <jon.mason@exar.com>
Signed-off-by: Ram Vepa <ram.vepa@exar.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/vxge/vxge-main.c
drivers/net/vxge/vxge-main.h

index 10549bd..ea303a2 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
+#include <linux/net_tstamp.h>
 #include "vxge-main.h"
 #include "vxge-reg.h"
 
@@ -369,7 +370,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
                 u8 t_code, void *userdata)
 {
        struct vxge_ring *ring = (struct vxge_ring *)userdata;
-       struct  net_device *dev = ring->ndev;
+       struct net_device *dev = ring->ndev;
        unsigned int dma_sizes;
        void *first_dtr = NULL;
        int dtr_cnt = 0;
@@ -513,6 +514,16 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
                else
                        skb_checksum_none_assert(skb);
 
+
+               if (ring->rx_hwts) {
+                       struct skb_shared_hwtstamps *skb_hwts;
+                       u32 ns = *(u32 *)(skb->head + pkt_length);
+
+                       skb_hwts = skb_hwtstamps(skb);
+                       skb_hwts->hwtstamp = ns_to_ktime(ns);
+                       skb_hwts->syststamp.tv64 = 0;
+               }
+
                /* rth_hash_type and rth_it_hit are non-zero regardless of
                 * whether rss is enabled.  Only the rth_value is zero/non-zero
                 * if rss is disabled/enabled, so key off of that.
@@ -2037,6 +2048,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
                                vdev->config.fifo_indicate_max_pkts;
                        vpath->ring.rx_vector_no = 0;
                        vpath->ring.rx_csum = vdev->rx_csum;
+                       vpath->ring.rx_hwts = vdev->rx_hwts;
                        vpath->is_open = 1;
                        vdev->vp_handles[i] = vpath->handle;
                        vpath->ring.gro_enable = vdev->config.gro_enable;
@@ -2971,6 +2983,101 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
        return net_stats;
 }
 
+static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev,
+                                                int enable)
+{
+       enum vxge_hw_status status;
+       u64 val64;
+
+       /* Timestamp is passed to the driver via the FCS, therefore we
+        * must disable the FCS stripping by the adapter.  Since this is
+        * required for the driver to load (due to a hardware bug),
+        * there is no need to do anything special here.
+        */
+       if (enable)
+               val64 = VXGE_HW_XMAC_TIMESTAMP_EN |
+                       VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) |
+                       VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0);
+       else
+               val64 = 0;
+
+       status = vxge_hw_mgmt_reg_write(vdev->devh,
+                                       vxge_hw_mgmt_reg_type_mrpcim,
+                                       0,
+                                       offsetof(struct vxge_hw_mrpcim_reg,
+                                                xmac_timestamp),
+                                       val64);
+       vxge_hw_device_flush_io(vdev->devh);
+       return status;
+}
+
+static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data)
+{
+       struct hwtstamp_config config;
+       enum vxge_hw_status status;
+       int i;
+
+       if (copy_from_user(&config, data, sizeof(config)))
+               return -EFAULT;
+
+       /* reserved for future extensions */
+       if (config.flags)
+               return -EINVAL;
+
+       /* Transmit HW Timestamp not supported */
+       switch (config.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               break;
+       case HWTSTAMP_TX_ON:
+       default:
+               return -ERANGE;
+       }
+
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               status = vxge_timestamp_config(vdev, 0);
+               if (status != VXGE_HW_OK)
+                       return -EFAULT;
+
+               vdev->rx_hwts = 0;
+               config.rx_filter = HWTSTAMP_FILTER_NONE;
+               break;
+
+       case HWTSTAMP_FILTER_ALL:
+       case HWTSTAMP_FILTER_SOME:
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               status = vxge_timestamp_config(vdev, 1);
+               if (status != VXGE_HW_OK)
+                       return -EFAULT;
+
+               vdev->rx_hwts = 1;
+               config.rx_filter = HWTSTAMP_FILTER_ALL;
+               break;
+
+       default:
+                return -ERANGE;
+       }
+
+       for (i = 0; i < vdev->no_of_vpath; i++)
+               vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts;
+
+       if (copy_to_user(data, &config, sizeof(config)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /**
  * vxge_ioctl
  * @dev: Device pointer.
@@ -2983,7 +3090,20 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
  */
 static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       return -EOPNOTSUPP;
+       struct vxgedev *vdev = netdev_priv(dev);
+       int ret;
+
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+               ret = vxge_hwtstamp_ioctl(vdev, rq->ifr_data);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
 }
 
 /**
@@ -3180,6 +3300,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
        vdev->pdev = hldev->pdev;
        memcpy(&vdev->config, config, sizeof(struct vxge_config));
        vdev->rx_csum = 1;      /* Enable Rx CSUM by default. */
+       vdev->rx_hwts = 0;
 
        SET_NETDEV_DEV(ndev, &vdev->pdev->dev);
 
@@ -4321,10 +4442,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        }
 
        /* if FCS stripping is not disabled in MAC fail driver load */
-       if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: FCS stripping is not disabled in MAC"
-                       " failing driver load", VXGE_DRIVER_NAME);
+       status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC"
+                               " failing driver load", VXGE_DRIVER_NAME);
                ret = -EINVAL;
                goto _exit4;
        }
index 1699d75..6f6e9ce 100644 (file)
@@ -248,8 +248,9 @@ struct vxge_ring {
         */
        int driver_id;
 
-        /* copy of the flag indicating whether rx_csum is to be used */
-       u32 rx_csum;
+       /* copy of the flag indicating whether rx_csum is to be used */
+       u32 rx_csum:1,
+           rx_hwts:1;
 
        int pkts_processed;
        int budget;
@@ -327,7 +328,8 @@ struct vxgedev {
        u16             all_multi_flg;
 
         /* A flag indicating whether rx_csum is to be used or not. */
-       u32     rx_csum;
+       u32     rx_csum:1,
+               rx_hwts:1;
 
        struct vxge_msix_entry *vxge_entries;
        struct msix_entry *entries;