Commit 3e77e59b authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: dsa: sja1105: add support for the SJA1110 switch family



The SJA1110 is basically an SJA1105 with more ports, some integrated
PHYs (100base-T1 and 100base-TX) and an embedded microcontroller which
can be disabled, and the switch core can be controlled by a host running
Linux, over SPI.

This patch contains:
- the static and dynamic config packing functions, for the tables that
  are common with SJA1105
- one more static config tables which is "unique" to the SJA1110
  (actually it is a rehash of stuff that was placed somewhere else in
  SJA1105): the PCP Remapping Table
- a reset and clock configuration procedure for the SJA1110 switch.
  This resets just the switch subsystem, and gates off the clock which
  powers on the embedded microcontroller.
- an RGMII delay configuration procedure for SJA1110, which is very
  similar to SJA1105, but different enough for us to be unable to reuse
  it (this is a pattern that repeats itself)
- some adaptations to dynamic config table entries which are no longer
  programmed in the same way. For example, to delete a VLAN, you used to
  write an entry through the dynamic reconfiguration interface with the
  desired VLAN ID, and with the VALIDENT bit set to false. Now, the VLAN
  table entries contain a TYPE_ENTRY field, which must be set to zero
  (in a backwards-incompatible way) in order for the entry to be deleted,
  or to some other entry for the VLAN to match "inner tagged" or "outer
  tagged" packets.
- a similar thing for the static config: the xMII Mode Parameters Table
  encoding for SGMII and MII (the latter just when attached to a
  100base-TX PHY) just isn't what it used to be in SJA1105. They are
  identical, except there is an extra "special" bit which needs to be
  set. Set it.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 070f5b70
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -13,15 +13,12 @@
#include <linux/mutex.h>
#include "sja1105_static_config.h"

#define SJA1105_NUM_PORTS		5
#define SJA1105_MAX_NUM_PORTS		SJA1105_NUM_PORTS
#define SJA1105_NUM_TC			8
#define SJA1105ET_FDB_BIN_SIZE		4
/* The hardware value is in multiples of 10 ms.
 * The passed parameter is in multiples of 1 ms.
 */
#define SJA1105_AGEING_TIME_MS(ms)	((ms) / 10)
#define SJA1105_NUM_L2_POLICERS		45
#define SJA1105_NUM_L2_POLICERS		SJA1110_MAX_L2_POLICING_COUNT

