Commit 86db36a3 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: dsa: sja1105: Implement state machine for TAS with PTP clock source



Tested using the following bash script and the tc from iproute2-next:

	#!/bin/bash

	set -e -u -o pipefail

	NSEC_PER_SEC="1000000000"

	gatemask() {
		local tc_list="$1"
		local mask=0

		for tc in ${tc_list}; do
			mask=$((${mask} | (1 << ${tc})))
		done

		printf "%02x" ${mask}
	}

	if ! systemctl is-active --quiet ptp4l; then
		echo "Please start the ptp4l service"
		exit
	fi

	now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }')
	# Phase-align the base time to the start of the next second.
	sec=$(echo "${now}" | gawk -F. '{ print $1; }')
	base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))"

	tc qdisc add dev swp5 parent root handle 100 taprio \
		num_tc 8 \
		map 0 1 2 3 5 6 7 \
		queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
		base-time ${base_time} \
		sched-entry S $(gatemask 7) 100000 \
		sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \
		clockid CLOCK_TAI flags 2

The "state machine" is a workqueue invoked after each manipulation
command on the PTP clock (reset, adjust time, set time, adjust
frequency) which checks over the state of the time-aware scheduler.
So it is not monitored periodically, only in reaction to a PTP command
typically triggered from a userspace daemon (linuxptp). Otherwise there
is no reason for things to go wrong.

Now that the timecounter/cyclecounter has been replaced with hardware
operations on the PTP clock, the TAS Kconfig now depends upon PTP and
the standalone clocksource operating mode has been removed.

Signed-off-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 41603d78
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ config NET_DSA_SJA1105_TAS
	bool "Support for the Time-Aware Scheduler on NXP SJA1105"
	depends on NET_DSA_SJA1105 && NET_SCH_TAPRIO
	depends on NET_SCH_TAPRIO=y || NET_DSA_SJA1105=m
	depends on NET_DSA_SJA1105_PTP
	help
	  This enables support for the TTEthernet-based egress scheduling
	  engine in the SJA1105 DSA driver, which is controlled using a
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ struct sja1105_regs {
	u64 ptp_control;
	u64 ptpclkval;
	u64 ptpclkrate;
	u64 ptpclkcorp;
	u64 ptpschtm;
	u64 ptpegr_ts[SJA1105_NUM_PORTS];
	u64 pad_mii_tx[SJA1105_NUM_PORTS];
	u64 pad_mii_id[SJA1105_NUM_PORTS];
+23 −7
Original line number Diff line number Diff line
@@ -201,6 +201,8 @@ void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
	u64 valid = 1;

	sja1105_packing(buf, &valid,           31, 31, size, op);
	sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
	sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
	sja1105_packing(buf, &cmd->resptp,      2,  2, size, op);
	sja1105_packing(buf, &cmd->corrclk4ts,  1,  1, size, op);
	sja1105_packing(buf, &cmd->ptpclkadd,   0,  0, size, op);
@@ -214,15 +216,17 @@ void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
	u64 valid = 1;

	sja1105_packing(buf, &valid,           31, 31, size, op);
	sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
	sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
	sja1105_packing(buf, &cmd->resptp,      3,  3, size, op);
	sja1105_packing(buf, &cmd->corrclk4ts,  2,  2, size, op);
	sja1105_packing(buf, &cmd->ptpclkadd,   0,  0, size, op);
}

static int sja1105_ptp_commit(struct sja1105_private *priv,
			      struct sja1105_ptp_cmd *cmd,
int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd,
		       sja1105_spi_rw_mode_t rw)
{
	const struct sja1105_private *priv = ds->priv;
	const struct sja1105_regs *regs = priv->info->regs;
	u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
	int rc;
@@ -448,7 +452,9 @@ static int sja1105_ptp_reset(struct dsa_switch *ds)
	cmd.resptp = 1;

	dev_dbg(ds->dev, "Resetting PTP clock\n");
	rc = sja1105_ptp_commit(priv, &cmd, SPI_WRITE);
	rc = sja1105_ptp_commit(ds, &cmd, SPI_WRITE);

	sja1105_tas_clockstep(priv->ds);

	mutex_unlock(&ptp_data->lock);

@@ -504,7 +510,7 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv,

	ptp_data->cmd.ptpclkadd = mode;

	return sja1105_ptp_commit(priv, &ptp_data->cmd, SPI_WRITE);
	return sja1105_ptp_commit(priv->ds, &ptp_data->cmd, SPI_WRITE);
}

/* Write to PTPCLKVAL while PTPCLKADD is 0 */
@@ -521,7 +527,11 @@ int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns,
		return rc;
	}

	return sja1105_ptpclkval_write(priv, ticks, ptp_sts);
	rc = sja1105_ptpclkval_write(priv, ticks, ptp_sts);

	sja1105_tas_clockstep(priv->ds);

	return rc;
}

static int sja1105_ptp_settime(struct ptp_clock_info *ptp,
@@ -563,6 +573,8 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
	rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32,
			      NULL);

	sja1105_tas_adjfreq(priv->ds);

	mutex_unlock(&ptp_data->lock);

	return rc;
@@ -581,7 +593,11 @@ int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta)
		return rc;
	}

	return sja1105_ptpclkval_write(priv, ticks, NULL);
	rc = sja1105_ptpclkval_write(priv, ticks, NULL);

	sja1105_tas_clockstep(priv->ds);

	return rc;
}

static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+12 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ static inline s64 sja1105_ticks_to_ns(s64 ticks)
}

struct sja1105_ptp_cmd {
	u64 ptpstrtsch;		/* start schedule */
	u64 ptpstopsch;		/* stop schedule */
	u64 resptp;		/* reset */
	u64 corrclk4ts;		/* use the corrected clock for timestamps */
	u64 ptpclkadd;		/* enum sja1105_ptp_clk_mode */
@@ -69,6 +71,9 @@ int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns,

int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta);

int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd,
		       sja1105_spi_rw_mode_t rw);

#else

struct sja1105_ptp_cmd;
@@ -110,6 +115,13 @@ static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta)
	return 0;
}

static inline int sja1105_ptp_commit(struct dsa_switch *ds,
				     struct sja1105_ptp_cmd *cmd,
				     sja1105_spi_rw_mode_t rw)
{
	return 0;
}

#define sja1105et_ptp_cmd_packing NULL

#define sja1105pqrs_ptp_cmd_packing NULL
+4 −0
Original line number Diff line number Diff line
@@ -539,9 +539,11 @@ static struct sja1105_regs sja1105et_regs = {
	.rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031},
	.rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
	.ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8},
	.ptpschtm = 0x12, /* Spans 0x12 to 0x13 */
	.ptp_control = 0x17,
	.ptpclkval = 0x18, /* Spans 0x18 to 0x19 */
	.ptpclkrate = 0x1A,
	.ptpclkcorp = 0x1D,
};

static struct sja1105_regs sja1105pqrs_regs = {
@@ -569,9 +571,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
	.rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
	.qlevel = {0x604, 0x614, 0x624, 0x634, 0x644},
	.ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0},
	.ptpschtm = 0x13, /* Spans 0x13 to 0x14 */
	.ptp_control = 0x18,
	.ptpclkval = 0x19,
	.ptpclkrate = 0x1B,
	.ptpclkcorp = 0x1E,
};

struct sja1105_info sja1105e_info = {
Loading