netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] net/mlx4: HW Timestamp support
@ 2012-09-28 10:03 Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 1/3] net/mlx4_core: Add timestamping device capability Yevgeny Petrilin
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-09-28 10:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, eugenia

This series of patches comes to introduce Ethernet HW timestamping support
for ConnectX3 devices.
When RX/TX timestamping is enabled every incoming/outgoing packet
will be timestamped.
Current limitation: for now HWTSTAMP_FILTER_ALL/NONE and HWTSAMP_TX_ON/OFF
are the only supported options.

The series consists of three logical sections:
1. Add timestamping device capability
   Add new device capability for timestamping support and query FW to retrieve it.
2. Read HCA frequency and map internal clock
   Read HCA frequency, read PCI clock bar and offset, map internal clock to PCI bar.
3. 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 flags 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.

Eugenia Emantayev (3):
   net/mlx4_core: Add timestamping device capability
   net/mlx4_core: Read HCA frequency and map internal clock
   net/mlx4_en: Add HW timestamping (TS) support

  drivers/infiniband/hw/mlx4/cq.c                   |    2
  drivers/net/ethernet/mellanox/mlx4/Makefile       |    2
  drivers/net/ethernet/mellanox/mlx4/cq.c           |   10 -
  drivers/net/ethernet/mellanox/mlx4/en_cq.c        |   10 +
  drivers/net/ethernet/mellanox/mlx4/en_main.c      |    5
  drivers/net/ethernet/mellanox/mlx4/en_netdev.c    |   60 +++++++
  drivers/net/ethernet/mellanox/mlx4/en_resources.c |    3
  drivers/net/ethernet/mellanox/mlx4/en_rx.c        |   28 +++
  drivers/net/ethernet/mellanox/mlx4/en_timestamp.c |  153 ++++++++++++++++++++
  drivers/net/ethernet/mellanox/mlx4/en_tx.c        |   33 +++-
  drivers/net/ethernet/mellanox/mlx4/fw.c           |   11 +
  drivers/net/ethernet/mellanox/mlx4/fw.h           |    1
  drivers/net/ethernet/mellanox/mlx4/main.c         |   22 ++
  drivers/net/ethernet/mellanox/mlx4/mlx4.h         |    6
  drivers/net/ethernet/mellanox/mlx4/mlx4_en.h      |   21 ++
  include/linux/mlx4/cq.h                           |   16 ++
  include/linux/mlx4/device.h                       |    6
  drivers/net/ethernet/mellanox/mlx4/fw.c             |    7
  drivers/net/ethernet/mellanox/mlx4/main.c           |   59 +++++++
  include/linux/mlx4/device.h                         |    4
  20 files changed, 439 insertions(+), 20 deletions(-)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] net/mlx4_core: Add timestamping device capability
  2012-09-28 10:03 [PATCH 0/3] net/mlx4: HW Timestamp support Yevgeny Petrilin
@ 2012-09-28 10:03 ` Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 2/3] net/mlx4_core: Read HCA frequency and map internal clock Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support Yevgeny Petrilin
  2 siblings, 0 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-09-28 10:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, eugenia

From: Eugenia Emantayev <eugenia@mellanox.co.il>

Add new device capability for timestamping support and query FW to retrieve it.

Signed-off-by: Eugenia Emantayev <eugenia@mellanox.co.il>
Reviewed-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/fw.c |    7 ++++++-
 include/linux/mlx4/device.h             |    3 ++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index c696484..d7b0850 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -125,7 +125,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
 		[0] = "RSS support",
 		[1] = "RSS Toeplitz Hash Function support",
 		[2] = "RSS XOR Hash Function support",
-		[3] = "Device manage flow steering support"
+		[3] = "Device manage flow steering support",
+		[4] = "Time stamping support"
 	};
 	int i;
 
@@ -402,6 +403,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET		0x38
 #define QUERY_DEV_CAP_MAX_GID_OFFSET		0x3b
 #define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET	0x3c
+#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET	0x3e
 #define QUERY_DEV_CAP_MAX_PKEY_OFFSET		0x3f
 #define QUERY_DEV_CAP_EXT_FLAGS_OFFSET		0x40
 #define QUERY_DEV_CAP_FLAGS_OFFSET		0x44
@@ -517,6 +519,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 	dev_cap->fs_max_num_qp_per_entry = field;
 	MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
 	dev_cap->stat_rate_support = stat_rate;
+	MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+	if (field & 0x80)
+		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS_EN;
 	MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
 	MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
 	dev_cap->flags = flags | (u64)ext_flags << 32;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 6e1b0f9..e482e6b 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -142,7 +142,8 @@ enum {
 	MLX4_DEV_CAP_FLAG2_RSS			= 1LL <<  0,
 	MLX4_DEV_CAP_FLAG2_RSS_TOP		= 1LL <<  1,
 	MLX4_DEV_CAP_FLAG2_RSS_XOR		= 1LL <<  2,
-	MLX4_DEV_CAP_FLAG2_FS_EN		= 1LL <<  3
+	MLX4_DEV_CAP_FLAG2_FS_EN		= 1LL <<  3,
+	MLX4_DEV_CAP_FLAG2_TS_EN		= 1LL <<  4
 };
 
 #define MLX4_ATTR_EXTENDED_PORT_INFO	cpu_to_be16(0xff90)
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] net/mlx4_core: Read HCA frequency and map internal clock
  2012-09-28 10:03 [PATCH 0/3] net/mlx4: HW Timestamp support Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 1/3] net/mlx4_core: Add timestamping device capability Yevgeny Petrilin
@ 2012-09-28 10:03 ` Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support Yevgeny Petrilin
  2 siblings, 0 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-09-28 10:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, eugenia