typedef enum {
	SPI_READ = 0,
@@ -99,6 +96,7 @@ struct sja1105_info {
	int ptpegr_ts_bytes;
	int num_cbs_shapers;
	int max_frame_mem;
	int num_ports;
	const struct sja1105_dynamic_table_ops *dyn_ops;
	const struct sja1105_table_ops *static_ops;
	const struct sja1105_regs *regs;
@@ -310,6 +308,10 @@ extern const struct sja1105_info sja1105p_info;
extern const struct sja1105_info sja1105q_info;
extern const struct sja1105_info sja1105r_info;
extern const struct sja1105_info sja1105s_info;
extern const struct sja1105_info sja1110a_info;
extern const struct sja1105_info sja1110b_info;
extern const struct sja1105_info sja1110c_info;
extern const struct sja1105_info sja1110d_info;

/* From sja1105_clocking.c */

@@ -326,8 +328,10 @@ typedef enum {
} sja1105_phy_interface_t;

int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1110_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
int sja1110_clocking_setup(struct sja1105_private *priv);

/* From sja1105_ethtool.c */
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
@@ -348,6 +352,18 @@ enum sja1105_iotag {
	SJA1105_S_TAG = 1, /* Outer VLAN header */
};

enum sja1110_vlan_type {
	SJA1110_VLAN_INVALID = 0,
	SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
	SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
	SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
};

enum sja1110_shaper_type {
	SJA1110_LEAKY_BUCKET_SHAPER = 0,
	SJA1110_CBS_SHAPER = 1,
};

u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid);
int sja1105et_fdb_add(struct dsa_switch *ds, int port,
		      const unsigned char *addr, u16 vid);
+91 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include "sja1105.h"

#define SJA1105_SIZE_CGU_CMD	4
#define SJA1110_BASE_TIMER_CLK	SJA1110_CGU_ADDR(0x74)

/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
struct sja1105_cfg_pad_mii {
@@ -61,6 +62,12 @@ struct sja1105_cgu_pll_ctrl {
	u64 pd;
};

struct sja1110_cgu_outclk {
	u64 clksrc;
	u64 autoblock;
	u64 pd;
};

enum {
	CLKSRC_MII0_TX_CLK	= 0x00,
	CLKSRC_MII0_RX_CLK	= 0x01,
@@ -461,6 +468,35 @@ sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

static void
sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
			       enum packing_op op)
{
	const int size = SJA1105_SIZE_CGU_CMD;
	u64 range = 4;

	/* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
	 * 0 = 2.5MHz
	 * 1 = 25MHz
	 * 2 = 50MHz
	 * 3 = 125MHz
	 * 4 = Automatically determined by port speed.
	 * There's no point in defining a structure different than the one for
	 * SJA1105, so just hardcode the frequency range to automatic, just as
	 * before.
	 */
	sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
	sja1105_packing(buf, &cmd->rxc_delay,      25, 21, size, op);
	sja1105_packing(buf, &range,               20, 18, size, op);
	sja1105_packing(buf, &cmd->rxc_bypass,     17, 17, size, op);
	sja1105_packing(buf, &cmd->rxc_pd,         16, 16, size, op);
	sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
	sja1105_packing(buf, &cmd->txc_delay,       9,  5, size, op);
	sja1105_packing(buf, &range,                4,  2, size, op);
	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

/* Valid range in degrees is an integer between 73.8 and 101.7 */
static u64 sja1105_rgmii_delay(u64 phase)
{
@@ -519,6 +555,35 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
				packed_buf, SJA1105_SIZE_CGU_CMD);
}

int sja1110_setup_rgmii_delay(const void *ctx, int port)
{
	const struct sja1105_private *priv = ctx;
	const struct sja1105_regs *regs = priv->info->regs;
	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};

	pad_mii_id.rxc_pd = 1;
	pad_mii_id.txc_pd = 1;

	if (priv->rgmii_rx_delay[port]) {
		pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
		/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
		pad_mii_id.rxc_bypass = 1;
		pad_mii_id.rxc_pd = 0;
	}

	if (priv->rgmii_tx_delay[port]) {
		pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
		pad_mii_id.txc_bypass = 1;
		pad_mii_id.txc_pd = 0;
	}

	sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);

	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
				packed_buf, SJA1105_SIZE_CGU_CMD);
}

static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
					sja1105_mii_role_t role)
{
@@ -755,3 +820,29 @@ int sja1105_clocking_setup(struct sja1105_private *priv)
	}
	return 0;
}

static void
sja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
			   enum packing_op op)
{
	const int size = 4;

	sja1105_packing(buf, &outclk->clksrc,    27, 24, size, op);
	sja1105_packing(buf, &outclk->autoblock, 11, 11, size, op);
	sja1105_packing(buf, &outclk->pd,         0,  0, size, op);
}

/* Power down the BASE_TIMER_CLK in order to disable the watchdog */
int sja1110_clocking_setup(struct sja1105_private *priv)
{
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
	struct sja1110_cgu_outclk outclk_7_c = {
		.clksrc = 0x5,
		.pd = true,
	};

	sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);

	return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
				packed_buf, SJA1105_SIZE_CGU_CMD);
}
+320 −1
Original line number Diff line number Diff line
@@ -106,6 +106,9 @@
#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)

#define SJA1110_SIZE_VL_POLICING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_POLICING_ENTRY)

#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
	SJA1105_SIZE_DYN_CMD

@@ -115,9 +118,15 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)

#define SJA1110_SIZE_L2_LOOKUP_DYN_CMD				\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_ENTRY)

#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)

#define SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_VLAN_LOOKUP_ENTRY)

#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)

@@ -133,12 +142,18 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)

#define SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY)

#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD			\
	SJA1105_SIZE_DYN_CMD

#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)

#define SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_GENERAL_PARAMS_ENTRY)

#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)

