diff options
author | Jon Mason <jon.mason@exar.com> | 2010-11-10 23:25:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-11 12:30:21 -0500 |
commit | b81b37338412e3215670641e5025c85146521dea (patch) | |
tree | b6a4a1280223e21d5108cde1a9377d98653b44d7 /drivers/net/vxge/vxge-main.c | |
parent | e8ac175615b9458a00193c55617b5b8865e67817 (diff) |
vxge: add receive hardware timestamping
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>
Diffstat (limited to 'drivers/net/vxge/vxge-main.c')
-rw-r--r-- | drivers/net/vxge/vxge-main.c | 133 |
1 files changed, 127 insertions, 6 deletions
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 10549bd39221..ea303a2af3aa 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/netdevice.h> | 51 | #include <linux/netdevice.h> |
52 | #include <linux/etherdevice.h> | 52 | #include <linux/etherdevice.h> |
53 | #include <linux/firmware.h> | 53 | #include <linux/firmware.h> |
54 | #include <linux/net_tstamp.h> | ||
54 | #include "vxge-main.h" | 55 | #include "vxge-main.h" |
55 | #include "vxge-reg.h" | 56 | #include "vxge-reg.h" |
56 | 57 | ||
@@ -369,7 +370,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, | |||
369 | u8 t_code, void *userdata) | 370 | u8 t_code, void *userdata) |
370 | { | 371 | { |
371 | struct vxge_ring *ring = (struct vxge_ring *)userdata; | 372 | struct vxge_ring *ring = (struct vxge_ring *)userdata; |
372 | struct net_device *dev = ring->ndev; | 373 | struct net_device *dev = ring->ndev; |
373 | unsigned int dma_sizes; | 374 | unsigned int dma_sizes; |
374 | void *first_dtr = NULL; | 375 | void *first_dtr = NULL; |
375 | int dtr_cnt = 0; | 376 | int dtr_cnt = 0; |
@@ -513,6 +514,16 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, | |||
513 | else | 514 | else |
514 | skb_checksum_none_assert(skb); | 515 | skb_checksum_none_assert(skb); |
515 | 516 | ||
517 | |||
518 | if (ring->rx_hwts) { | ||
519 | struct skb_shared_hwtstamps *skb_hwts; | ||
520 | u32 ns = *(u32 *)(skb->head + pkt_length); | ||
521 | |||
522 | skb_hwts = skb_hwtstamps(skb); | ||
523 | skb_hwts->hwtstamp = ns_to_ktime(ns); | ||
524 | skb_hwts->syststamp.tv64 = 0; | ||
525 | } | ||
526 | |||
516 | /* rth_hash_type and rth_it_hit are non-zero regardless of | 527 | /* rth_hash_type and rth_it_hit are non-zero regardless of |
517 | * whether rss is enabled. Only the rth_value is zero/non-zero | 528 | * whether rss is enabled. Only the rth_value is zero/non-zero |
518 | * if rss is disabled/enabled, so key off of that. | 529 | * if rss is disabled/enabled, so key off of that. |
@@ -2037,6 +2048,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev) | |||
2037 | vdev->config.fifo_indicate_max_pkts; | 2048 | vdev->config.fifo_indicate_max_pkts; |
2038 | vpath->ring.rx_vector_no = 0; | 2049 | vpath->ring.rx_vector_no = 0; |
2039 | vpath->ring.rx_csum = vdev->rx_csum; | 2050 | vpath->ring.rx_csum = vdev->rx_csum; |
2051 | vpath->ring.rx_hwts = vdev->rx_hwts; | ||
2040 | vpath->is_open = 1; | 2052 | vpath->is_open = 1; |
2041 | vdev->vp_handles[i] = vpath->handle; | 2053 | vdev->vp_handles[i] = vpath->handle; |
2042 | vpath->ring.gro_enable = vdev->config.gro_enable; | 2054 | 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) | |||
2971 | return net_stats; | 2983 | return net_stats; |
2972 | } | 2984 | } |
2973 | 2985 | ||
2986 | static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, | ||
2987 | int enable) | ||
2988 | { | ||
2989 | enum vxge_hw_status status; | ||
2990 | u64 val64; | ||
2991 | |||
2992 | /* Timestamp is passed to the driver via the FCS, therefore we | ||
2993 | * must disable the FCS stripping by the adapter. Since this is | ||
2994 | * required for the driver to load (due to a hardware bug), | ||
2995 | * there is no need to do anything special here. | ||
2996 | */ | ||
2997 | if (enable) | ||
2998 | val64 = VXGE_HW_XMAC_TIMESTAMP_EN | | ||
2999 | VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | | ||
3000 | VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); | ||
3001 | else | ||
3002 | val64 = 0; | ||
3003 | |||
3004 | status = vxge_hw_mgmt_reg_write(vdev->devh, | ||
3005 | vxge_hw_mgmt_reg_type_mrpcim, | ||
3006 | 0, | ||
3007 | offsetof(struct vxge_hw_mrpcim_reg, | ||
3008 | xmac_timestamp), | ||
3009 | val64); | ||
3010 | vxge_hw_device_flush_io(vdev->devh); | ||
3011 | return status; | ||
3012 | } | ||
3013 | |||
3014 | static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) | ||
3015 | { | ||
3016 | struct hwtstamp_config config; | ||
3017 | enum vxge_hw_status status; | ||
3018 | int i; | ||
3019 | |||
3020 | if (copy_from_user(&config, data, sizeof(config))) | ||
3021 | return -EFAULT; | ||
3022 | |||
3023 | /* reserved for future extensions */ | ||
3024 | if (config.flags) | ||
3025 | return -EINVAL; | ||
3026 | |||
3027 | /* Transmit HW Timestamp not supported */ | ||
3028 | switch (config.tx_type) { | ||
3029 | case HWTSTAMP_TX_OFF: | ||
3030 | break; | ||
3031 | case HWTSTAMP_TX_ON: | ||
3032 | default: | ||
3033 | return -ERANGE; | ||
3034 | } | ||
3035 | |||
3036 | switch (config.rx_filter) { | ||
3037 | case HWTSTAMP_FILTER_NONE: | ||
3038 | status = vxge_timestamp_config(vdev, 0); | ||
3039 | if (status != VXGE_HW_OK) | ||
3040 | return -EFAULT; | ||
3041 | |||
3042 | vdev->rx_hwts = 0; | ||
3043 | config.rx_filter = HWTSTAMP_FILTER_NONE; | ||
3044 | break; | ||
3045 | |||
3046 | case HWTSTAMP_FILTER_ALL: | ||
3047 | case HWTSTAMP_FILTER_SOME: | ||
3048 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
3049 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
3050 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
3051 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
3052 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
3053 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
3054 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
3055 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
3056 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
3057 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
3058 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
3059 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
3060 | status = vxge_timestamp_config(vdev, 1); | ||
3061 | if (status != VXGE_HW_OK) | ||
3062 | return -EFAULT; | ||
3063 | |||
3064 | vdev->rx_hwts = 1; | ||
3065 | config.rx_filter = HWTSTAMP_FILTER_ALL; | ||
3066 | break; | ||
3067 | |||
3068 | default: | ||
3069 | return -ERANGE; | ||
3070 | } | ||
3071 | |||
3072 | for (i = 0; i < vdev->no_of_vpath; i++) | ||
3073 | vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts; | ||
3074 | |||
3075 | if (copy_to_user(data, &config, sizeof(config))) | ||
3076 | return -EFAULT; | ||
3077 | |||
3078 | return 0; | ||
3079 | } | ||
3080 | |||
2974 | /** | 3081 | /** |
2975 | * vxge_ioctl | 3082 | * vxge_ioctl |
2976 | * @dev: Device pointer. | 3083 | * @dev: Device pointer. |
@@ -2983,7 +3090,20 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) | |||
2983 | */ | 3090 | */ |
2984 | static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 3091 | static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
2985 | { | 3092 | { |
2986 | return -EOPNOTSUPP; | 3093 | struct vxgedev *vdev = netdev_priv(dev); |
3094 | int ret; | ||
3095 | |||
3096 | switch (cmd) { | ||
3097 | case SIOCSHWTSTAMP: | ||
3098 | ret = vxge_hwtstamp_ioctl(vdev, rq->ifr_data); | ||
3099 | if (ret) | ||
3100 | return ret; | ||
3101 | break; | ||
3102 | default: | ||
3103 | return -EOPNOTSUPP; | ||
3104 | } | ||
3105 | |||
3106 | return 0; | ||
2987 | } | 3107 | } |
2988 | 3108 | ||
2989 | /** | 3109 | /** |
@@ -3180,6 +3300,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, | |||
3180 | vdev->pdev = hldev->pdev; | 3300 | vdev->pdev = hldev->pdev; |
3181 | memcpy(&vdev->config, config, sizeof(struct vxge_config)); | 3301 | memcpy(&vdev->config, config, sizeof(struct vxge_config)); |
3182 | vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ | 3302 | vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ |
3303 | vdev->rx_hwts = 0; | ||
3183 | 3304 | ||
3184 | SET_NETDEV_DEV(ndev, &vdev->pdev->dev); | 3305 | SET_NETDEV_DEV(ndev, &vdev->pdev->dev); |
3185 | 3306 | ||
@@ -4321,10 +4442,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4321 | } | 4442 | } |
4322 | 4443 | ||
4323 | /* if FCS stripping is not disabled in MAC fail driver load */ | 4444 | /* if FCS stripping is not disabled in MAC fail driver load */ |
4324 | if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) { | 4445 | status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask); |
4325 | vxge_debug_init(VXGE_ERR, | 4446 | if (status != VXGE_HW_OK) { |
4326 | "%s: FCS stripping is not disabled in MAC" | 4447 | vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC" |
4327 | " failing driver load", VXGE_DRIVER_NAME); | 4448 | " failing driver load", VXGE_DRIVER_NAME); |
4328 | ret = -EINVAL; | 4449 | ret = -EINVAL; |
4329 | goto _exit4; | 4450 | goto _exit4; |
4330 | } | 4451 | } |