Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a875509 authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller
Browse files

net: thunderx: add timestamping support



This adds timestamping support for both receive and transmit
paths. On the receive side no filters are supported i.e either
all pkts will get a timestamp appended infront of the packet or none.
On the transmit side HW doesn't support timestamp insertion but
only generates a separate CQE with transmitted packet's timestamp.
Also HW supports only one packet at a time for timestamping on the
transmit side.

Signed-off-by: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarAleksey Makarov <aleksey.makarov@cavium.com>
Acked-by: default avatarPhilippe Ombredanne <pombredanne@nexb.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8c56df37
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ config THUNDER_NIC_PF

config THUNDER_NIC_VF
	tristate "Thunder Virtual function driver"
	imply CAVIUM_PTP
	depends on 64BIT
	---help---
	  This driver supports Thunder's NIC virtual function
+36 −0
Original line number Diff line number Diff line
@@ -263,6 +263,8 @@ struct nicvf_drv_stats {
	struct u64_stats_sync   syncp;
};

struct cavium_ptp;

struct nicvf {
	struct nicvf		*pnicvf;
	struct net_device	*netdev;
@@ -312,6 +314,33 @@ struct nicvf {
	struct tasklet_struct	qs_err_task;
	struct work_struct	reset_task;

	/* PTP timestamp */
	struct cavium_ptp	*ptp_clock;
	/* Inbound timestamping is on */
	bool			hw_rx_tstamp;
	/* When the packet that requires timestamping is sent, hardware inserts
	 * two entries to the completion queue.  First is the regular
	 * CQE_TYPE_SEND entry that signals that the packet was sent.
	 * The second is CQE_TYPE_SEND_PTP that contains the actual timestamp
	 * for that packet.
	 * `ptp_skb` is initialized in the handler for the CQE_TYPE_SEND
	 * entry and is used and zeroed in the handler for the CQE_TYPE_SEND_PTP
	 * entry.
	 * So `ptp_skb` is used to hold the pointer to the packet between
	 * the calls to CQE_TYPE_SEND and CQE_TYPE_SEND_PTP handlers.
	 */
	struct sk_buff		*ptp_skb;
	/* `tx_ptp_skbs` is set when the hardware is sending a packet that
	 * requires timestamping.  Cavium hardware can not process more than one
	 * such packet at once so this is set each time the driver submits
	 * a packet that requires timestamping to the send queue and clears
	 * each time it receives the entry on the completion queue saying
	 * that such packet was sent.
	 * So `tx_ptp_skbs` prevents driver from submitting more than one
	 * packet that requires timestamping to the hardware for transmitting.
	 */
	atomic_t		tx_ptp_skbs;

	/* Interrupt coalescing settings */
	u32			cq_coalesce_usecs;
	u32			msg_enable;
@@ -371,6 +400,7 @@ struct nicvf {
#define	NIC_MBOX_MSG_LOOPBACK		0x16	/* Set interface in loopback */
#define	NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17	/* Reset statistics counters */
#define	NIC_MBOX_MSG_PFC		0x18	/* Pause frame control */
#define	NIC_MBOX_MSG_PTP_CFG		0x19	/* HW packet timestamp */
#define	NIC_MBOX_MSG_CFG_DONE		0xF0	/* VF configuration done */
#define	NIC_MBOX_MSG_SHUTDOWN		0xF1	/* VF is being shutdown */

@@ -521,6 +551,11 @@ struct pfc {
	u8    fc_tx;
};

struct set_ptp {
	u8    msg;
	bool  enable;
};

/* 128 bit shared memory between PF and each VF */
union nic_mbx {
	struct { u8 msg; }	msg;
@@ -540,6 +575,7 @@ union nic_mbx {
	struct set_loopback	lbk;
	struct reset_stat_cfg	reset_stat;
	struct pfc		pfc;
	struct set_ptp		ptp;
};

#define NIC_NODE_ID_MASK	0x03
+53 −3
Original line number Diff line number Diff line
@@ -426,13 +426,22 @@ static void nic_init_hw(struct nicpf *nic)
	/* Enable backpressure */
	nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03);

	/* TNS and TNS bypass modes are present only on 88xx */
	/* TNS and TNS bypass modes are present only on 88xx
	 * Also offset of this CSR has changed in 81xx and 83xx.
	 */
	if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) {
		/* Disable TNS mode on both interfaces */
		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
			      (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
			      (NIC_TNS_BYPASS_MODE << 7) |
			      BGX0_BLOCK | (1ULL << 16));
		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
			      (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
			      (NIC_TNS_BYPASS_MODE << 7) |
			      BGX1_BLOCK | (1ULL << 16));
	} else {
		/* Configure timestamp generation timeout to 10us */
		for (i = 0; i < nic->hw->bgx_cnt; i++)
			nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3),
				      (1ULL << 16));
	}

	nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