@@ -151,8 +166,17 @@
#define SJA1105PQRS_SIZE_CBS_DYN_CMD				\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)

#define SJA1110_SIZE_XMII_PARAMS_DYN_CMD			\
	SJA1110_SIZE_XMII_PARAMS_ENTRY

#define SJA1110_SIZE_L2_POLICING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_POLICING_ENTRY)

#define SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD		\
	SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY

#define SJA1105_MAX_DYN_CMD_SIZE				\
	SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD
	SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD

struct sja1105_dyn_cmd {
	bool search;
@@ -197,6 +221,19 @@ sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    9,  0, size, op);
}

static void
sja1110_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			      enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,   11,  0, size, op);
}

static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
						enum packing_op op)
{
@@ -208,6 +245,18 @@ static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
	return size;
}

static void
sja1110_vl_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->index,   11,  0, size, op);
}

static void
sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
@@ -326,6 +375,18 @@ sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
}

static size_t sja1110_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
						  enum packing_op op)
{
	struct sja1105_l2_lookup_entry *entry = entry_ptr;
	u8 *cmd = buf + SJA1110_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);

	return sja1110_l2_lookup_entry_packing(buf, entry_ptr, op);
}

static void
sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
@@ -437,6 +498,39 @@ sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
}

/* In SJA1110 there is no gap between the command and the data, yay... */
static void
sja1110_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;
	u64 type_entry = 0;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	/* Hack: treat 'vlanid' field of struct sja1105_vlan_lookup_entry as
	 * cmd->index.
	 */
	sja1105_packing(buf, &cmd->index, 38, 27,
			SJA1110_SIZE_VLAN_LOOKUP_ENTRY, op);

	/* But the VALIDENT bit has disappeared, now we are supposed to
	 * invalidate an entry through the TYPE_ENTRY field of the entry..
	 * This is a hack to transform the non-zero quality of the TYPE_ENTRY
	 * field into a VALIDENT bit.
	 */
	if (op == PACK && !cmd->valident) {
		sja1105_packing(buf, &type_entry, 40, 39,
				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, PACK);
	} else if (op == UNPACK) {
		sja1105_packing(buf, &type_entry, 40, 39,
				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, UNPACK);
		cmd->valident = !!type_entry;
	}
}

static void
sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
@@ -450,6 +544,19 @@ sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    4,  0, size, op);
}

static void
sja1110_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    4,  0, size, op);
}

static void
sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				 enum packing_op op)
@@ -504,6 +611,19 @@ sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    2,  0, size, op);
}

static void
sja1110_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			       enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    3,  0, size, op);
}

static void
sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				       enum packing_op op)
@@ -536,6 +656,18 @@ sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
}

static void
sja1110_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				     enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
}

static void
sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				     enum packing_op op)
@@ -570,6 +702,18 @@ sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
}

static void
sja1110_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				   enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
}

static void
sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				   enum packing_op op)
@@ -596,6 +740,20 @@ sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,     5,  0, size, op);
}

static void
sja1110_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			      enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
	sja1105_packing(p, &cmd->valident, 28, 28, size, op);
	sja1105_packing(p, &cmd->index,     4,  0, size, op);
}

static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				      enum packing_op op)
{
@@ -635,6 +793,18 @@ static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    3,  0, size, op);
}

static void sja1110_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				    enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    7,  0, size, op);
}

static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
					    enum packing_op op)
{
@@ -650,6 +820,39 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
	return size;
}

static size_t sja1110_cbs_entry_packing(void *buf, void *entry_ptr,
					enum packing_op op)
{
	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
	struct sja1105_cbs_entry *entry = entry_ptr;
	u64 entry_type = SJA1110_CBS_SHAPER;

	sja1105_packing(buf, &entry_type,       159, 159, size, op);
	sja1105_packing(buf, &entry->credit_lo, 151, 120, size, op);
	sja1105_packing(buf, &entry->credit_hi, 119,  88, size, op);
	sja1105_packing(buf, &entry->send_slope, 87,  56, size, op);
	sja1105_packing(buf, &entry->idle_slope, 55,  24, size, op);
	return size;
}

static void sja1110_dummy_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				      enum packing_op op)
{
}

