Commit c9c12d33 authored by Aleksey Makarov's avatar Aleksey Makarov Committed by David S. Miller
Browse files

octeontx2-pf: Add support for PTP clock



This patch adds PTP clock and uses it in Octeontx2
network device. PTP clock uses mailbox calls to
access the hardware counter on the RVU side.

Co-developed-by: default avatarSubbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: default avatarSubbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: default avatarAleksey Makarov <amakarov@marvell.com>
Signed-off-by: default avatarSunil Goutham <sgoutham@marvell.com>
Acked-by: default avatarRichard Cochran <richardcochran@gmail.com>
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Reviewed-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4086f2a0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@
obj-$(CONFIG_OCTEONTX2_PF) += octeontx2_nicpf.o
obj-$(CONFIG_OCTEONTX2_VF) += octeontx2_nicvf.o

octeontx2_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o
octeontx2_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
		     otx2_ptp.o
octeontx2_nicvf-y := otx2_vf.o

ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
+7 −0
Original line number Diff line number Diff line
@@ -671,6 +671,13 @@ static int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
	if (!sq->sg)
		return -ENOMEM;

	if (pfvf->ptp) {
		err = qmem_alloc(pfvf->dev, &sq->timestamps, qset->sqe_cnt,
				 sizeof(*sq->timestamps));
		if (err)
			return err;
	}

	sq->head = 0;
	sq->sqe_per_sqb = (pfvf->hw.sqb_size / sq->sqe_size) - 1;
	sq->num_sqbs = (qset->sqe_cnt + sq->sqe_per_sqb) / sq->sqe_per_sqb;
+19 −0
Original line number Diff line number Diff line
@@ -13,6 +13,9 @@

#include <linux/pci.h>
#include <linux/iommu.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>

#include <mbox.h>
#include "otx2_reg.h"
@@ -209,6 +212,17 @@ struct refill_work {
	struct otx2_nic *pf;
};

struct otx2_ptp {
	struct ptp_clock_info ptp_info;
	struct ptp_clock *ptp_clock;
	struct otx2_nic *nic;

	struct cyclecounter cycle_counter;
	struct timecounter time_counter;
};

#define OTX2_HW_TIMESTAMP_LEN	8

