Commit 44a8535f authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'octeontx2-cn10k-ptp'



From: Naveen Mamindlapalli <naveenm@marvell.com>
To: <kuba@kernel.org>, <davem@davemloft.net>, <edumazet@google.com>,
	<pabeni@redhat.com>, <richardcochran@gmail.com>,
	<netdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<sgoutham@marvell.com>, <hkelam@marvell.com>
Cc: Naveen Mamindlapalli <naveenm@marvell.com>
Subject: [net-next PATCH 0/4] Add PTP support for CN10K silicon
Date: Sat, 10 Sep 2022 13:24:12 +0530	[thread overview]
Message-ID: <20220910075416.22887-1-naveenm@marvell.com> (raw)

This patchset adds PTP support for CN10K silicon, specifically
to workaround few hardware issues and to add 1-step mode.

Patchset overview:

Patch #1 returns correct ptp timestamp in nanoseconds captured
         when external timestamp event occurs.

Patch #2 adds 1-step mode support.

Patch #3 implements software workaround to generate PPS output properly.

Patch #4 provides a software workaround for the rollover register default
         value, which causes ptp to return the wrong timestamp.
====================

Acked-by: default avatarRichard Cochran <richardcochran@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5947b7f7 85a5f963
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1471,6 +1471,7 @@ enum ptp_op {
	PTP_OP_GET_CLOCK = 1,
	PTP_OP_GET_TSTMP = 2,
	PTP_OP_SET_THRESH = 3,
	PTP_OP_EXTTS_ON = 4,
};

struct ptp_req {
@@ -1478,6 +1479,7 @@ struct ptp_req {
	u8 op;
	s64 scaled_ppm;
	u64 thresh;
	int extts_on;
};

struct ptp_rsp {
+104 −2
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>

#include "ptp.h"
#include "mbox.h"
@@ -50,12 +52,23 @@
#define PTP_CLOCK_COMP				0xF18ULL
#define PTP_TIMESTAMP				0xF20ULL
#define PTP_CLOCK_SEC				0xFD0ULL
#define PTP_SEC_ROLLOVER			0xFD8ULL

#define CYCLE_MULT				1000

static struct ptp *first_ptp_block;
static const struct pci_device_id ptp_id_table[];

static bool is_ptp_dev_cnf10kb(struct ptp *ptp)
{
	return (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_B_PTP) ? true : false;
}

static bool is_ptp_dev_cn10k(struct ptp *ptp)
{
	return (ptp->pdev->device == PCI_DEVID_CN10K_PTP) ? true : false;
}

static bool cn10k_ptp_errata(struct ptp *ptp)
{
	if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
@@ -72,6 +85,43 @@ static bool is_ptp_tsfmt_sec_nsec(struct ptp *ptp)
	return false;
}

static enum hrtimer_restart ptp_reset_thresh(struct hrtimer *hrtimer)
{
	struct ptp *ptp = container_of(hrtimer, struct ptp, hrtimer);
	ktime_t curr_ts = ktime_get();
	ktime_t delta_ns, period_ns;
	u64 ptp_clock_hi;

	/* calculate the elapsed time since last restart */
	delta_ns = ktime_to_ns(ktime_sub(curr_ts, ptp->last_ts));

	/* if the ptp clock value has crossed 0.5 seconds,
	 * its too late to update pps threshold value, so
	 * update threshold after 1 second.
	 */
	ptp_clock_hi = readq(ptp->reg_base + PTP_CLOCK_HI);
	if (ptp_clock_hi > 500000000) {
		period_ns = ktime_set(0, (NSEC_PER_SEC + 100 - ptp_clock_hi));
	} else {
		writeq(500000000, ptp->reg_base + PTP_PPS_THRESH_HI);
		period_ns = ktime_set(0, (NSEC_PER_SEC + 100 - delta_ns));
	}

	hrtimer_forward_now(hrtimer, period_ns);
	ptp->last_ts = curr_ts;

	return HRTIMER_RESTART;
}

static void ptp_hrtimer_start(struct ptp *ptp, ktime_t start_ns)
{
	ktime_t period_ns;

	period_ns = ktime_set(0, (NSEC_PER_SEC + 100 - start_ns));
	hrtimer_start(&ptp->hrtimer, period_ns, HRTIMER_MODE_REL);
	ptp->last_ts = ktime_get();
}

static u64 read_ptp_tstmp_sec_nsec(struct ptp *ptp)
{
	u64 sec, sec1, nsec;
@@ -246,6 +296,10 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
	/* sclk is in MHz */
	ptp->clock_rate = sclk * 1000000;

	/* Program the seconds rollover value to 1 second */
	if (is_ptp_dev_cnf10kb(ptp))
		writeq(0x3b9aca00, ptp->reg_base + PTP_SEC_ROLLOVER);

	/* Enable PTP clock */
	clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);

@@ -270,6 +324,18 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
	/* Set 50% duty cycle for 1Hz output */
	writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR);
	writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_LO_INCR);
	if (cn10k_ptp_errata(ptp)) {
		/* The ptp_clock_hi rollsover to zero once clock cycle before it
		 * reaches one second boundary. so, program the pps_lo_incr in
		 * such a way that the pps threshold value comparison at one
		 * second boundary will succeed and pps edge changes. After each
		 * one second boundary, the hrtimer handler will be invoked and
		 * reprograms the pps threshold value.
		 */
		ptp->clock_period = NSEC_PER_SEC / ptp->clock_rate;
		writeq((0x1dcd6500ULL - ptp->clock_period) << 32,
		       ptp->reg_base + PTP_PPS_LO_INCR);
	}

	if (cn10k_ptp_errata(ptp))
		clock_comp = ptp_calc_adjusted_comp(ptp->clock_rate);