static void
sja1110_l2_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_L2_POLICING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    6,  0, size, op);
}

#define OP_READ		BIT(0)
#define OP_WRITE	BIT(1)
#define OP_DEL		BIT(2)
@@ -832,6 +1035,122 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	},
};

/* SJA1110: Third generation */
const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1110_vl_lookup_entry_packing,
		.cmd_packing = sja1110_vl_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x124),
	},
	[BLK_IDX_VL_POLICING] = {
		.entry_packing = sja1110_vl_policing_entry_packing,
		.cmd_packing = sja1110_vl_policing_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
		.packed_size = SJA1110_SIZE_VL_POLICING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x310),
	},
	[BLK_IDX_L2_LOOKUP] = {
		.entry_packing = sja1110_dyn_l2_lookup_entry_packing,
		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
		.packed_size = SJA1110_SIZE_L2_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x8c),
	},
	[BLK_IDX_VLAN_LOOKUP] = {
		.entry_packing = sja1110_vlan_lookup_entry_packing,
		.cmd_packing = sja1110_vlan_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL),
		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
		.packed_size = SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xb4),
	},
	[BLK_IDX_L2_FORWARDING] = {
		.entry_packing = sja1110_l2_forwarding_entry_packing,
		.cmd_packing = sja1110_l2_forwarding_cmd_packing,
		.max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xa8),
	},
	[BLK_IDX_MAC_CONFIG] = {
		.entry_packing = sja1110_mac_config_entry_packing,
		.cmd_packing = sja1110_mac_config_cmd_packing,
		.max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x134),
	},
	[BLK_IDX_L2_LOOKUP_PARAMS] = {
		.entry_packing = sja1110_l2_lookup_params_entry_packing,
		.cmd_packing = sja1110_l2_lookup_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x158),
	},
	[BLK_IDX_AVB_PARAMS] = {
		.entry_packing = sja1105pqrs_avb_params_entry_packing,
		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x2000C),
	},
	[BLK_IDX_GENERAL_PARAMS] = {
		.entry_packing = sja1110_general_params_entry_packing,
		.cmd_packing = sja1110_general_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xe8),
	},
	[BLK_IDX_RETAGGING] = {
		.entry_packing = sja1110_retagging_entry_packing,
		.cmd_packing = sja1110_retagging_cmd_packing,
		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_DEL),
		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xdc),
	},
	[BLK_IDX_CBS] = {
		.entry_packing = sja1110_cbs_entry_packing,
		.cmd_packing = sja1110_cbs_cmd_packing,
		.max_entry_count = SJA1110_MAX_CBS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xc4),
	},
	[BLK_IDX_XMII_PARAMS] = {
		.entry_packing = sja1110_xmii_params_entry_packing,
		.cmd_packing = sja1110_dummy_cmd_packing,
		.max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
		.access = (OP_READ | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_XMII_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x3c),
	},
	[BLK_IDX_L2_POLICING] = {
		.entry_packing = sja1110_l2_policing_entry_packing,
		.cmd_packing = sja1110_l2_policing_cmd_packing,
		.max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_POLICING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x2fc),
	},
	[BLK_IDX_L2_FORWARDING_PARAMS] = {
		.entry_packing = sja1110_l2_forwarding_params_entry_packing,
		.cmd_packing = sja1110_dummy_cmd_packing,
		.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
		.access = (OP_READ | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x20000),
	},
};