struct otx2_nic {
	void __iomem		*reg_base;
	struct net_device	*netdev;
@@ -216,6 +230,8 @@ struct otx2_nic {
	u16			max_frs;
	u16			rbsize; /* Receive buffer size */

#define OTX2_FLAG_RX_TSTAMP_ENABLED		BIT_ULL(0)
#define OTX2_FLAG_TX_TSTAMP_ENABLED		BIT_ULL(1)
#define OTX2_FLAG_INTF_DOWN			BIT_ULL(2)
#define OTX2_FLAG_RX_PAUSE_ENABLED		BIT_ULL(9)
#define OTX2_FLAG_TX_PAUSE_ENABLED		BIT_ULL(10)
@@ -251,6 +267,9 @@ struct otx2_nic {

	/* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
	int			nix_blkaddr;

	struct otx2_ptp		*ptp;
	struct hwtstamp_config	tstamp;
};

static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
+28 −0
Original line number Diff line number Diff line
@@ -13,8 +13,10 @@
#include <linux/stddef.h>
#include <linux/etherdevice.h>
#include <linux/log2.h>
#include <linux/net_tstamp.h>

#include "otx2_common.h"
#include "otx2_ptp.h"

#define DRV_NAME	"octeontx2-nicpf"
#define DRV_VF_NAME	"octeontx2-nicvf"
@@ -663,6 +665,31 @@ static u32 otx2_get_link(struct net_device *netdev)
	return pfvf->linfo.link_up;
}

static int otx2_get_ts_info(struct net_device *netdev,
			    struct ethtool_ts_info *info)
{
	struct otx2_nic *pfvf = netdev_priv(netdev);

	if (!pfvf->ptp)
		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 = otx2_ptp_clock_index(pfvf);

	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 otx2_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
				     ETHTOOL_COALESCE_MAX_FRAMES,
@@ -687,6 +714,7 @@ static const struct ethtool_ops otx2_ethtool_ops = {
	.set_msglevel		= otx2_set_msglevel,
	.get_pauseparam		= otx2_get_pauseparam,
	.set_pauseparam		= otx2_set_pauseparam,
	.get_ts_info		= otx2_get_ts_info,
};

void otx2_set_ethtool_ops(struct net_device *netdev)
+166 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "otx2_common.h"
#include "otx2_txrx.h"
#include "otx2_struct.h"
#include "otx2_ptp.h"

#define DRV_NAME	"octeontx2-nicpf"
#define DRV_STRING	"Marvell OcteonTX2 NIC Physical Function Driver"
@@ -41,6 +42,9 @@ enum {
	TYPE_PFVF,
};

static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable);
static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable);

static int otx2_change_mtu(struct net_device *netdev, int new_mtu)
{
	bool if_up = netif_running(netdev);
@@ -1281,7 +1285,8 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
	hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt;

	/* Get the size of receive buffers to allocate */
	pf->rbsize = RCV_FRAG_LEN(pf->netdev->mtu + OTX2_ETH_HLEN);
	pf->rbsize = RCV_FRAG_LEN(OTX2_HW_TIMESTAMP_LEN + pf->netdev->mtu +
				  OTX2_ETH_HLEN);

	mutex_lock(&mbox->lock);
	/* NPA init */
@@ -1547,6 +1552,16 @@ int otx2_open(struct net_device *netdev)

	otx2_set_cints_affinity(pf);

	/* When reinitializing enable time stamping if it is enabled before */
	if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED) {
		pf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
		otx2_config_hw_tx_tstamp(pf, true);
	}
	if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED) {
		pf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
		otx2_config_hw_rx_tstamp(pf, true);
	}

	pf->flags &= ~OTX2_FLAG_INTF_DOWN;
	/* 'intf_down' may be checked on any cpu */
	smp_wmb();
@@ -1738,6 +1753,143 @@ static void otx2_reset_task(struct work_struct *work)
	rtnl_unlock();
}

static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)
{
	struct msg_req *req;
	int err;

	if (pfvf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED && enable)
		return 0;

	mutex_lock(&pfvf->mbox.lock);
	if (enable)
		req = otx2_mbox_alloc_msg_cgx_ptp_rx_enable(&pfvf->mbox);
	else
		req = otx2_mbox_alloc_msg_cgx_ptp_rx_disable(&pfvf->mbox);
	if (!req) {
		mutex_unlock(&pfvf->mbox.lock);
		return -ENOMEM;
	}

	err = otx2_sync_mbox_msg(&pfvf->mbox);
	if (err) {
		mutex_unlock(&pfvf->mbox.lock);
		return err;
	}

	mutex_unlock(&pfvf->mbox.lock);
	if (enable)
		pfvf->flags |= OTX2_FLAG_RX_TSTAMP_ENABLED;
	else
		pfvf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
	return 0;
}

static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)
{
	struct msg_req *req;
	int err;

	if (pfvf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED && enable)
		return 0;

	mutex_lock(&pfvf->mbox.lock);
	if (enable)
		req = otx2_mbox_alloc_msg_nix_lf_ptp_tx_enable(&pfvf->mbox);
	else
		req = otx2_mbox_alloc_msg_nix_lf_ptp_tx_disable(&pfvf->mbox);
	if (!req) {
		mutex_unlock(&pfvf->mbox.lock);
		return -ENOMEM;
	}

	err = otx2_sync_mbox_msg(&pfvf->mbox);
	if (err) {
		mutex_unlock(&pfvf->mbox.lock);
		return err;
	}

	mutex_unlock(&pfvf->mbox.lock);
	if (enable)
		pfvf->flags |= OTX2_FLAG_TX_TSTAMP_ENABLED;
	else
		pfvf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
	return 0;
}