@@ -880,6 +889,44 @@ static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg)
	}
}

/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */
static void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp)
{
	struct pkind_cfg *pkind;
	u8 lmac, bgx_idx;
	u64 pkind_val, pkind_idx;

	if (vf >= nic->num_vf_en)
		return;

	bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);

	pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX;
	pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3));
	pkind = (struct pkind_cfg *)&pkind_val;

	if (ptp->enable && !pkind->hdr_sl) {
		/* Skiplen to exclude 8byte timestamp while parsing pkt
		 * If not configured, will result in L2 errors.
		 */
		pkind->hdr_sl = 4;
		/* Adjust max packet length allowed */
		pkind->maxlen += (pkind->hdr_sl * 2);
		bgx_config_timestamping(nic->node, bgx_idx, lmac, true);
		nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3),
			      (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588);
	} else if (!ptp->enable && pkind->hdr_sl) {
		pkind->maxlen -= (pkind->hdr_sl * 2);
		pkind->hdr_sl = 0;
		bgx_config_timestamping(nic->node, bgx_idx, lmac, false);
		nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3),
			      (ETYPE_ALG_SKIP << 16) | ETH_P_8021Q);
	}

	nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val);
}

/* Interrupt handler to handle mailbox messages from VFs */
static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
{
@@ -1022,6 +1069,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
	case NIC_MBOX_MSG_PFC:
		nic_pause_frame(nic, vf, &mbx.pfc);
		goto unlock;
	case NIC_MBOX_MSG_PTP_CFG:
		nic_config_timestamp(nic, vf, &mbx.ptp);
		break;
	default:
		dev_err(&nic->pdev->dev,
			"Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@
#define   NIC_PF_ECC3_DBE_INT_W1S		(0x2708)
#define   NIC_PF_ECC3_DBE_ENA_W1C		(0x2710)
#define   NIC_PF_ECC3_DBE_ENA_W1S		(0x2718)
#define   NIC_PF_INTFX_SEND_CFG			(0x4000)
#define   NIC_PF_MCAM_0_191_ENA			(0x100000)
#define   NIC_PF_MCAM_0_191_M_0_5_DATA		(0x110000)
#define   NIC_PF_MCAM_CTRL			(0x120000)
+28 −1
Original line number Diff line number Diff line
@@ -9,12 +9,14 @@
/* ETHTOOL Support for VNIC_VF Device*/

#include <linux/pci.h>
#include <linux/net_tstamp.h>

#include "nic_reg.h"
#include "nic.h"
#include "nicvf_queues.h"
#include "q_struct.h"
#include "thunder_bgx.h"
#include "../common/cavium_ptp.h"

#define DRV_NAME	"thunder-nicvf"
#define DRV_VERSION     "1.0"
@@ -824,6 +826,31 @@ static int nicvf_set_pauseparam(struct net_device *dev,
	return 0;
}

static int nicvf_get_ts_info(struct net_device *netdev,
			     struct ethtool_ts_info *info)
{
	struct nicvf *nic = netdev_priv(netdev);

	if (!nic->ptp_clock)
		return ethtool_op_get_ts_info(netdev, info);

	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
				SOF_TIMESTAMPING_RX_SOFTWARE |
				SOF_TIMESTAMPING_SOFTWARE |
				SOF_TIMESTAMPING_TX_HARDWARE |
				SOF_TIMESTAMPING_RX_HARDWARE |
				SOF_TIMESTAMPING_RAW_HARDWARE;

	info->phc_index = cavium_ptp_clock_index(nic->ptp_clock);

	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
			   (1 << HWTSTAMP_FILTER_ALL);

	return 0;
}

static const struct ethtool_ops nicvf_ethtool_ops = {
	.get_link		= nicvf_get_link,
	.get_drvinfo		= nicvf_get_drvinfo,
@@ -847,7 +874,7 @@ static const struct ethtool_ops nicvf_ethtool_ops = {
	.set_channels		= nicvf_set_channels,
	.get_pauseparam         = nicvf_get_pauseparam,
	.set_pauseparam         = nicvf_set_pauseparam,
	.get_ts_info		= ethtool_op_get_ts_info,
	.get_ts_info		= nicvf_get_ts_info,
	.get_link_ksettings	= nicvf_get_link_ksettings,
};

Loading