/* Provides read access to the settings through the dynamic interface
 * of the switch.
 * @blk_idx	is used as key to select from the sja1105_dynamic_table_ops.
+1 −0
Original line number Diff line number Diff line
@@ -36,5 +36,6 @@ struct sja1105_mgmt_entry {

extern const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN];
extern const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN];
extern const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN];

#endif
+54 −1
Original line number Diff line number Diff line
@@ -343,6 +343,7 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
{
	struct sja1105_table *table;
	struct sja1105_vlan_lookup_entry pvid = {
		.type_entry = SJA1110_VLAN_D_TAG,
		.ving_mirr = 0,
		.vegr_mirr = 0,
		.vmemb_port = 0,
@@ -455,6 +456,47 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv)

			l2fwd[ds->num_ports + i].vlan_pmap[j] = i;
		}

		l2fwd[ds->num_ports + i].type_egrpcp2outputq = true;
	}

	return 0;
}

static int sja1110_init_pcp_remapping(struct sja1105_private *priv)
{
	struct sja1110_pcp_remapping_entry *pcp_remap;
	struct dsa_switch *ds = priv->ds;
	struct sja1105_table *table;
	int port, tc;

	table = &priv->static_config.tables[BLK_IDX_PCP_REMAPPING];

	/* Nothing to do for SJA1105 */
	if (!table->ops->max_entry_count)
		return 0;

	if (table->entry_count) {
		kfree(table->entries);
		table->entry_count = 0;
	}

	table->entries = kcalloc(table->ops->max_entry_count,
				 table->ops->unpacked_entry_size, GFP_KERNEL);
	if (!table->entries)
		return -ENOMEM;

	table->entry_count = table->ops->max_entry_count;

	pcp_remap = table->entries;

	/* Repeat the configuration done for vlan_pmap */
	for (port = 0; port < ds->num_ports; port++) {
		if (dsa_is_unused_port(ds, port))
			continue;

		for (tc = 0; tc < SJA1105_NUM_TC; tc++)
			pcp_remap[port].egrpcp[tc] = tc;
	}

	return 0;
@@ -777,6 +819,9 @@ static int sja1105_static_config_load(struct sja1105_private *priv)
	if (rc < 0)
		return rc;
	rc = sja1105_init_avb_params(priv);
	if (rc < 0)
		return rc;
	rc = sja1110_init_pcp_remapping(priv);
	if (rc < 0)
		return rc;

@@ -2295,6 +2340,7 @@ sja1105_build_bridge_vlans(struct sja1105_private *priv,
		new_vlan[match].vlan_bc |= BIT(v->port);
		if (!v->untagged)
			new_vlan[match].tag_port |= BIT(v->port);
		new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
	}

	return 0;
@@ -2317,6 +2363,7 @@ sja1105_build_dsa_8021q_vlans(struct sja1105_private *priv,
		new_vlan[match].vlan_bc |= BIT(v->port);
		if (!v->untagged)
			new_vlan[match].tag_port |= BIT(v->port);
		new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
	}

	return 0;
@@ -2377,6 +2424,7 @@ static int sja1105_build_subvlans(struct sja1105_private *priv,
			new_vlan[match].tag_port |= BIT(v->port);
		/* But it's always tagged towards the CPU */
		new_vlan[match].tag_port |= BIT(upstream);
		new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;

		/* The Retagging Table generates packet *clones* with
		 * the new VLAN. This is a very odd hardware quirk
@@ -2544,6 +2592,7 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
		if (!tmp->untagged)
			new_vlan[match].tag_port |= BIT(tmp->port);
		new_vlan[match].tag_port |= BIT(upstream);
		new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
		/* Deny egress of @rx_vid towards our front-panel port.
		 * This will force the switch to drop it, and we'll see
		 * only the re-retagged packets (having the original,
@@ -3684,7 +3733,7 @@ static int sja1105_probe(struct spi_device *spi)
		return -ENOMEM;

	ds->dev = dev;
	ds->num_ports = SJA1105_MAX_NUM_PORTS;
	ds->num_ports = priv->info->num_ports;
	ds->ops = &sja1105_switch_ops;
	ds->priv = priv;
	priv->ds = ds;
@@ -3788,6 +3837,10 @@ static const struct of_device_id sja1105_dt_ids[] = {
	{ .compatible = "nxp,sja1105q", .data = &sja1105q_info },
	{ .compatible = "nxp,sja1105r", .data = &sja1105r_info },
	{ .compatible = "nxp,sja1105s", .data = &sja1105s_info },
	{ .compatible = "nxp,sja1110a", .data = &sja1110a_info },
	{ .compatible = "nxp,sja1110b", .data = &sja1110b_info },
	{ .compatible = "nxp,sja1110c", .data = &sja1110c_info },
	{ .compatible = "nxp,sja1110d", .data = &sja1110d_info },
	{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sja1105_dt_ids);
Loading