static int otx2_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr)
{
	struct otx2_nic *pfvf = netdev_priv(netdev);
	struct hwtstamp_config config;

	if (!pfvf->ptp)
		return -ENODEV;

	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
		return -EFAULT;

	/* reserved for future extensions */
	if (config.flags)
		return -EINVAL;

	switch (config.tx_type) {
	case HWTSTAMP_TX_OFF:
		otx2_config_hw_tx_tstamp(pfvf, false);
		break;
	case HWTSTAMP_TX_ON:
		otx2_config_hw_tx_tstamp(pfvf, true);
		break;
	default:
		return -ERANGE;
	}

	switch (config.rx_filter) {
	case HWTSTAMP_FILTER_NONE:
		otx2_config_hw_rx_tstamp(pfvf, false);
		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:
		otx2_config_hw_rx_tstamp(pfvf, true);
		config.rx_filter = HWTSTAMP_FILTER_ALL;
		break;
	default:
		return -ERANGE;
	}

	memcpy(&pfvf->tstamp, &config, sizeof(config));

	return copy_to_user(ifr->ifr_data, &config,
			    sizeof(config)) ? -EFAULT : 0;
}

static int otx2_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
{
	struct otx2_nic *pfvf = netdev_priv(netdev);
	struct hwtstamp_config *cfg = &pfvf->tstamp;

	switch (cmd) {
	case SIOCSHWTSTAMP:
		return otx2_config_hwtstamp(netdev, req);
	case SIOCGHWTSTAMP:
		return copy_to_user(req->ifr_data, cfg,
				    sizeof(*cfg)) ? -EFAULT : 0;
	default:
		return -EOPNOTSUPP;
	}
}

static const struct net_device_ops otx2_netdev_ops = {
	.ndo_open		= otx2_open,
	.ndo_stop		= otx2_stop,
@@ -1748,6 +1900,7 @@ static const struct net_device_ops otx2_netdev_ops = {
	.ndo_set_features	= otx2_set_features,
	.ndo_tx_timeout		= otx2_tx_timeout,
	.ndo_get_stats64	= otx2_get_stats64,
	.ndo_do_ioctl		= otx2_ioctl,
};

static int otx2_wq_init(struct otx2_nic *pf)
@@ -1920,6 +2073,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	/* Assign default mac address */
	otx2_get_mac_from_af(netdev);

	/* Don't check for error.  Proceed without ptp */
	otx2_ptp_init(pf);

	/* NPA's pool is a stack to which SW frees buffer pointers via Aura.
	 * HW allocates buffer pointer from stack and uses it for DMA'ing
	 * ingress packet. In some scenarios HW can free back allocated buffer
@@ -1952,7 +2108,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	err = register_netdev(netdev);
	if (err) {
		dev_err(dev, "Failed to register netdevice\n");
		goto err_detach_rsrc;
		goto err_ptp_destroy;
	}

	err = otx2_wq_init(pf);
@@ -1972,6 +2128,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)

err_unreg_netdev:
	unregister_netdev(netdev);
err_ptp_destroy:
	otx2_ptp_destroy(pf);
err_detach_rsrc:
	otx2_detach_resources(&pf->mbox);
err_disable_mbox_intr:
@@ -2113,6 +2271,11 @@ static void otx2_remove(struct pci_dev *pdev)

	pf = netdev_priv(netdev);

	if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED)
		otx2_config_hw_tx_tstamp(pf, false);
	if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED)
		otx2_config_hw_rx_tstamp(pf, false);

	cancel_work_sync(&pf->reset_task);
	/* Disable link notifications */
	otx2_cgx_config_linkevents(pf, false);
@@ -2122,6 +2285,7 @@ static void otx2_remove(struct pci_dev *pdev)
	if (pf->otx2_wq)
		destroy_workqueue(pf->otx2_wq);

	otx2_ptp_destroy(pf);
	otx2_detach_resources(&pf->mbox);
	otx2_disable_mbox_intr(pf);
	otx2_pfaf_mbox_destroy(pf);
Loading