From: Eugenia Emantayev <eugenia@mellanox.co.il>

Read HCA frequency, read PCI clock bar and offset, map internal clock to PCI bar.

Signed-off-by: Eugenia Emantayev <eugenia@mellanox.co.il>
Reviewed-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/fw.c   |   11 +++++
 drivers/net/ethernet/mellanox/mlx4/fw.h   |    1 +
 drivers/net/ethernet/mellanox/mlx4/main.c |   59 +++++++++++++++++++++++++++++
 drivers/net/ethernet/mellanox/mlx4/mlx4.h |    6 ++-
 include/linux/mlx4/device.h               |    1 +
 5 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index d7b0850..d5141fc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -944,6 +944,9 @@ int mlx4_QUERY_FW(struct mlx4_dev *dev)
 #define QUERY_FW_COMM_BASE_OFFSET      0x40
 #define QUERY_FW_COMM_BAR_OFFSET       0x48
 
+#define QUERY_FW_CLOCK_OFFSET	       0x50
+#define QUERY_FW_CLOCK_BAR	       0x58
+
 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
@@ -1018,6 +1021,12 @@ int mlx4_QUERY_FW(struct mlx4_dev *dev)
 		 fw->comm_bar, fw->comm_base);
 	mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
 
+	MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET);
+	MLX4_GET(fw->clock_bar,    outbox, QUERY_FW_CLOCK_BAR);
+	fw->clock_bar = (fw->clock_bar >> 6) * 2;
+	mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n",
+		 fw->clock_bar, fw->clock_offset);
+
 	/*
 	 * Round up number of system pages needed in case
 	 * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
@@ -1283,6 +1292,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
 	int err;
 
 #define QUERY_HCA_GLOBAL_CAPS_OFFSET	0x04
+#define QUERY_HCA_CORE_CLOCK_OFFSET	0x0c
 
 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 	if (IS_ERR(mailbox))
@@ -1297,6 +1307,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
 		goto out;
 
 	MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET);
+	MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
 
 	/* QPC/EEC/CQC/EQC/RDMARC attributes */
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index 83fcbbf..fa2f723 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -158,6 +158,7 @@ struct mlx4_init_hca_param {
 	u64 global_caps;
 	u16 log_mc_entry_sz;
 	u16 log_mc_hash_sz;
+	u16 hca_core_clock;
 	u8  log_num_qps;
 	u8  log_num_srqs;
 	u8  log_num_cqs;
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 2f816c6..60c159a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -461,6 +461,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
 
 	mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz;
 
+	dev->caps.hca_core_clock = hca_param.hca_core_clock;
+
 	memset(&dev_cap, 0, sizeof(dev_cap));
 	dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp;
 	err = mlx4_dev_cap(dev, &dev_cap);
@@ -1125,8 +1127,31 @@ static void unmap_bf_area(struct mlx4_dev *dev)
 		io_mapping_free(mlx4_priv(dev)->bf_mapping);
 }
 
