Skip to content

Commit ec693d4

Browse files
amirvdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Amir Vadai <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ddd8a6c commit ec693d4

File tree

15 files changed

+375
-17
lines changed

15 files changed

+375
-17
lines changed

drivers/infiniband/hw/mlx4/cq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
228228
vector = dev->eq_table[vector % ibdev->num_comp_vectors];
229229

230230
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
231-
cq->db.dma, &cq->mcq, vector, 0);
231+
cq->db.dma, &cq->mcq, vector, 0, 0);
232232
if (err)
233233
goto err_dbmap;
234234

drivers/net/ethernet/mellanox/mlx4/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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 \
66
obj-$(CONFIG_MLX4_EN) += mlx4_en.o
77

88
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
1010
mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o

drivers/net/ethernet/mellanox/mlx4/cq.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,10 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
240240
__mlx4_cq_free_icm(dev, cqn);
241241
}
242242

243-
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
244-
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
245-
unsigned vector, int collapsed)
243+
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
244+
struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec,
245+
struct mlx4_cq *cq, unsigned vector, int collapsed,
246+
int timestamp_en)
246247
{
247248
struct mlx4_priv *priv = mlx4_priv(dev);
248249
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,
276277
memset(cq_context, 0, sizeof *cq_context);
277278

278279
cq_context->flags = cpu_to_be32(!!collapsed << 18);
280+
if (timestamp_en)
281+
cq_context->flags |= cpu_to_be32(1 << 19);
282+
279283
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
280284
cq_context->comp_eqn = priv->eq_table.eq[vector].eqn;
281285
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

drivers/net/ethernet/mellanox/mlx4/en_cq.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
7777
struct mlx4_en_dev *mdev = priv->mdev;
7878
int err = 0;
7979
char name[25];
80+
int timestamp_en = 0;
8081
struct cpu_rmap *rmap =
8182
#ifdef CONFIG_RFS_ACCEL
8283
priv->dev->rx_cpu_rmap;
@@ -123,8 +124,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
123124
if (!cq->is_tx)
124125
cq->size = priv->rx_ring[cq->ring].actual_size;
125126

126-
err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
127-
cq->wqres.db.dma, &cq->mcq, cq->vector, 0);
127+
if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
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);
128134
if (err)
129135
return err;
130136

drivers/net/ethernet/mellanox/mlx4/en_ethtool.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,35 @@ static int mlx4_en_set_channels(struct net_device *dev,
11471147
return err;
11481148
}
11491149

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+
11501179
const struct ethtool_ops mlx4_en_ethtool_ops = {
11511180
.get_drvinfo = mlx4_en_get_drvinfo,
11521181
.get_settings = mlx4_en_get_settings,
@@ -1173,6 +1202,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
11731202
.set_rxfh_indir = mlx4_en_set_rxfh_indir,
11741203
.get_channels = mlx4_en_get_channels,
11751204
.set_channels = mlx4_en_set_channels,
1205+
.get_ts_info = mlx4_en_get_ts_info,
11761206
};
11771207

11781208

drivers/net/ethernet/mellanox/mlx4/en_main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
300300
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
301301
mdev->pndev[i] = NULL;
302302
}
303+
304+
/* Initialize time stamp mechanism */
305+
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
306+
mlx4_en_init_timestamp(mdev);
307+
303308
return mdev;
304309

305310
err_mr:

drivers/net/ethernet/mellanox/mlx4/en_netdev.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
19161916
return 0;
19171917
}
19181918

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+
19191988
static int mlx4_en_set_features(struct net_device *netdev,
19201989
netdev_features_t features)
19211990
{
@@ -1943,6 +2012,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
19432012
.ndo_set_mac_address = mlx4_en_set_mac,
19442013
.ndo_validate_addr = eth_validate_addr,
19452014
.ndo_change_mtu = mlx4_en_change_mtu,
2015+
.ndo_do_ioctl = mlx4_en_ioctl,
19462016
.ndo_tx_timeout = mlx4_en_tx_timeout,
19472017
.ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid,
19482018
.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,
20542124
spin_lock_init(&priv->filters_lock);
20552125
#endif
20562126

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+
20572132
/* Allocate page for receive rings */
20582133
err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
20592134
MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);

drivers/net/ethernet/mellanox/mlx4/en_resources.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
4242
int user_prio, struct mlx4_qp_context *context)
4343
{
4444
struct mlx4_en_dev *mdev = priv->mdev;
45+
struct net_device *dev = priv->dev;
4546

4647
memset(context, 0, sizeof *context);
4748
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,
6566
context->cqn_send = cpu_to_be32(cqn);
6667
context->cqn_recv = cpu_to_be32(cqn);
6768
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);
6871
}
6972

7073

0 commit comments

Comments
 (0)