@@ -282,18 +348,43 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)

static int ptp_get_tstmp(struct ptp *ptp, u64 *clk)
{
	u64 timestamp;

	if (is_ptp_dev_cn10k(ptp)) {
		timestamp = readq(ptp->reg_base + PTP_TIMESTAMP);
		*clk = (timestamp >> 32) * NSEC_PER_SEC + (timestamp & 0xFFFFFFFF);
	} else {
		*clk = readq(ptp->reg_base + PTP_TIMESTAMP);
	}

	return 0;
}

static int ptp_set_thresh(struct ptp *ptp, u64 thresh)
{
	if (!cn10k_ptp_errata(ptp))
		writeq(thresh, ptp->reg_base + PTP_PPS_THRESH_HI);

	return 0;
}

static int ptp_extts_on(struct ptp *ptp, int on)
{
	u64 ptp_clock_hi;

	if (cn10k_ptp_errata(ptp)) {
		if (on) {
			ptp_clock_hi = readq(ptp->reg_base + PTP_CLOCK_HI);
			ptp_hrtimer_start(ptp, (ktime_t)ptp_clock_hi);
		} else {
			if (hrtimer_active(&ptp->hrtimer))
				hrtimer_cancel(&ptp->hrtimer);
		}
	}

	return 0;
}

static int ptp_probe(struct pci_dev *pdev,
		     const struct pci_device_id *ent)
{
@@ -329,6 +420,11 @@ static int ptp_probe(struct pci_dev *pdev,
	else
		ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;

	if (cn10k_ptp_errata(ptp)) {
		hrtimer_init(&ptp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		ptp->hrtimer.function = ptp_reset_thresh;
	}

	return 0;

error_free:
@@ -353,6 +449,9 @@ static void ptp_remove(struct pci_dev *pdev)
	struct ptp *ptp = pci_get_drvdata(pdev);
	u64 clock_cfg;

	if (cn10k_ptp_errata(ptp) && hrtimer_active(&ptp->hrtimer))
		hrtimer_cancel(&ptp->hrtimer);

	if (IS_ERR_OR_NULL(ptp))
		return;

@@ -420,6 +519,9 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
	case PTP_OP_SET_THRESH:
		err = ptp_set_thresh(rvu->ptp, req->thresh);
		break;
	case PTP_OP_EXTTS_ON:
		err = ptp_extts_on(rvu->ptp, req->extts_on);
		break;
	default:
		err = -EINVAL;
		break;
+3 −0
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ struct ptp {
	void __iomem *reg_base;
	u64 (*read_ptp_tstmp)(struct ptp *ptp);
	spinlock_t ptp_lock; /* lock */
	struct hrtimer hrtimer;
	ktime_t last_ts;
	u32 clock_rate;
	u32 clock_period;
};

struct ptp *ptp_get(void);
+17 −2
Original line number Diff line number Diff line
@@ -415,11 +415,26 @@ void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable)
		return;

	cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG);
	if (enable)
	if (enable) {
		cfg |= RPMX_RX_TS_PREPEND;
	else
		cfg |= RPMX_TX_PTP_1S_SUPPORT;
	} else {
		cfg &= ~RPMX_RX_TS_PREPEND;
		cfg &= ~RPMX_TX_PTP_1S_SUPPORT;
	}

	rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg);

	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_XIF_MODE);

	if (enable) {
		cfg |= RPMX_ONESTEP_ENABLE;
		cfg &= ~RPMX_TS_BINARY_MODE;
	} else {
		cfg &= ~RPMX_ONESTEP_ENABLE;
	}

	rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_XIF_MODE, cfg);
}

int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 pfc_en)
+5 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
/* Registers */
#define RPMX_CMRX_CFG			0x00
#define RPMX_RX_TS_PREPEND              BIT_ULL(22)
#define RPMX_TX_PTP_1S_SUPPORT          BIT_ULL(17)
#define RPMX_CMRX_SW_INT                0x180
#define RPMX_CMRX_SW_INT_W1S            0x188
#define RPMX_CMRX_SW_INT_ENA_W1S        0x198
@@ -72,6 +73,10 @@
#define RPMX_MTI_MAC100X_CL89_PAUSE_QUANTA		0x8108
#define RPM_DEFAULT_PAUSE_TIME                          0x7FF

#define RPMX_MTI_MAC100X_XIF_MODE		        0x8100
#define RPMX_ONESTEP_ENABLE				BIT_ULL(5)
#define RPMX_TS_BINARY_MODE				BIT_ULL(11)

/* Function Declarations */
int rpm_get_nr_lmacs(void *rpmd);
u8 rpm_get_lmac_type(void *rpmd, int lmac_id);
Loading