+static int map_internal_clock(struct mlx4_dev *dev)
+{
+	struct mlx4_priv *priv = mlx4_priv(dev);
+
+	priv->clock_mapping = ioremap(pci_resource_start(dev->pdev,
+				priv->fw.clock_bar) +
+				priv->fw.clock_offset, MLX4_CLOCK_SIZE);
+
+	if (!priv->clock_mapping)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void unmap_internal_clock(struct mlx4_dev *dev)
+{
+	struct mlx4_priv *priv = mlx4_priv(dev);
+
+	if (priv->clock_mapping)
+		iounmap(priv->clock_mapping);
+}
+
 static void mlx4_close_hca(struct mlx4_dev *dev)
 {
+	unmap_internal_clock(dev);
 	unmap_bf_area(dev);
 	if (mlx4_is_slave(dev))
 		mlx4_slave_exit(dev);
@@ -1300,6 +1325,39 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 			mlx4_err(dev, "INIT_HCA command failed, aborting.\n");
 			goto err_free_icm;
 		}
+		/*
+		 * If TS is supported by FW
+		 * read HCA frequency by QUERY_HCA command
+		 */
+		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS_EN) {
+			memset(&init_hca, 0, sizeof(init_hca));
+			err = mlx4_QUERY_HCA(dev, &init_hca);
+			if (err) {
+				mlx4_err(dev, "QUERY_HCA command failed, disable timestamp.\n");
+				dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS_EN;
+			} else {
+				dev->caps.hca_core_clock =
+					init_hca.hca_core_clock;
+			}
+
+			/*
+			 * In case we got HCA frequency 0 - disable timestamping
+			 * to avoid dividing by zero
+			 */
+			if (!dev->caps.hca_core_clock) {
+				dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS_EN;
+				mlx4_err(dev, "HCA frequency is 0. " \
+					 "Timestamping is not supported.");
+			} else if (map_internal_clock(dev)) {
+				/*
+				 * Map internal clock,
+				 * in case of failure disable timestamping
+				 */
+				dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS_EN;
+				mlx4_err(dev, "Failed to map internal clock. " \
+					 "Timestamping is not supported.\n");
+			}
+		}
 	} else {
 		err = mlx4_init_slave(dev);
 		if (err) {
@@ -1333,6 +1391,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 	return 0;
 
 unmap_bf:
+	unmap_internal_clock(dev);
 	unmap_bf_area(dev);
 
 err_close:
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index dba69d9..64b7ce6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -90,7 +90,8 @@ enum {
 	MLX4_HCR_SIZE		= 0x0001c,
 	MLX4_CLR_INT_SIZE	= 0x00008,
 	MLX4_SLAVE_COMM_BASE	= 0x0,
-	MLX4_COMM_PAGESIZE	= 0x1000
+	MLX4_COMM_PAGESIZE	= 0x1000,
+	MLX4_CLOCK_SIZE		= 0x00008
 };
 
 enum {
@@ -388,6 +389,7 @@ struct mlx4_fw {
 	u64			clr_int_base;
 	u64			catas_offset;
 	u64			comm_base;
+	u64			clock_offset;
 	struct mlx4_icm	       *fw_icm;
 	struct mlx4_icm	       *aux_icm;
 	u32			catas_size;
@@ -395,6 +397,7 @@ struct mlx4_fw {
 	u8			clr_int_bar;
 	u8			catas_bar;
 	u8			comm_bar;
+	u8			clock_bar;
 };
 
 struct mlx4_comm {
@@ -805,6 +808,7 @@ struct mlx4_priv {
 	struct list_head	bf_list;
 	struct mutex		bf_mutex;
 	struct io_mapping	*bf_mapping;
+	void __iomem            *clock_mapping;
 	int			reserved_mtts;
 	int			fs_hash_mode;
 };
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index e482e6b..e094c48 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -390,6 +390,7 @@ struct mlx4_caps {
 	enum mlx4_port_type	possible_type[MLX4_MAX_PORTS + 1];
 	u32			max_counters;
 	u8			port_ib_mtu[MLX4_MAX_PORTS + 1];
+	u16			hca_core_clock;
 };
 
 struct mlx4_buf_list {
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-09-28 10:03 [PATCH 0/3] net/mlx4: HW Timestamp support Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 1/3] net/mlx4_core: Add timestamping device capability Yevgeny Petrilin
  2012-09-28 10:03 ` [PATCH 2/3] net/mlx4_core: Read HCA frequency and map internal clock Yevgeny Petrilin
@ 2012-09-28 10:03 ` Yevgeny Petrilin
  2012-09-28 11:11   ` Richard Cochran
  2012-10-01 15:08   ` Ben Hutchings
  2 siblings, 2 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-09-28 10:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, eugenia

From: Eugenia Emantayev <eugenia@mellanox.co.il>

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.co.il>
Reviewed-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
---
 drivers/infiniband/hw/mlx4/cq.c                   |    2 +-
 drivers/net/ethernet/mellanox/mlx4/Makefile       |    2 +-
 drivers/net/ethernet/mellanox/mlx4/cq.c           |   10 +-
 drivers/net/ethernet/mellanox/mlx4/en_cq.c        |   10 +-
 drivers/net/ethernet/mellanox/mlx4/en_main.c      |    5 +
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c    |   60 ++++++++
 drivers/net/ethernet/mellanox/mlx4/en_resources.c |    3 +
 drivers/net/ethernet/mellanox/mlx4/en_rx.c        |   28 +++-
 drivers/net/ethernet/mellanox/mlx4/en_timestamp.c |  153 +++++++++++++++++++++
 drivers/net/ethernet/mellanox/mlx4/en_tx.c        |   33 ++++-
 drivers/net/ethernet/mellanox/mlx4/main.c         |   22 +++
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h      |   21 +++
 include/linux/mlx4/cq.h                           |   16 ++
 include/linux/mlx4/device.h                       |    6 +-
 14 files changed, 354 insertions(+), 17 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx4/en_timestamp.c

diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 6d4ef71c..a996de6 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -226,7 +226,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];
 
 	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)
 		goto err_dbmap;
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile
index 293127d..b99a7f2 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 \
 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 \
-		en_resources.o en_netdev.o en_selftest.o
+		en_resources.o en_netdev.o en_selftest.o en_timestamp.o
 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 7e64033..a681bf5 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)
 		__mlx4_cq_free_icm(dev, cqn);
 }
 
-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,
-		  unsigned vector, int collapsed)
+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, unsigned vector, int collapsed,
+		  int timestamp_en)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	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,
 	memset(cq_context, 0, sizeof *cq_context);
 
 	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->comp_eqn	    = priv->eq_table.eq[vector].eqn;
 	cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index aa9c2f6..59d8318 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,
 	struct mlx4_en_dev *mdev = priv->mdev;
 	int err = 0;
 	char name[25];
+	int timestamp_en = 0;
 	struct cpu_rmap *rmap =
 #ifdef CONFIG_RFS_ACCEL
 		priv->dev->rx_cpu_rmap;
@@ -123,8 +124,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
 	if (!cq->is_tx)
 		cq->size = priv->rx_ring[cq->ring].actual_size;
 
-	err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
-			    cq->wqres.db.dma, &cq->mcq, cq->vector, 0);
+	if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
+	    (!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)
 		return err;
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index a52922e..d14f8f8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -280,6 +280,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
 		if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
 			mdev->pndev[i] = NULL;
 	}
+
+	/* Initialize time stamp mechanism */
+	if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS_EN)
+		mlx4_en_init_timestamp(mdev);
+
 	return mdev;
 
 err_mr:
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index edd9cb8..10fa453 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1517,6 +1517,60 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
 	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_EN))
+		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:
+	case 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,
 		netdev_features_t features)
 {
@@ -1542,6 +1596,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 	.ndo_set_mac_address	= mlx4_en_set_mac,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= mlx4_en_change_mtu,
+	.ndo_do_ioctl		= mlx4_en_ioctl,
 	.ndo_tx_timeout		= mlx4_en_tx_timeout,
 	.ndo_vlan_rx_add_vid	= mlx4_en_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= mlx4_en_vlan_rx_kill_vid,
@@ -1629,6 +1684,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	if (err)
 		goto out;
 
+	/* 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 */
 	err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
 				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 10c24c7..bfc9be8 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,
 			     int user_prio, struct mlx4_qp_context *context)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct net_device *dev = priv->dev;
 
 	memset(context, 0, sizeof *context);
 	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,
 	context->cqn_send = cpu_to_be32(cqn);
 	context->cqn_recv = cpu_to_be32(cqn);
 	context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
+	if (!(dev->features & NETIF_F_HW_VLAN_RX))
+		context->param3 |= cpu_to_be32(1 << 30);
 }
 
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 5aba5ec..2d8827c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -319,6 +319,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 	}
 	ring->buf = ring->wqres.buf.direct.buf;
 
+	ring->hwtstamp_rx_filter = priv->hwtstamp_config.rx_filter;
+
 	return 0;
 
 err_hwq:
@@ -553,6 +555,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)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_cqe *cqe;
 	struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
 	struct mlx4_en_rx_alloc *frags;
@@ -566,6 +569,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 	struct ethhdr *ethh;
 	dma_addr_t dma;
 	u64 s_mac;
+	u64 timestamp;
 
 	if (!priv->port_up)
 		return 0;
@@ -651,8 +655,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->ip_summed = CHECKSUM_UNNECESSARY;
 
-					if (cqe->vlan_my_qpn &
-					    cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) {
+					if ((cqe->vlan_my_qpn &
+					    cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
+					    (dev->features & NETIF_F_HW_VLAN_RX)) {
 						u16 vid = be16_to_cpu(cqe->sl_vid);
 
 						__vlan_hwaccel_put_tag(gro_skb, vid);
@@ -662,8 +667,14 @@ 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);
 
 					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;
 				}
 
@@ -696,10 +707,17 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 		if (dev->features & NETIF_F_RXHASH)
 			skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
 
-		if (be32_to_cpu(cqe->vlan_my_qpn) &
-		    MLX4_CQE_VLAN_PRESENT_MASK)
+		if ((be32_to_cpu(cqe->vlan_my_qpn) &
+			MLX4_CQE_VLAN_PRESENT_MASK) &&
+			(dev->features & NETIF_F_HW_VLAN_RX))
 			__vlan_hwaccel_put_tag(skb, 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 */
 		netif_receive_skb(skb);
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_timestamp.c b/drivers/net/ethernet/mellanox/mlx4/en_timestamp.c
new file mode 100644
index 0000000..9b997c5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx4/en_timestamp.c
@@ -0,0 +1,153 @@
+/*
+ * 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"
+
+#define CORE_CLOCK_MASK 0xffffffffffffULL
+
+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);
+	}
+
+	mlx4_en_free_resources(priv);
+
+	en_err(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_RX;
+	else
+		dev->features |= NETIF_F_HW_VLAN_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);
+	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) & CORE_CLOCK_MASK;
+}
+
+u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
+{
+	u64 ts;
+	struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;
+
+	ts = (u64) be32_to_cpu(ts_cqe->timestamp_hi) << 16
+		| (u64) be16_to_cpu(ts_cqe->timestamp_lo);
+
+	return ts;
+}
+
+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);
+
+	/*
+	 * force a timecompare_update here (even if less than a second
+	 * has passed) in order to prevent the case when ptpd or other
+	 * software jumps the clock offset. othwerise there is a small
+	 * window when the timestamp would be based on previous skew
+	 * and invalid results would be pushed to the network stack.
+	 */
+	timecompare_update(&mdev->compare, 0);
+	memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
+	hwts->hwtstamp = ns_to_ktime(nsec);
+	hwts->syststamp = timecompare_transform(&mdev->compare, nsec);
+}
+
+void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
+{
+	struct mlx4_dev *dev = mdev->dev;
+	u64 temp_mult;
+
+	memset(&mdev->cycles, 0, sizeof(mdev->cycles));
+	mdev->cycles.read = mlx4_en_read_clock;
+	mdev->cycles.mask = CLOCKSOURCE_MASK(48);
+
+	/*
+	 * we have hca_core_clock in MHz, so to translate cycles to nsecs
+	 * we need to divide cycles by freq and multiply by 1000;
+	 * in order to get precise result we shift left the value,
+	 * since we don't have floating point there;
+	 * at the end shift result back
+	 */
+	temp_mult = ((1ull * 1000) << 29) / dev->caps.hca_core_clock;
+	mdev->cycles.mult = (u32)temp_mult;
+	mdev->cycles.shift = 29;
+
+	timecounter_init(&mdev->clock, &mdev->cycles,
+			 ktime_to_ns(ktime_get_real()));
+
+	memset(&mdev->compare, 0, sizeof(mdev->compare));
+	mdev->compare.source = &mdev->clock;
+	mdev->compare.target = ktime_get_real;
+	mdev->compare.num_samples = 10;
+	timecompare_update(&mdev->compare, 0);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 10bba09..35d462d 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,
 	} else
 		ring->bf_enabled = true;
 
+	ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
+
 	return 0;
 
 err_map:
@@ -193,8 +195,9 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
 
 static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 				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_desc *tx_desc = ring->buf + index * TXBB_SIZE;
 	struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
@@ -205,6 +208,12 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 	int i;
 	__be32 *ptr = (__be32 *)tx_desc;
 	__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 */
 	if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
@@ -290,7 +299,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
 	while (ring->cons != ring->prod) {
 		ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
 						ring->cons & ring->size_mask,
-						!!(ring->cons & ring->size));
+						!!(ring->cons & ring->size), 0);
 		ring->cons += ring->last_nr_txbb;
 		cnt++;
 	}
@@ -316,6 +325,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 	struct mlx4_cqe *buf = cq->buf;
 	u32 packets = 0;
 	u32 bytes = 0;
+	u64 timestamp = 0;
+	struct mlx4_en_tx_info *tx_info;
 
 	if (!priv->port_up)
 		return;
@@ -323,6 +334,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 	index = cons_index & size_mask;
 	cqe = &buf[index];
 	ring_index = ring->cons & size_mask;
+	tx_info = &ring->tx_info[ring_index];
 
 	/* Process all completed CQEs */
 	while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
@@ -336,6 +348,9 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 		/* Skip over last polled CQE */
 		new_index = be16_to_cpu(cqe->wqe_index) & size_mask;
 
+		if (tx_info->ts_requested)
+			timestamp = mlx4_en_get_cqe_ts(cqe);
+
 		do {
 			txbbs_skipped += ring->last_nr_txbb;
 			ring_index = (ring_index + ring->last_nr_txbb) & size_mask;
@@ -343,7 +358,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 			ring->last_nr_txbb = mlx4_en_free_tx_desc(
 					priv, ring, ring_index,
 					!!((ring->cons + txbbs_skipped) &
-							ring->size));
+					ring->size), timestamp);
 			packets++;
 			bytes += ring->tx_info[ring_index].nr_bytes;
 		} while (ring_index != new_index);
@@ -617,6 +632,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 	tx_info->skb = skb;
 	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
 	 * whether LSO is used */
 	tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
@@ -713,7 +738,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 		tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
 
 	/* Run destructor before passing skb to HW */
-	if (likely(!skb_shared(skb)))
+	if (likely(!skb_shared(skb)) && !tx_info->ts_requested)
 		skb_orphan(skb);
 
 	if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 60c159a..bc0ac9e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1127,6 +1127,28 @@ static void unmap_bf_area(struct mlx4_dev *dev)
 		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)
 {
 	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 9d27e42..082dafe 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -40,6 +40,8 @@
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
+#include <linux/timecompare.h>
 #ifdef CONFIG_MLX4_EN_DCB
 #include <linux/dcbnl.h>
 #endif
@@ -207,6 +209,7 @@ struct mlx4_en_tx_info {
 	u8 linear;
 	u8 data_offset;
 	u8 inl;
+	u8 ts_requested;
 };
 
 
@@ -262,6 +265,7 @@ struct mlx4_en_tx_ring {
 	struct mlx4_bf bf;
 	bool bf_enabled;
 	struct netdev_queue *tx_queue;
+	int hwtstamp_tx_type;
 };
 
 struct mlx4_en_rx_desc {
@@ -288,6 +292,7 @@ struct mlx4_en_rx_ring {
 	unsigned long packets;
 	unsigned long csum_ok;
 	unsigned long csum_none;
+	int hwtstamp_rx_filter;
 };
 
 
@@ -363,6 +368,9 @@ struct mlx4_en_dev {
 	u32                     priv_pdn;
 	spinlock_t              uar_lock;
 	u8			mac_removed[MLX4_MAX_PORTS + 1];
+	struct cyclecounter	cycles;
+	struct timecounter	clock;
+	struct timecompare	compare;
 };
 
 
@@ -522,6 +530,7 @@ struct mlx4_en_priv {
 	bool wol;
 	struct device *ddev;
 	int base_tx_qpn;
+	struct hwtstamp_config hwtstamp_config;
 
 #ifdef CONFIG_MLX4_EN_DCB
 	struct ieee_ets ets;
@@ -623,6 +632,18 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
 u64 mlx4_en_mac_to_u64(u8 *addr);
 
 /*
+ * 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;
diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h
index 6f65b2c..98fa492 100644
--- a/include/linux/mlx4/cq.h
+++ b/include/linux/mlx4/cq.h
@@ -64,6 +64,22 @@ struct mlx4_err_cqe {
 	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 {
 	MLX4_CQE_VLAN_PRESENT_MASK	= 1 << 29,
 	MLX4_CQE_QPN_MASK		= 0xffffff,
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index e094c48..c0f3ca0 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -40,6 +40,8 @@
 
 #include <linux/atomic.h>
 
+#include <linux/clocksource.h>
+
 #define MAX_MSIX_P_PORT		17
 #define MAX_MSIX		64
 #define MSIX_LEGACY_SZ		4
@@ -753,7 +755,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,
 		  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);
 
 int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
@@ -931,4 +933,6 @@ int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id);
 
 int mlx4_get_parav_qkey(struct mlx4_dev *dev, u32 qpn, u32 *qkey);
 
+cycle_t mlx4_read_clock(struct mlx4_dev *dev);
+
 #endif /* MLX4_DEVICE_H */
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-09-28 10:03 ` [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support Yevgeny Petrilin
@ 2012-09-28 11:11   ` Richard Cochran
  2012-09-28 14:10     ` Yevgeny Petrilin
  2012-10-04 14:08     ` Eugenia Emantayev
  2012-10-01 15:08   ` Ben Hutchings
  1 sibling, 2 replies; 12+ messages in thread
From: Richard Cochran @ 2012-09-28 11:11 UTC (permalink / raw)
  To: Yevgeny Petrilin; +Cc: davem, netdev, eugenia

On Fri, Sep 28, 2012 at 12:03:23PM +0200, Yevgeny Petrilin wrote:
> From: Eugenia Emantayev <eugenia@mellanox.co.il>
> 

...

> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> index edd9cb8..10fa453 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> @@ -1517,6 +1517,60 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
>  	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_EN))
> +		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:
> +	case HWTSTAMP_FILTER_ALL:
> +		break;
> +	default:

Instead of rejecting the HWTSTAMP_FILTER_PTP_ codes out of hand, you
should just accept them, and return by promoting rx_filter to
HWTSTAMP_FILTER_ALL.

[ See Documentation/networking/timestamping.txt ]

> +		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;
> +}

...

> @@ -363,6 +368,9 @@ struct mlx4_en_dev {
>  	u32                     priv_pdn;
>  	spinlock_t              uar_lock;
>  	u8			mac_removed[MLX4_MAX_PORTS + 1];
> +	struct cyclecounter	cycles;
> +	struct timecounter	clock;
> +	struct timecompare	compare;

I am working on a patch to remove the timecompare stuff altogether
(after removing it from blackfin). It is and was a bad idea, I would
hate to see new drivers using it.

I strongly recommend just offering raw hardware time stamps in
nanosecond resolution. Also, why not expose your device as a PTP
Hardware Clock?

Thanks,
Richard

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-09-28 11:11   ` Richard Cochran
@ 2012-09-28 14:10     ` Yevgeny Petrilin
  2012-10-04 14:08     ` Eugenia Emantayev
  1 sibling, 0 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-09-28 14:10 UTC (permalink / raw)
  To: Richard Cochran; +Cc: davem, netdev, Eugenia Emantayev

> > diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > index edd9cb8..10fa453 100644
> > --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > @@ -1517,6 +1517,60 @@ static int mlx4_en_change_mtu(struct net_device
> *dev, int new_mtu)
> >  	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_EN))
> > +		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:
> > +	case HWTSTAMP_FILTER_ALL:
> > +		break;
> > +	default:
> 
> Instead of rejecting the HWTSTAMP_FILTER_PTP_ codes out of hand, you
> should just accept them, and return by promoting rx_filter to
> HWTSTAMP_FILTER_ALL.
> 
> [ See Documentation/networking/timestamping.txt ]
> 
> > +		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;
> > +}
> 
> ...
> 
> > @@ -363,6 +368,9 @@ struct mlx4_en_dev {
> >  	u32                     priv_pdn;
> >  	spinlock_t              uar_lock;
> >  	u8			mac_removed[MLX4_MAX_PORTS + 1];
> > +	struct cyclecounter	cycles;
> > +	struct timecounter	clock;
> > +	struct timecompare	compare;
> 
> I am working on a patch to remove the timecompare stuff altogether
> (after removing it from blackfin). It is and was a bad idea, I would
> hate to see new drivers using it.
> 
> I strongly recommend just offering raw hardware time stamps in
> nanosecond resolution. Also, why not expose your device as a PTP
> Hardware Clock?
> 
> Thanks,
> Richard

Hello Richard,
Thanks for your feedback,
Will address all your comments in V1 of this patchset.

Thanks,
Yevgeny 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-09-28 10:03 ` [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support Yevgeny Petrilin
  2012-09-28 11:11   ` Richard Cochran
@ 2012-10-01 15:08   ` Ben Hutchings
  2012-10-02  7:32     ` Yevgeny Petrilin
  1 sibling, 1 reply; 12+ messages in thread
From: Ben Hutchings @ 2012-10-01 15:08 UTC (permalink / raw)
  To: Yevgeny Petrilin; +Cc: davem, netdev, eugenia

On Fri, 2012-09-28 at 12:03 +0200, Yevgeny Petrilin wrote:
> From: Eugenia Emantayev <eugenia@mellanox.co.il>
> 
> 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.
[...]
> --- /dev/null
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_timestamp.c
[...]
> +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);
> +	}
> +
> +	mlx4_en_free_resources(priv);
> +
> +	en_err(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_RX;
> +	else
> +		dev->features |= NETIF_F_HW_VLAN_RX;
[...]

If you change dev->features you should also call
netdev_features_change(dev) (holding only the RTNL lock, so after you
unlock mdev->state_lock).

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-10-01 15:08   ` Ben Hutchings
@ 2012-10-02  7:32     ` Yevgeny Petrilin
  0 siblings, 0 replies; 12+ messages in thread
From: Yevgeny Petrilin @ 2012-10-02  7:32 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: davem, netdev, Eugenia Emantayev

> > +
> > +	if (rx_filter != HWTSTAMP_FILTER_NONE)
> > +		dev->features &= ~NETIF_F_HW_VLAN_RX;
> > +	else
> > +		dev->features |= NETIF_F_HW_VLAN_RX;
> [...]
> 
> If you change dev->features you should also call
> netdev_features_change(dev) (holding only the RTNL lock, so after you
> unlock mdev->state_lock).
> 
> Ben.
> 
Thanks Ben,
Will fix.

Yevgeny

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-09-28 11:11   ` Richard Cochran
  2012-09-28 14:10     ` Yevgeny Petrilin
@ 2012-10-04 14:08     ` Eugenia Emantayev
  2012-10-04 14:27       ` Richard Cochran
  1 sibling, 1 reply; 12+ messages in thread
From: Eugenia Emantayev @ 2012-10-04 14:08 UTC (permalink / raw)
  To: Richard Cochran, Yevgeny Petrilin; +Cc: davem, netdev, Or Gerlitz

> Also, why not expose your device as a PTP Hardware Clock?

Hello Richard,
Could you please clarify the above?
What do you mean by expose your device as a PTP Hardware Clock?

Thanks,
Eugenia

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-10-04 14:08     ` Eugenia Emantayev
@ 2012-10-04 14:27       ` Richard Cochran
  2012-10-04 20:58         ` Eugenia Emantayev
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Cochran @ 2012-10-04 14:27 UTC (permalink / raw)
  To: Eugenia Emantayev; +Cc: Yevgeny Petrilin, davem, netdev, Or Gerlitz

On Thu, Oct 04, 2012 at 02:08:29PM +0000, Eugenia Emantayev wrote:
> > Also, why not expose your device as a PTP Hardware Clock?
> 
> Hello Richard,
> Could you please clarify the above?
> What do you mean by expose your device as a PTP Hardware Clock?

You could register the driver as PHC class device, described in

   Documentation/ptp/ptp.txt

and then you device will work together along with a user space PTP
stack, like the one I wrote at

   http://linuxptp.sourceforge.net

Thanks,
Richard

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-10-04 14:27       ` Richard Cochran
@ 2012-10-04 20:58         ` Eugenia Emantayev
  2012-10-05 10:38           ` Richard Cochran
  0 siblings, 1 reply; 12+ messages in thread
From: Eugenia Emantayev @ 2012-10-04 20:58 UTC (permalink / raw)
  To: Richard Cochran; +Cc: Yevgeny Petrilin, davem, netdev, Or Gerlitz

> You could register the driver as PHC class device, described in
>
>   Documentation/ptp/ptp.txt
>
> and then you device will work together along with a user space PTP stack, like the one I wrote at
>
>   http://linuxptp.sourceforge.net


Richard,

Thanks for the explanation.
At this stage we prefer to submit the initial patch set (V1) and then, at the next phase,
extend it as you suggested above, after learning and better understanding the requirements
and effects.

Regards,
Eugenia

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
  2012-10-04 20:58         ` Eugenia Emantayev
@ 2012-10-05 10:38           ` Richard Cochran
  0 siblings, 0 replies; 12+ messages in thread
From: Richard Cochran @ 2012-10-05 10:38 UTC (permalink / raw)
  To: Eugenia Emantayev; +Cc: Yevgeny Petrilin, davem, netdev, Or Gerlitz

On Thu, Oct 04, 2012 at 08:58:59PM +0000, Eugenia Emantayev wrote:
> > You could register the driver as PHC class device, described in
> >
> >   Documentation/ptp/ptp.txt
> >
> > and then you device will work together along with a user space PTP stack, like the one I wrote at
> >
> >   http://linuxptp.sourceforge.net
> 
> 
> Richard,
> 
> Thanks for the explanation.
> At this stage we prefer to submit the initial patch set (V1) and then, at the next phase,
> extend it as you suggested above, after learning and better understanding the requirements
> and effects.

Well, if you want to provide a way to relate your hardware time stamps
with the system time, then you need to implement the PHC.  Please do
not make use of the timecompare code in your driver, since it is going
to be removed soon.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-10-05 10:38 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-28 10:03 [PATCH 0/3] net/mlx4: HW Timestamp support Yevgeny Petrilin
2012-09-28 10:03 ` [PATCH 1/3] net/mlx4_core: Add timestamping device capability Yevgeny Petrilin
2012-09-28 10:03 ` [PATCH 2/3] net/mlx4_core: Read HCA frequency and map internal clock Yevgeny Petrilin
2012-09-28 10:03 ` [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support Yevgeny Petrilin
2012-09-28 11:11   ` Richard Cochran
2012-09-28 14:10     ` Yevgeny Petrilin
2012-10-04 14:08     ` Eugenia Emantayev
2012-10-04 14:27       ` Richard Cochran
2012-10-04 20:58         ` Eugenia Emantayev
2012-10-05 10:38           ` Richard Cochran
2012-10-01 15:08   ` Ben Hutchings
2012-10-02  7:32     ` Yevgeny Petrilin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).