Commit ec693d47 authored by Amir Vadai's avatar Amir Vadai Committed by David S. Miller

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: default avatarEugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: default avatarAmir Vadai <amirv@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ddd8a6c1
...@@ -228,7 +228,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector ...@@ -228,7 +228,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
vector = dev->eq_table[vector % ibdev->num_comp_vectors]; vector = dev->eq_table[vector % ibdev->num_comp_vectors];
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
cq->db.dma, &cq->mcq, vector, 0); cq->db.dma, &cq->mcq, vector, 0, 0);
if (err) if (err)
goto err_dbmap; goto err_dbmap;
......
...@@ -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,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 \
obj-$(CONFIG_MLX4_EN) += mlx4_en.o obj-$(CONFIG_MLX4_EN) += mlx4_en.o
mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
en_resources.o en_netdev.o en_selftest.o en_resources.o en_netdev.o en_selftest.o en_clock.o
mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o
...@@ -240,9 +240,10 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) ...@@ -240,9 +240,10 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
__mlx4_cq_free_icm(dev, cqn); __mlx4_cq_free_icm(dev, cqn);
} }
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec,
unsigned vector, int collapsed) struct mlx4_cq *cq, unsigned vector, int collapsed,
int timestamp_en)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cq_table *cq_table = &priv->cq_table; 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,6 +277,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
memset(cq_context, 0, sizeof *cq_context); memset(cq_context, 0, sizeof *cq_context);
cq_context->flags = cpu_to_be32(!!collapsed << 18); cq_context->flags = cpu_to_be32(!!collapsed << 18);
if (timestamp_en)
cq_context->flags |= cpu_to_be32(1 << 19);
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; cq_context->comp_eqn = priv->eq_table.eq[vector].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
......
/*
* Copyright (c) 2012 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <linux/mlx4/device.h>
#include "mlx4_en.h"
int mlx4_en_timestamp_config(struct net_device *dev, int tx_type, int rx_filter)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
int port_up = 0;
int err = 0;
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
port_up = 1;
mlx4_en_stop_port(dev, 1);
}
mlx4_en_free_resources(priv);
en_warn(priv, "Changing Time Stamp configuration\n");
priv->hwtstamp_config.tx_type = tx_type;
priv->hwtstamp_config.rx_filter = rx_filter;
if (rx_filter != HWTSTAMP_FILTER_NONE)
dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
else
dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
err = mlx4_en_alloc_resources(priv);
if (err) {
en_err(priv, "Failed reallocating port resources\n");
goto out;
}
if (port_up) {
err = mlx4_en_start_port(dev);
if (err)
en_err(priv, "Failed starting port\n");
}
out:
mutex_unlock(&mdev->state_lock);
netdev_features_change(dev);
return err;
}
/* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
*/
static cycle_t mlx4_en_read_clock(const struct cyclecounter *tc)
{
struct mlx4_en_dev *mdev =
container_of(tc, struct mlx4_en_dev, cycles);
struct mlx4_dev *dev = mdev->dev;
return mlx4_read_clock(dev) & tc->mask;
}
u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
{
u64 hi, lo;
struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;
lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo);
hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16;
return hi | lo;
}
void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
struct skb_shared_hwtstamps *hwts,
u64 timestamp)
{
u64 nsec;
nsec = timecounter_cyc2time(&mdev->clock, timestamp);
memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
hwts->hwtstamp = ns_to_ktime(nsec);
}
void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
{
struct mlx4_dev *dev = mdev->dev;
memset(&mdev->cycles, 0, sizeof(mdev->cycles));
mdev->cycles.read = mlx4_en_read_clock;
mdev->cycles.mask = CLOCKSOURCE_MASK(48);
/* Using shift to make calculation more accurate. Since current HW
* clock frequency is 427 MHz, and cycles are given using a 48 bits
* register, the biggest shift when calculating using u64, is 14
* (max_cycles * multiplier < 2^64)
*/
mdev->cycles.shift = 14;
mdev->cycles.mult =
clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
timecounter_init(&mdev->clock, &mdev->cycles,
ktime_to_ns(ktime_get_real()));
}
...@@ -77,6 +77,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, ...@@ -77,6 +77,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
int err = 0; int err = 0;
char name[25]; char name[25];
int timestamp_en = 0;
struct cpu_rmap *rmap = struct cpu_rmap *rmap =
#ifdef CONFIG_RFS_ACCEL #ifdef CONFIG_RFS_ACCEL
priv->dev->rx_cpu_rmap; 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,8 +124,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
if (!cq->is_tx) if (!cq->is_tx)
cq->size = priv->rx_ring[cq->ring].actual_size; cq->size = priv->rx_ring[cq->ring].actual_size;
err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
cq->wqres.db.dma, &cq->mcq, cq->vector, 0); (!cq->is_tx && priv->hwtstamp_config.rx_filter))
timestamp_en = 1;
err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt,
&mdev->priv_uar, cq->wqres.db.dma, &cq->mcq,
cq->vector, 0, timestamp_en);
if (err) if (err)
return err; return err;
......
...@@ -1147,6 +1147,35 @@ static int mlx4_en_set_channels(struct net_device *dev, ...@@ -1147,6 +1147,35 @@ static int mlx4_en_set_channels(struct net_device *dev,
return err; return err;
} }
static int mlx4_en_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
int ret;
ret = ethtool_op_get_ts_info(dev, info);
if (ret)
return ret;
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) {
info->so_timestamping |=
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
info->rx_filters =
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_ALL);
}
return ret;
}
const struct ethtool_ops mlx4_en_ethtool_ops = { const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo, .get_drvinfo = mlx4_en_get_drvinfo,
.get_settings = mlx4_en_get_settings, .get_settings = mlx4_en_get_settings,
...@@ -1173,6 +1202,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { ...@@ -1173,6 +1202,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.set_rxfh_indir = mlx4_en_set_rxfh_indir, .set_rxfh_indir = mlx4_en_set_rxfh_indir,
.get_channels = mlx4_en_get_channels, .get_channels = mlx4_en_get_channels,
.set_channels = mlx4_en_set_channels, .set_channels = mlx4_en_set_channels,
.get_ts_info = mlx4_en_get_ts_info,
}; };
......
...@@ -300,6 +300,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev) ...@@ -300,6 +300,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
mdev->pndev[i] = NULL; mdev->pndev[i] = NULL;
} }
/* Initialize time stamp mechanism */
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
mlx4_en_init_timestamp(mdev);
return mdev; return mdev;
err_mr: err_mr:
......
...@@ -1916,6 +1916,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1916,6 +1916,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
struct hwtstamp_config config;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
/* reserved for future extensions */
if (config.flags)
return -EINVAL;
/* device doesn't support time stamping */
if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS))
return -EINVAL;
/* TX HW timestamp */
switch (config.tx_type) {
case HWTSTAMP_TX_OFF:
case HWTSTAMP_TX_ON:
break;
default:
return -ERANGE;
}
/* RX HW timestamp */
switch (config.rx_filter) {
case 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:
config.rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
}
if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
config.tx_type = HWTSTAMP_TX_OFF;
config.rx_filter = HWTSTAMP_FILTER_NONE;
}
return copy_to_user(ifr->ifr_data, &config,
sizeof(config)) ? -EFAULT : 0;
}
static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
case SIOCSHWTSTAMP:
return mlx4_en_hwtstamp_ioctl(dev, ifr);
default:
return -EOPNOTSUPP;
}
}
static int mlx4_en_set_features(struct net_device *netdev, static int mlx4_en_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
...@@ -1943,6 +2012,7 @@ static const struct net_device_ops mlx4_netdev_ops = { ...@@ -1943,6 +2012,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_set_mac_address = mlx4_en_set_mac, .ndo_set_mac_address = mlx4_en_set_mac,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = mlx4_en_change_mtu, .ndo_change_mtu = mlx4_en_change_mtu,
.ndo_do_ioctl = mlx4_en_ioctl,
.ndo_tx_timeout = mlx4_en_tx_timeout, .ndo_tx_timeout = mlx4_en_tx_timeout,
.ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, .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,6 +2124,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
spin_lock_init(&priv->filters_lock); spin_lock_init(&priv->filters_lock);
#endif #endif
/* Initialize time stamping config */
priv->hwtstamp_config.flags = 0;
priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
/* Allocate page for receive rings */ /* Allocate page for receive rings */
err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
......
...@@ -42,6 +42,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, ...@@ -42,6 +42,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
int user_prio, struct mlx4_qp_context *context) int user_prio, struct mlx4_qp_context *context)
{ {
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct net_device *dev = priv->dev;
memset(context, 0, sizeof *context); memset(context, 0, sizeof *context);
context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET); 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,6 +66,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->cqn_send = cpu_to_be32(cqn); context->cqn_send = cpu_to_be32(cqn);
context->cqn_recv = cpu_to_be32(cqn); context->cqn_recv = cpu_to_be32(cqn);
context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX))
context->param3 |= cpu_to_be32(1 << 30);
} }
......
...@@ -320,6 +320,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, ...@@ -320,6 +320,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
} }
ring->buf = ring->wqres.buf.direct.buf; ring->buf = ring->wqres.buf.direct.buf;
ring->hwtstamp_rx_filter = priv->hwtstamp_config.rx_filter;
return 0; return 0;
err_hwq: err_hwq:
...@@ -554,6 +556,7 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv, ...@@ -554,6 +556,7 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,
int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_cqe *cqe; struct mlx4_cqe *cqe;
struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
struct mlx4_en_rx_alloc *frags; 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,6 +568,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
int polled = 0; int polled = 0;
int ip_summed; int ip_summed;
int factor = priv->cqe_factor; int factor = priv->cqe_factor;
u64 timestamp;
if (!priv->port_up) if (!priv->port_up)
return 0; return 0;
...@@ -669,8 +673,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ...@@ -669,8 +673,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
gro_skb->data_len = length; gro_skb->data_len = length;
gro_skb->ip_summed = CHECKSUM_UNNECESSARY; gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
if (cqe->vlan_my_qpn & if ((cqe->vlan_my_qpn &
cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) { cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
(dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
u16 vid = be16_to_cpu(cqe->sl_vid); u16 vid = be16_to_cpu(cqe->sl_vid);
__vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); __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,8 +685,15 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
skb_record_rx_queue(gro_skb, cq->ring); skb_record_rx_queue(gro_skb, cq->ring);
napi_gro_frags(&cq->napi);
if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
timestamp = mlx4_en_get_cqe_ts(cqe);
mlx4_en_fill_hwtstamps(mdev,
skb_hwtstamps(gro_skb),
timestamp);
}
napi_gro_frags(&cq->napi);
goto next; goto next;
} }
...@@ -714,10 +726,17 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ...@@ -714,10 +726,17 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
if (dev->features & NETIF_F_RXHASH) if (dev->features & NETIF_F_RXHASH)
skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid); skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
if (be32_to_cpu(cqe->vlan_my_qpn) & if ((be32_to_cpu(cqe->vlan_my_qpn) &
MLX4_CQE_VLAN_PRESENT_MASK) MLX4_CQE_VLAN_PRESENT_MASK) &&
(dev->features & NETIF_F_HW_VLAN_CTAG_RX))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid));
if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
timestamp = mlx4_en_get_cqe_ts(cqe);
mlx4_en_fill_hwtstamps(mdev, skb_hwtstamps(skb),
timestamp);
}
/* Push it up the stack */ /* Push it up the stack */
netif_receive_skb(skb); netif_receive_skb(skb);
......
...@@ -118,6 +118,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ...@@ -118,6 +118,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
} else } else
ring->bf_enabled = true; ring->bf_enabled = true;
ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
return 0; return 0;
err_map: err_map:
...@@ -192,8 +194,9 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, ...@@ -192,8 +194,9 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring, struct mlx4_en_tx_ring *ring,
int index, u8 owner) int index, u8 owner, u64 timestamp)
{ {
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; 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,6 +207,12 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
int i; int i;
__be32 *ptr = (__be32 *)tx_desc; __be32 *ptr = (__be32 *)tx_desc;
__be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
struct skb_shared_hwtstamps hwts;
if (timestamp) {
mlx4_en_fill_hwtstamps(mdev, &hwts, timestamp);
skb_tstamp_tx(skb, &hwts);
}
/* Optimize the common case when there are no wraparounds */ /* Optimize the common case when there are no wraparounds */
if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { 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,7 +298,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
while (ring->cons != ring->prod) { while (ring->cons != ring->prod) {
ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
ring->cons & ring->size_mask, ring->cons & ring->size_mask,
!!(ring->cons & ring->size)); !!(ring->cons & ring->size), 0);
ring->cons += ring->last_nr_txbb; ring->cons += ring->last_nr_txbb;
cnt++; cnt++;
} }
...@@ -318,6 +327,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) ...@@ -318,6 +327,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
u32 packets = 0; u32 packets = 0;
u32 bytes = 0; u32 bytes = 0;
int factor = priv->cqe_factor; int factor = priv->cqe_factor;
u64 timestamp = 0;
if (!priv->port_up) if (!priv->port_up)
return; return;
...@@ -341,11 +351,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) ...@@ -341,11 +351,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
do { do {
txbbs_skipped += ring->last_nr_txbb; txbbs_skipped += ring->last_nr_txbb;
ring_index = (ring_index + ring->last_nr_txbb) & size_mask; ring_index = (ring_index + ring->last_nr_txbb) & size_mask;
if (ring->tx_info[ring_index].ts_requested)
timestamp = mlx4_en_get_cqe_ts(cqe);
/* free next descriptor */ /* free next descriptor */
ring->last_nr_txbb = mlx4_en_free_tx_desc( ring->last_nr_txbb = mlx4_en_free_tx_desc(
priv, ring, ring_index, priv, ring, ring_index,
!!((ring->cons + txbbs_skipped) & !!((ring->cons + txbbs_skipped) &
ring->size)); ring->size), timestamp);
packets++; packets++;
bytes += ring->tx_info[ring_index].nr_bytes; bytes += ring->tx_info[ring_index].nr_bytes;
} while (ring_index != new_index); } while (ring_index != new_index);
...@@ -629,6 +642,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -629,6 +642,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
tx_info->skb = skb; tx_info->skb = skb;
tx_info->nr_txbb = nr_txbb; tx_info->nr_txbb = nr_txbb;
/*
* For timestamping add flag to skb_shinfo and
* set flag for further reference
*/
if (ring->hwtstamp_tx_type == HWTSTAMP_TX_ON &&
skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_info->ts_requested = 1;
}
/* Prepare ctrl segement apart opcode+ownership, which depends on /* Prepare ctrl segement apart opcode+ownership, which depends on
* whether LSO is used */ * whether LSO is used */
tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
......
...@@ -1228,6 +1228,28 @@ static void unmap_bf_area(struct mlx4_dev *dev) ...@@ -1228,6 +1228,28 @@ static void unmap_bf_area(struct mlx4_dev *dev)
io_mapping_free(mlx4_priv(dev)->bf_mapping); io_mapping_free(mlx4_priv(dev)->bf_mapping);
} }
cycle_t mlx4_read_clock(struct mlx4_dev *dev)
{
u32 clockhi, clocklo, clockhi1;
cycle_t cycles;
int i;
struct mlx4_priv *priv = mlx4_priv(dev);
for (i = 0; i < 10; i++) {
clockhi = swab32(readl(priv->clock_mapping));
clocklo = swab32(readl(priv->clock_mapping + 4));
clockhi1 = swab32(readl(priv->clock_mapping));
if (clockhi == clockhi1)
break;
}
cycles = (u64) clockhi << 32 | (u64) clocklo;
return cycles;
}
EXPORT_SYMBOL_GPL(mlx4_read_clock);
static int map_internal_clock(struct mlx4_dev *dev) static int map_internal_clock(struct mlx4_dev *dev)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/net_tstamp.h>
#ifdef CONFIG_MLX4_EN_DCB #ifdef CONFIG_MLX4_EN_DCB
#include <linux/dcbnl.h> #include <linux/dcbnl.h>
#endif #endif
...@@ -207,6 +208,7 @@ struct mlx4_en_tx_info { ...@@ -207,6 +208,7 @@ struct mlx4_en_tx_info {
u8 linear; u8 linear;
u8 data_offset; u8 data_offset;
u8 inl; u8 inl;
u8 ts_requested;
}; };
...@@ -262,6 +264,7 @@ struct mlx4_en_tx_ring { ...@@ -262,6 +264,7 @@ struct mlx4_en_tx_ring {
struct mlx4_bf bf; struct mlx4_bf bf;
bool bf_enabled; bool bf_enabled;
struct netdev_queue *tx_queue; struct netdev_queue *tx_queue;
int hwtstamp_tx_type;
}; };
struct mlx4_en_rx_desc { struct mlx4_en_rx_desc {
...@@ -288,6 +291,7 @@ struct mlx4_en_rx_ring { ...@@ -288,6 +291,7 @@ struct mlx4_en_rx_ring {
unsigned long packets; unsigned long packets;
unsigned long csum_ok; unsigned long csum_ok;
unsigned long csum_none; unsigned long csum_none;
int hwtstamp_rx_filter;
}; };
struct mlx4_en_cq { struct mlx4_en_cq {
...@@ -348,6 +352,9 @@ struct mlx4_en_dev { ...@@ -348,6 +352,9 @@ struct mlx4_en_dev {
u32 priv_pdn; u32 priv_pdn;
spinlock_t uar_lock; spinlock_t uar_lock;
u8 mac_removed[MLX4_MAX_PORTS + 1]; u8 mac_removed[MLX4_MAX_PORTS + 1];
struct cyclecounter cycles;
struct timecounter clock;
unsigned long last_overflow_check;
}; };
...@@ -525,6 +532,7 @@ struct mlx4_en_priv { ...@@ -525,6 +532,7 @@ struct mlx4_en_priv {
struct device *ddev; struct device *ddev;
int base_tx_qpn; int base_tx_qpn;
struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
struct hwtstamp_config hwtstamp_config;
#ifdef CONFIG_MLX4_EN_DCB #ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets; struct ieee_ets ets;
...@@ -639,7 +647,18 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); ...@@ -639,7 +647,18 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
u64 mlx4_en_mac_to_u64(u8 *addr); u64 mlx4_en_mac_to_u64(u8 *addr);
/* /*
* Globals * Functions for time stamping
*/
u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe);
void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
struct skb_shared_hwtstamps *hwts,
u64 timestamp);
void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev);
int mlx4_en_timestamp_config(struct net_device *dev,
int tx_type,
int rx_filter);
/* Globals
*/ */
extern const struct ethtool_ops mlx4_en_ethtool_ops; extern const struct ethtool_ops mlx4_en_ethtool_ops;
......
...@@ -64,6 +64,22 @@ struct mlx4_err_cqe { ...@@ -64,6 +64,22 @@ struct mlx4_err_cqe {
u8 owner_sr_opcode; u8 owner_sr_opcode;
}; };
struct mlx4_ts_cqe {
__be32 vlan_my_qpn;
__be32 immed_rss_invalid;
__be32 g_mlpath_rqpn;
__be32 timestamp_hi;
__be16 status;
u8 ipv6_ext_mask;
u8 badfcs_enc;
__be32 byte_cnt;
__be16 wqe_index;
__be16 checksum;
u8 reserved;
__be16 timestamp_lo;
u8 owner_sr_opcode;
} __packed;
enum { enum {
MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29, MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29,
MLX4_CQE_QPN_MASK = 0xffffff, MLX4_CQE_QPN_MASK = 0xffffff,
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/clocksource.h>
#define MAX_MSIX_P_PORT 17 #define MAX_MSIX_P_PORT 17
#define MAX_MSIX 64 #define MAX_MSIX 64
#define MSIX_LEGACY_SZ 4 #define MSIX_LEGACY_SZ 4
...@@ -840,7 +842,7 @@ void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres, ...@@ -840,7 +842,7 @@ void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres,
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
unsigned vector, int collapsed); unsigned vector, int collapsed, int timestamp_en);
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base); int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
...@@ -1031,4 +1033,6 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int ...@@ -1031,4 +1033,6 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int
void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid); void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid);
__be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave); __be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave);
cycle_t mlx4_read_clock(struct mlx4_dev *dev);
#endif /* MLX4_DEVICE_H */ #endif /* MLX4_DEVICE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment