]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ethernet/mellanox/mlx4/en_tx.c
net/mlx4_en: Add HW timestamping (TS) support
[~andy/linux] / drivers / net / ethernet / mellanox / mlx4 / en_tx.c
index 49308cc65ee7f48a786fa25c993a72c4cecc7361..b0a2d2b96e439b41044af7824cf496141cfc82f9 100644 (file)
@@ -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:
@@ -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,
                                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;
@@ -204,6 +207,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)) {
@@ -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) {
                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++;
        }
@@ -318,6 +327,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        u32 packets = 0;
        u32 bytes = 0;
        int factor = priv->cqe_factor;
+       u64 timestamp = 0;
 
        if (!priv->port_up)
                return;
@@ -341,11 +351,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
                do {
                        txbbs_skipped += ring->last_nr_txbb;
                        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 */
                        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);
@@ -629,6 +642,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);