diff options
author | Amir Vadai <amirv@mellanox.com> | 2013-04-23 02:06:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-24 16:30:14 -0400 |
commit | ec693d47010e8302e61e0bdf3f47496c5610641a (patch) | |
tree | 8fbcfe632cb618318dcb1c9a9050afd025462b0a /drivers/net/ethernet/mellanox | |
parent | ddd8a6c12d7e494902a9435a9a7a543ef730b2d8 (diff) |
net/mlx4_en: Add HW timestamping (TS) support
The patch allows to enable/disable HW timestamping for incoming and/or
outgoing packets. It adds and initializes all structs and callbacks
needed by kernel TS API.
To enable/disable HW timestamping appropriate ioctl should be used.
Currently HWTSTAMP_FILTER_ALL/NONE and HWTSAMP_TX_ON/OFF only are
supported.
When enabling TS on receive flow - VLAN stripping will be disabled.
Also were made all relevant changes in RX/TX flows to consider TS request
and plant HW timestamps into relevant structures.
mlx4_ib was fixed to compile with new mlx4_cq_alloc() signature.
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cq.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_clock.c | 132 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_cq.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 30 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_main.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 75 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_resources.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_rx.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_tx.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/main.c | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 21 |
12 files changed, 353 insertions, 15 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile index 293127d28b33..3e9c70f15b42 100644 --- a/drivers/net/ethernet/mellanox/mlx4/Makefile +++ b/drivers/net/ethernet/mellanox/mlx4/Makefile | |||
@@ -6,5 +6,5 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ | |||
6 | obj-$(CONFIG_MLX4_EN) += mlx4_en.o | 6 | obj-$(CONFIG_MLX4_EN) += mlx4_en.o |
7 | 7 | ||
8 | mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ | 8 | mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ |
9 | en_resources.o en_netdev.o en_selftest.o | 9 | en_resources.o en_netdev.o en_selftest.o en_clock.o |
10 | mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o | 10 | mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o |
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 0706623cfb96..004e4231af67 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c | |||
@@ -240,9 +240,10 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) | |||
240 | __mlx4_cq_free_icm(dev, cqn); | 240 | __mlx4_cq_free_icm(dev, cqn); |
241 | } | 241 | } |
242 | 242 | ||
243 | int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, | 243 | int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, |
244 | struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, | 244 | struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, |
245 | unsigned vector, int collapsed) | 245 | struct mlx4_cq *cq, unsigned vector, int collapsed, |
246 | int timestamp_en) | ||
246 | { | 247 | { |
247 | struct mlx4_priv *priv = mlx4_priv(dev); | 248 | struct mlx4_priv *priv = mlx4_priv(dev); |
248 | struct mlx4_cq_table *cq_table = &priv->cq_table; | 249 | struct mlx4_cq_table *cq_table = &priv->cq_table; |
@@ -276,6 +277,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, | |||
276 | memset(cq_context, 0, sizeof *cq_context); | 277 | memset(cq_context, 0, sizeof *cq_context); |
277 | 278 | ||
278 | cq_context->flags = cpu_to_be32(!!collapsed << 18); | 279 | cq_context->flags = cpu_to_be32(!!collapsed << 18); |
280 | if (timestamp_en) | ||
281 | cq_context->flags |= cpu_to_be32(1 << 19); | ||
282 | |||
279 | cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); | 283 | cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); |
280 | cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; | 284 | cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; |
281 | cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; | 285 | cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c new file mode 100644 index 000000000000..501c72f1fbeb --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Mellanox Technologies. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/mlx4/device.h> | ||
35 | |||
36 | #include "mlx4_en.h" | ||
37 | |||
38 | int mlx4_en_timestamp_config(struct net_device *dev, int tx_type, int rx_filter) | ||
39 | { | ||
40 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
41 | struct mlx4_en_dev *mdev = priv->mdev; | ||
42 | int port_up = 0; | ||
43 | int err = 0; | ||
44 | |||
45 | mutex_lock(&mdev->state_lock); | ||
46 | if (priv->port_up) { | ||
47 | port_up = 1; | ||
48 | mlx4_en_stop_port(dev, 1); | ||
49 | } | ||
50 | |||
51 | mlx4_en_free_resources(priv); | ||
52 | |||
53 | en_warn(priv, "Changing Time Stamp configuration\n"); | ||
54 | |||
55 | priv->hwtstamp_config.tx_type = tx_type; | ||
56 | priv->hwtstamp_config.rx_filter = rx_filter; | ||
57 | |||
58 | if (rx_filter != HWTSTAMP_FILTER_NONE) | ||
59 | dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; | ||
60 | else | ||
61 | dev->features |= NETIF_F_HW_VLAN_CTAG_RX; | ||
62 | |||
63 | err = mlx4_en_alloc_resources(priv); | ||
64 | if (err) { | ||
65 | en_err(priv, "Failed reallocating port resources\n"); | ||
66 | goto out; | ||
67 | } | ||
68 | if (port_up) { | ||
69 | err = mlx4_en_start_port(dev); | ||
70 | if (err) | ||
71 | en_err(priv, "Failed starting port\n"); | ||
72 | } | ||
73 | |||
74 | out: | ||
75 | mutex_unlock(&mdev->state_lock); | ||
76 | netdev_features_change(dev); | ||
77 | return err; | ||
78 | } | ||
79 | |||
80 | /* mlx4_en_read_clock - read raw cycle counter (to be used by time counter) | ||
81 | */ | ||
82 | static cycle_t mlx4_en_read_clock(const struct cyclecounter *tc) | ||
83 | { | ||
84 | struct mlx4_en_dev *mdev = | ||
85 | container_of(tc, struct mlx4_en_dev, cycles); | ||
86 | struct mlx4_dev *dev = mdev->dev; | ||
87 | |||
88 | return mlx4_read_clock(dev) & tc->mask; | ||
89 | } | ||
90 | |||
91 | u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe) | ||
92 | { | ||
93 | u64 hi, lo; | ||
94 | struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe; | ||
95 | |||
96 | lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo); | ||
97 | hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16; | ||
98 | |||
99 | return hi | lo; | ||
100 | } | ||
101 | |||
102 | void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev, | ||
103 | struct skb_shared_hwtstamps *hwts, | ||
104 | u64 timestamp) | ||
105 | { | ||
106 | u64 nsec; | ||
107 | |||
108 | nsec = timecounter_cyc2time(&mdev->clock, timestamp); | ||
109 | |||
110 | memset(hwts, 0, sizeof(struct skb_shared_hwtstamps)); | ||
111 | hwts->hwtstamp = ns_to_ktime(nsec); | ||
112 | } | ||
113 | |||
114 | void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) | ||
115 | { | ||
116 | struct mlx4_dev *dev = mdev->dev; | ||
117 | |||
118 | memset(&mdev->cycles, 0, sizeof(mdev->cycles)); | ||
119 | mdev->cycles.read = mlx4_en_read_clock; | ||
120 | mdev->cycles.mask = CLOCKSOURCE_MASK(48); | ||
121 | /* Using shift to make calculation more accurate. Since current HW | ||
122 | * clock frequency is 427 MHz, and cycles are given using a 48 bits | ||
123 | * register, the biggest shift when calculating using u64, is 14 | ||
124 | * (max_cycles * multiplier < 2^64) | ||
125 | */ | ||
126 | mdev->cycles.shift = 14; | ||
127 | mdev->cycles.mult = | ||
128 | clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift); | ||
129 | |||
130 | timecounter_init(&mdev->clock, &mdev->cycles, | ||
131 | ktime_to_ns(ktime_get_real())); | ||
132 | } | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index b8d0854a7ad1..1e6c594d6d04 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c | |||
@@ -77,6 +77,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, | |||
77 | struct mlx4_en_dev *mdev = priv->mdev; | 77 | struct mlx4_en_dev *mdev = priv->mdev; |
78 | int err = 0; | 78 | int err = 0; |
79 | char name[25]; | 79 | char name[25]; |
80 | int timestamp_en = 0; | ||
80 | struct cpu_rmap *rmap = | 81 | struct cpu_rmap *rmap = |
81 | #ifdef CONFIG_RFS_ACCEL | 82 | #ifdef CONFIG_RFS_ACCEL |
82 | priv->dev->rx_cpu_rmap; | 83 | priv->dev->rx_cpu_rmap; |
@@ -123,8 +124,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, | |||
123 | if (!cq->is_tx) | 124 | if (!cq->is_tx) |
124 | cq->size = priv->rx_ring[cq->ring].actual_size; | 125 | cq->size = priv->rx_ring[cq->ring].actual_size; |
125 | 126 | ||
126 | err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, | 127 | if ((cq->is_tx && priv->hwtstamp_config.tx_type) || |
127 | cq->wqres.db.dma, &cq->mcq, cq->vector, 0); | 128 | (!cq->is_tx && priv->hwtstamp_config.rx_filter)) |
129 | timestamp_en = 1; | ||
130 | |||
131 | err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, | ||
132 | &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, | ||
133 | cq->vector, 0, timestamp_en); | ||
128 | if (err) | 134 | if (err) |
129 | return err; | 135 | return err; |
130 | 136 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 00f25b5f297f..bcf4d118e98c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | |||
@@ -1147,6 +1147,35 @@ out: | |||
1147 | return err; | 1147 | return err; |
1148 | } | 1148 | } |
1149 | 1149 | ||
1150 | static int mlx4_en_get_ts_info(struct net_device *dev, | ||
1151 | struct ethtool_ts_info *info) | ||
1152 | { | ||
1153 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
1154 | struct mlx4_en_dev *mdev = priv->mdev; | ||
1155 | int ret; | ||
1156 | |||
1157 | ret = ethtool_op_get_ts_info(dev, info); | ||
1158 | if (ret) | ||
1159 | return ret; | ||
1160 | |||
1161 | if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) { | ||
1162 | info->so_timestamping |= | ||
1163 | SOF_TIMESTAMPING_TX_HARDWARE | | ||
1164 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
1165 | SOF_TIMESTAMPING_RAW_HARDWARE; | ||
1166 | |||
1167 | info->tx_types = | ||
1168 | (1 << HWTSTAMP_TX_OFF) | | ||
1169 | (1 << HWTSTAMP_TX_ON); | ||
1170 | |||
1171 | info->rx_filters = | ||
1172 | (1 << HWTSTAMP_FILTER_NONE) | | ||
1173 | (1 << HWTSTAMP_FILTER_ALL); | ||
1174 | } | ||
1175 | |||
1176 | return ret; | ||
1177 | } | ||
1178 | |||
1150 | const struct ethtool_ops mlx4_en_ethtool_ops = { | 1179 | const struct ethtool_ops mlx4_en_ethtool_ops = { |
1151 | .get_drvinfo = mlx4_en_get_drvinfo, | 1180 | .get_drvinfo = mlx4_en_get_drvinfo, |
1152 | .get_settings = mlx4_en_get_settings, | 1181 | .get_settings = mlx4_en_get_settings, |
@@ -1173,6 +1202,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | |||
1173 | .set_rxfh_indir = mlx4_en_set_rxfh_indir, | 1202 | .set_rxfh_indir = mlx4_en_set_rxfh_indir, |
1174 | .get_channels = mlx4_en_get_channels, | 1203 | .get_channels = mlx4_en_get_channels, |
1175 | .set_channels = mlx4_en_set_channels, | 1204 | .set_channels = mlx4_en_set_channels, |
1205 | .get_ts_info = mlx4_en_get_ts_info, | ||
1176 | }; | 1206 | }; |
1177 | 1207 | ||
1178 | 1208 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index fc27800e9c38..a5c9df07a7d0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c | |||
@@ -300,6 +300,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev) | |||
300 | if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) | 300 | if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) |
301 | mdev->pndev[i] = NULL; | 301 | mdev->pndev[i] = NULL; |
302 | } | 302 | } |
303 | |||
304 | /* Initialize time stamp mechanism */ | ||
305 | if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) | ||
306 | mlx4_en_init_timestamp(mdev); | ||
307 | |||
303 | return mdev; | 308 | return mdev; |
304 | 309 | ||
305 | err_mr: | 310 | err_mr: |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e7e27842d8d4..4cb9f3203973 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c | |||
@@ -1916,6 +1916,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) | |||
1916 | return 0; | 1916 | return 0; |
1917 | } | 1917 | } |
1918 | 1918 | ||
1919 | static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) | ||
1920 | { | ||
1921 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
1922 | struct mlx4_en_dev *mdev = priv->mdev; | ||
1923 | struct hwtstamp_config config; | ||
1924 | |||
1925 | if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) | ||
1926 | return -EFAULT; | ||
1927 | |||
1928 | /* reserved for future extensions */ | ||
1929 | if (config.flags) | ||
1930 | return -EINVAL; | ||
1931 | |||
1932 | /* device doesn't support time stamping */ | ||
1933 | if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)) | ||
1934 | return -EINVAL; | ||
1935 | |||
1936 | /* TX HW timestamp */ | ||
1937 | switch (config.tx_type) { | ||
1938 | case HWTSTAMP_TX_OFF: | ||
1939 | case HWTSTAMP_TX_ON: | ||
1940 | break; | ||
1941 | default: | ||
1942 | return -ERANGE; | ||
1943 | } | ||
1944 | |||
1945 | /* RX HW timestamp */ | ||
1946 | switch (config.rx_filter) { | ||
1947 | case HWTSTAMP_FILTER_NONE: | ||
1948 | break; | ||
1949 | case HWTSTAMP_FILTER_ALL: | ||
1950 | case HWTSTAMP_FILTER_SOME: | ||
1951 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
1952 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
1953 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
1954 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
1955 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
1956 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
1957 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
1958 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
1959 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
1960 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
1961 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
1962 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
1963 | config.rx_filter = HWTSTAMP_FILTER_ALL; | ||
1964 | break; | ||
1965 | default: | ||
1966 | return -ERANGE; | ||
1967 | } | ||
1968 | |||
1969 | if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) { | ||
1970 | config.tx_type = HWTSTAMP_TX_OFF; | ||
1971 | config.rx_filter = HWTSTAMP_FILTER_NONE; | ||
1972 | } | ||
1973 | |||
1974 | return copy_to_user(ifr->ifr_data, &config, | ||
1975 | sizeof(config)) ? -EFAULT : 0; | ||
1976 | } | ||
1977 | |||
1978 | static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1979 | { | ||
1980 | switch (cmd) { | ||
1981 | case SIOCSHWTSTAMP: | ||
1982 | return mlx4_en_hwtstamp_ioctl(dev, ifr); | ||
1983 | default: | ||
1984 | return -EOPNOTSUPP; | ||
1985 | } | ||
1986 | } | ||
1987 | |||
1919 | static int mlx4_en_set_features(struct net_device *netdev, | 1988 | static int mlx4_en_set_features(struct net_device *netdev, |
1920 | netdev_features_t features) | 1989 | netdev_features_t features) |
1921 | { | 1990 | { |
@@ -1943,6 +2012,7 @@ static const struct net_device_ops mlx4_netdev_ops = { | |||
1943 | .ndo_set_mac_address = mlx4_en_set_mac, | 2012 | .ndo_set_mac_address = mlx4_en_set_mac, |
1944 | .ndo_validate_addr = eth_validate_addr, | 2013 | .ndo_validate_addr = eth_validate_addr, |
1945 | .ndo_change_mtu = mlx4_en_change_mtu, | 2014 | .ndo_change_mtu = mlx4_en_change_mtu, |
2015 | .ndo_do_ioctl = mlx4_en_ioctl, | ||
1946 | .ndo_tx_timeout = mlx4_en_tx_timeout, | 2016 | .ndo_tx_timeout = mlx4_en_tx_timeout, |
1947 | .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, | 2017 | .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, |
1948 | .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, | 2018 | .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, |
@@ -2054,6 +2124,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
2054 | spin_lock_init(&priv->filters_lock); | 2124 | spin_lock_init(&priv->filters_lock); |
2055 | #endif | 2125 | #endif |
2056 | 2126 | ||
2127 | /* Initialize time stamping config */ | ||
2128 | priv->hwtstamp_config.flags = 0; | ||
2129 | priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF; | ||
2130 | priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; | ||
2131 | |||
2057 | /* Allocate page for receive rings */ | 2132 | /* Allocate page for receive rings */ |
2058 | err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, | 2133 | err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, |
2059 | MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); | 2134 | MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c index 10c24c784b70..91f2b2c43c12 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c | |||
@@ -42,6 +42,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, | |||
42 | int user_prio, struct mlx4_qp_context *context) | 42 | int user_prio, struct mlx4_qp_context *context) |
43 | { | 43 | { |
44 | struct mlx4_en_dev *mdev = priv->mdev; | 44 | struct mlx4_en_dev *mdev = priv->mdev; |
45 | struct net_device *dev = priv->dev; | ||
45 | 46 | ||
46 | memset(context, 0, sizeof *context); | 47 | memset(context, 0, sizeof *context); |
47 | context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET); | 48 | context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET); |
@@ -65,6 +66,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, | |||
65 | context->cqn_send = cpu_to_be32(cqn); | 66 | context->cqn_send = cpu_to_be32(cqn); |
66 | context->cqn_recv = cpu_to_be32(cqn); | 67 | context->cqn_recv = cpu_to_be32(cqn); |
67 | context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); | 68 | context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); |
69 | if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX)) | ||
70 | context->param3 |= cpu_to_be32(1 << 30); | ||
68 | } | 71 | } |
69 | 72 | ||
70 | 73 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 4006f8857cb5..02aee1ebd203 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c | |||
@@ -320,6 +320,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, | |||
320 | } | 320 | } |
321 | ring->buf = ring->wqres.buf.direct.buf; | 321 | ring->buf = ring->wqres.buf.direct.buf; |
322 | 322 | ||
323 | ring->hwtstamp_rx_filter = priv->hwtstamp_config.rx_filter; | ||
324 | |||
323 | return 0; | 325 | return 0; |
324 | 326 | ||
325 | err_hwq: | 327 | err_hwq: |
@@ -554,6 +556,7 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv, | |||
554 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) | 556 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) |
555 | { | 557 | { |
556 | struct mlx4_en_priv *priv = netdev_priv(dev); | 558 | struct mlx4_en_priv *priv = netdev_priv(dev); |
559 | struct mlx4_en_dev *mdev = priv->mdev; | ||
557 | struct mlx4_cqe *cqe; | 560 | struct mlx4_cqe *cqe; |
558 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; | 561 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; |
559 | struct mlx4_en_rx_alloc *frags; | 562 | struct mlx4_en_rx_alloc *frags; |
@@ -565,6 +568,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
565 | int polled = 0; | 568 | int polled = 0; |
566 | int ip_summed; | 569 | int ip_summed; |
567 | int factor = priv->cqe_factor; | 570 | int factor = priv->cqe_factor; |
571 | u64 timestamp; | ||
568 | 572 | ||
569 | if (!priv->port_up) | 573 | if (!priv->port_up) |
570 | return 0; | 574 | return 0; |
@@ -669,8 +673,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
669 | gro_skb->data_len = length; | 673 | gro_skb->data_len = length; |
670 | gro_skb->ip_summed = CHECKSUM_UNNECESSARY; | 674 | gro_skb->ip_summed = CHECKSUM_UNNECESSARY; |
671 | 675 | ||
672 | if (cqe->vlan_my_qpn & | 676 | if ((cqe->vlan_my_qpn & |
673 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) { | 677 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) && |
678 | (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) { | ||
674 | u16 vid = be16_to_cpu(cqe->sl_vid); | 679 | u16 vid = be16_to_cpu(cqe->sl_vid); |
675 | 680 | ||
676 | __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); | 681 | __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); |
@@ -680,8 +685,15 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
680 | gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); | 685 | gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); |
681 | 686 | ||
682 | skb_record_rx_queue(gro_skb, cq->ring); | 687 | skb_record_rx_queue(gro_skb, cq->ring); |
683 | napi_gro_frags(&cq->napi); | ||
684 | 688 | ||
689 | if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) { | ||
690 | timestamp = mlx4_en_get_cqe_ts(cqe); | ||
691 | mlx4_en_fill_hwtstamps(mdev, | ||
692 | skb_hwtstamps(gro_skb), | ||
693 | timestamp); | ||
694 | } | ||
695 | |||
696 | napi_gro_frags(&cq->napi); | ||
685 | goto next; | 697 | goto next; |
686 | } | 698 | } |
687 | 699 | ||
@@ -714,10 +726,17 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
714 | if (dev->features & NETIF_F_RXHASH) | 726 | if (dev->features & NETIF_F_RXHASH) |
715 | skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); | 727 | skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); |
716 | 728 | ||
717 | if (be32_to_cpu(cqe->vlan_my_qpn) & | 729 | if ((be32_to_cpu(cqe->vlan_my_qpn) & |
718 | MLX4_CQE_VLAN_PRESENT_MASK) | 730 | MLX4_CQE_VLAN_PRESENT_MASK) && |
731 | (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) | ||
719 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); | 732 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); |
720 | 733 | ||
734 | if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) { | ||
735 | timestamp = mlx4_en_get_cqe_ts(cqe); | ||
736 | mlx4_en_fill_hwtstamps(mdev, skb_hwtstamps(skb), | ||
737 | timestamp); | ||
738 | } | ||
739 | |||
721 | /* Push it up the stack */ | 740 | /* Push it up the stack */ |
722 | netif_receive_skb(skb); | 741 | netif_receive_skb(skb); |
723 | 742 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 49308cc65ee7..b0a2d2b96e43 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c | |||
@@ -118,6 +118,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, | |||
118 | } else | 118 | } else |
119 | ring->bf_enabled = true; | 119 | ring->bf_enabled = true; |
120 | 120 | ||
121 | ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type; | ||
122 | |||
121 | return 0; | 123 | return 0; |
122 | 124 | ||
123 | err_map: | 125 | err_map: |
@@ -192,8 +194,9 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, | |||
192 | 194 | ||
193 | static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, | 195 | static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, |
194 | struct mlx4_en_tx_ring *ring, | 196 | struct mlx4_en_tx_ring *ring, |
195 | int index, u8 owner) | 197 | int index, u8 owner, u64 timestamp) |
196 | { | 198 | { |
199 | struct mlx4_en_dev *mdev = priv->mdev; | ||
197 | struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; | 200 | struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; |
198 | struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; | 201 | struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; |
199 | struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; | 202 | struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; |
@@ -204,6 +207,12 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, | |||
204 | int i; | 207 | int i; |
205 | __be32 *ptr = (__be32 *)tx_desc; | 208 | __be32 *ptr = (__be32 *)tx_desc; |
206 | __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); | 209 | __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); |
210 | struct skb_shared_hwtstamps hwts; | ||
211 | |||
212 | if (timestamp) { | ||
213 | mlx4_en_fill_hwtstamps(mdev, &hwts, timestamp); | ||
214 | skb_tstamp_tx(skb, &hwts); | ||
215 | } | ||
207 | 216 | ||
208 | /* Optimize the common case when there are no wraparounds */ | 217 | /* Optimize the common case when there are no wraparounds */ |
209 | if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { | 218 | if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { |
@@ -289,7 +298,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) | |||
289 | while (ring->cons != ring->prod) { | 298 | while (ring->cons != ring->prod) { |
290 | ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, | 299 | ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, |
291 | ring->cons & ring->size_mask, | 300 | ring->cons & ring->size_mask, |
292 | !!(ring->cons & ring->size)); | 301 | !!(ring->cons & ring->size), 0); |
293 | ring->cons += ring->last_nr_txbb; | 302 | ring->cons += ring->last_nr_txbb; |
294 | cnt++; | 303 | cnt++; |
295 | } | 304 | } |
@@ -318,6 +327,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) | |||
318 | u32 packets = 0; | 327 | u32 packets = 0; |
319 | u32 bytes = 0; | 328 | u32 bytes = 0; |
320 | int factor = priv->cqe_factor; | 329 | int factor = priv->cqe_factor; |
330 | u64 timestamp = 0; | ||
321 | 331 | ||
322 | if (!priv->port_up) | 332 | if (!priv->port_up) |
323 | return; | 333 | return; |
@@ -341,11 +351,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) | |||
341 | do { | 351 | do { |
342 | txbbs_skipped += ring->last_nr_txbb; | 352 | txbbs_skipped += ring->last_nr_txbb; |
343 | ring_index = (ring_index + ring->last_nr_txbb) & size_mask; | 353 | ring_index = (ring_index + ring->last_nr_txbb) & size_mask; |
354 | if (ring->tx_info[ring_index].ts_requested) | ||
355 | timestamp = mlx4_en_get_cqe_ts(cqe); | ||
356 | |||
344 | /* free next descriptor */ | 357 | /* free next descriptor */ |
345 | ring->last_nr_txbb = mlx4_en_free_tx_desc( | 358 | ring->last_nr_txbb = mlx4_en_free_tx_desc( |
346 | priv, ring, ring_index, | 359 | priv, ring, ring_index, |
347 | !!((ring->cons + txbbs_skipped) & | 360 | !!((ring->cons + txbbs_skipped) & |
348 | ring->size)); | 361 | ring->size), timestamp); |
349 | packets++; | 362 | packets++; |
350 | bytes += ring->tx_info[ring_index].nr_bytes; | 363 | bytes += ring->tx_info[ring_index].nr_bytes; |
351 | } while (ring_index != new_index); | 364 | } while (ring_index != new_index); |
@@ -629,6 +642,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
629 | tx_info->skb = skb; | 642 | tx_info->skb = skb; |
630 | tx_info->nr_txbb = nr_txbb; | 643 | tx_info->nr_txbb = nr_txbb; |
631 | 644 | ||
645 | /* | ||
646 | * For timestamping add flag to skb_shinfo and | ||
647 | * set flag for further reference | ||
648 | */ | ||
649 | if (ring->hwtstamp_tx_type == HWTSTAMP_TX_ON && | ||
650 | skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { | ||
651 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | ||
652 | tx_info->ts_requested = 1; | ||
653 | } | ||
654 | |||
632 | /* Prepare ctrl segement apart opcode+ownership, which depends on | 655 | /* Prepare ctrl segement apart opcode+ownership, which depends on |
633 | * whether LSO is used */ | 656 | * whether LSO is used */ |
634 | tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); | 657 | tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index e81840faa6c6..0d32a82458bf 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c | |||
@@ -1228,6 +1228,28 @@ static void unmap_bf_area(struct mlx4_dev *dev) | |||
1228 | io_mapping_free(mlx4_priv(dev)->bf_mapping); | 1228 | io_mapping_free(mlx4_priv(dev)->bf_mapping); |
1229 | } | 1229 | } |
1230 | 1230 | ||
1231 | cycle_t mlx4_read_clock(struct mlx4_dev *dev) | ||
1232 | { | ||
1233 | u32 clockhi, clocklo, clockhi1; | ||
1234 | cycle_t cycles; | ||
1235 | int i; | ||
1236 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
1237 | |||
1238 | for (i = 0; i < 10; i++) { | ||
1239 | clockhi = swab32(readl(priv->clock_mapping)); | ||
1240 | clocklo = swab32(readl(priv->clock_mapping + 4)); | ||
1241 | clockhi1 = swab32(readl(priv->clock_mapping)); | ||
1242 | if (clockhi == clockhi1) | ||
1243 | break; | ||
1244 | } | ||
1245 | |||
1246 | cycles = (u64) clockhi << 32 | (u64) clocklo; | ||
1247 | |||
1248 | return cycles; | ||
1249 | } | ||
1250 | EXPORT_SYMBOL_GPL(mlx4_read_clock); | ||
1251 | |||
1252 | |||
1231 | static int map_internal_clock(struct mlx4_dev *dev) | 1253 | static int map_internal_clock(struct mlx4_dev *dev) |
1232 | { | 1254 | { |
1233 | struct mlx4_priv *priv = mlx4_priv(dev); | 1255 | struct mlx4_priv *priv = mlx4_priv(dev); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index d4cb5d3b28a2..85b0754ec8ac 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/mutex.h> | 40 | #include <linux/mutex.h> |
41 | #include <linux/netdevice.h> | 41 | #include <linux/netdevice.h> |
42 | #include <linux/if_vlan.h> | 42 | #include <linux/if_vlan.h> |
43 | #include <linux/net_tstamp.h> | ||
43 | #ifdef CONFIG_MLX4_EN_DCB | 44 | #ifdef CONFIG_MLX4_EN_DCB |
44 | #include <linux/dcbnl.h> | 45 | #include <linux/dcbnl.h> |
45 | #endif | 46 | #endif |
@@ -207,6 +208,7 @@ struct mlx4_en_tx_info { | |||
207 | u8 linear; | 208 | u8 linear; |
208 | u8 data_offset; | 209 | u8 data_offset; |
209 | u8 inl; | 210 | u8 inl; |
211 | u8 ts_requested; | ||
210 | }; | 212 | }; |
211 | 213 | ||
212 | 214 | ||
@@ -262,6 +264,7 @@ struct mlx4_en_tx_ring { | |||
262 | struct mlx4_bf bf; | 264 | struct mlx4_bf bf; |
263 | bool bf_enabled; | 265 | bool bf_enabled; |
264 | struct netdev_queue *tx_queue; | 266 | struct netdev_queue *tx_queue; |
267 | int hwtstamp_tx_type; | ||
265 | }; | 268 | }; |
266 | 269 | ||
267 | struct mlx4_en_rx_desc { | 270 | struct mlx4_en_rx_desc { |
@@ -288,6 +291,7 @@ struct mlx4_en_rx_ring { | |||
288 | unsigned long packets; | 291 | unsigned long packets; |
289 | unsigned long csum_ok; | 292 | unsigned long csum_ok; |
290 | unsigned long csum_none; | 293 | unsigned long csum_none; |
294 | int hwtstamp_rx_filter; | ||
291 | }; | 295 | }; |
292 | 296 | ||
293 | struct mlx4_en_cq { | 297 | struct mlx4_en_cq { |
@@ -348,6 +352,9 @@ struct mlx4_en_dev { | |||
348 | u32 priv_pdn; | 352 | u32 priv_pdn; |
349 | spinlock_t uar_lock; | 353 | spinlock_t uar_lock; |
350 | u8 mac_removed[MLX4_MAX_PORTS + 1]; | 354 | u8 mac_removed[MLX4_MAX_PORTS + 1]; |
355 | struct cyclecounter cycles; | ||
356 | struct timecounter clock; | ||
357 | unsigned long last_overflow_check; | ||
351 | }; | 358 | }; |
352 | 359 | ||
353 | 360 | ||
@@ -525,6 +532,7 @@ struct mlx4_en_priv { | |||
525 | struct device *ddev; | 532 | struct device *ddev; |
526 | int base_tx_qpn; | 533 | int base_tx_qpn; |
527 | struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; | 534 | struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; |
535 | struct hwtstamp_config hwtstamp_config; | ||
528 | 536 | ||
529 | #ifdef CONFIG_MLX4_EN_DCB | 537 | #ifdef CONFIG_MLX4_EN_DCB |
530 | struct ieee_ets ets; | 538 | struct ieee_ets ets; |
@@ -639,7 +647,18 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); | |||
639 | u64 mlx4_en_mac_to_u64(u8 *addr); | 647 | u64 mlx4_en_mac_to_u64(u8 *addr); |
640 | 648 | ||
641 | /* | 649 | /* |
642 | * Globals | 650 | * Functions for time stamping |
651 | */ | ||
652 | u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe); | ||
653 | void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev, | ||
654 | struct skb_shared_hwtstamps *hwts, | ||
655 | u64 timestamp); | ||
656 | void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev); | ||
657 | int mlx4_en_timestamp_config(struct net_device *dev, | ||
658 | int tx_type, | ||
659 | int rx_filter); | ||
660 | |||
661 | /* Globals | ||
643 | */ | 662 | */ |
644 | extern const struct ethtool_ops mlx4_en_ethtool_ops; | 663 | extern const struct ethtool_ops mlx4_en_ethtool_ops; |
645 | 664 | ||