Commit f5d8ec83 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-dsa-b53-add-support-for-bcm5389-97-98-and-bcm63xx-arl-formats'

Jonas Gorski says:

====================
net: dsa: b53: add support for BCM5389/97/98 and BCM63XX ARL formats

Currently b53 assumes that all switches apart from BCM5325/5365 use the
same ARL formats, but there are actually multiple formats in use.

Older switches use a format apparently introduced with BCM5387/BCM5389,
while newer chips use a format apparently introduced with BCM5395.

Note that these numbers are not linear, BCM5397/BCM5398 use the older
format.

In addition to that the switches integrated into BCM63XX SoCs use their
own format. While accessing these normal read/write ARL entries are the
same format as BCM5389 one, the search format is different.

So in order to support all these different format, split all code
accessing these entries into chip-family specific functions, and collect
them in appropriate arl ops structs to keep the code cleaner.

Sent as net-next since the ARL accesses have never worked before, and
the extensive refactoring might be too much to warrant a fix.
====================

Link: https://patch.msgid.link/20251107080749.26936-1-jonas.gorski@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 7fc2bf8d 2b3013ac
Loading
Loading
Loading
Loading
+219 −97
Original line number Diff line number Diff line
@@ -1850,48 +1850,77 @@ static int b53_arl_rw_op(struct b53_device *dev, unsigned int op)
	return b53_arl_op_wait(dev);
}

static int b53_arl_read(struct b53_device *dev, u64 mac,
			u16 vid, struct b53_arl_entry *ent, u8 *idx)
static void b53_arl_read_entry_25(struct b53_device *dev,
				  struct b53_arl_entry *ent, u8 idx)
{
	DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
	unsigned int i;
	int ret;
	u64 mac_vid;

	ret = b53_arl_op_wait(dev);
	if (ret)
		return ret;
	b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx),
		   &mac_vid);
	b53_arl_to_entry_25(ent, mac_vid);
}

	bitmap_zero(free_bins, dev->num_arl_bins);
static void b53_arl_write_entry_25(struct b53_device *dev,
				   const struct b53_arl_entry *ent, u8 idx)
{
	u64 mac_vid;

	/* Read the bins */
	for (i = 0; i < dev->num_arl_bins; i++) {
	b53_arl_from_entry_25(&mac_vid, ent);
	b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx),
		    mac_vid);
}

static void b53_arl_read_entry_89(struct b53_device *dev,
				  struct b53_arl_entry *ent, u8 idx)
{
	u64 mac_vid;
		u32 fwd_entry;
	u16 fwd_entry;

		b53_read64(dev, B53_ARLIO_PAGE,
			   B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
		b53_read32(dev, B53_ARLIO_PAGE,
			   B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
		b53_arl_to_entry(ent, mac_vid, fwd_entry);
	b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx),
		   &mac_vid);
	b53_read16(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx), &fwd_entry);
	b53_arl_to_entry_89(ent, mac_vid, fwd_entry);
}

		if (!(fwd_entry & ARLTBL_VALID)) {
			set_bit(i, free_bins);
			continue;
static void b53_arl_write_entry_89(struct b53_device *dev,
				   const struct b53_arl_entry *ent, u8 idx)
{
	u32 fwd_entry;
	u64 mac_vid;

	b53_arl_from_entry_89(&mac_vid, &fwd_entry, ent);
	b53_write64(dev, B53_ARLIO_PAGE,
		    B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);
	b53_write16(dev, B53_ARLIO_PAGE,
		    B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
}
		if ((mac_vid & ARLTBL_MAC_MASK) != mac)
			continue;
		if (dev->vlan_enabled &&
		    ((mac_vid >> ARLTBL_VID_S) & ARLTBL_VID_MASK) != vid)
			continue;
		*idx = i;
		return 0;

static void b53_arl_read_entry_95(struct b53_device *dev,
				  struct b53_arl_entry *ent, u8 idx)
{
	u32 fwd_entry;
	u64 mac_vid;

	b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx),
		   &mac_vid);
	b53_read32(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx), &fwd_entry);
	b53_arl_to_entry(ent, mac_vid, fwd_entry);
}

	*idx = find_first_bit(free_bins, dev->num_arl_bins);
	return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
static void b53_arl_write_entry_95(struct b53_device *dev,
				   const struct b53_arl_entry *ent, u8 idx)
{
	u32 fwd_entry;
	u64 mac_vid;

	b53_arl_from_entry(&mac_vid, &fwd_entry, ent);
	b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx),
		    mac_vid);
	b53_write32(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx),
		    fwd_entry);
}

static int b53_arl_read_25(struct b53_device *dev, u64 mac,
static int b53_arl_read(struct b53_device *dev, const u8 *mac,
			u16 vid, struct b53_arl_entry *ent, u8 *idx)
{
	DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
@@ -1906,21 +1935,15 @@ static int b53_arl_read_25(struct b53_device *dev, u64 mac,

	/* Read the bins */
	for (i = 0; i < dev->num_arl_bins; i++) {
		u64 mac_vid;

		b53_read64(dev, B53_ARLIO_PAGE,
			   B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);

		b53_arl_to_entry_25(ent, mac_vid);
		b53_arl_read_entry(dev, ent, i);

		if (!(mac_vid & ARLTBL_VALID_25)) {
		if (!ent->is_valid) {
			set_bit(i, free_bins);
			continue;
		}
		if ((mac_vid & ARLTBL_MAC_MASK) != mac)
		if (!ether_addr_equal(ent->mac, mac))
			continue;
		if (dev->vlan_enabled &&
		    ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid)
		if (dev->vlan_enabled && ent->vid != vid)
			continue;
		*idx = i;
		return 0;
@@ -1934,9 +1957,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
		      const unsigned char *addr, u16 vid, bool is_valid)
{
	struct b53_arl_entry ent;
	u32 fwd_entry;
	u64 mac, mac_vid = 0;
	u8 idx = 0;
	u64 mac;
	int ret;

	/* Convert the array into a 64-bit MAC */
@@ -1952,10 +1974,7 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
	if (ret)
		return ret;

	if (is5325(dev) || is5365(dev))
		ret = b53_arl_read_25(dev, mac, vid, &ent, &idx);
	else
		ret = b53_arl_read(dev, mac, vid, &ent, &idx);
	ret = b53_arl_read(dev, addr, vid, &ent, &idx);

	/* If this is a read, just finish now */
	if (op)
@@ -1972,7 +1991,6 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
		/* We could not find a matching MAC, so reset to a new entry */
		dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n",
			addr, vid, idx);
		fwd_entry = 0;
		break;
	default:
		dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n",
@@ -1999,17 +2017,7 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
	ent.is_static = true;
	ent.is_age = false;
	memcpy(ent.mac, addr, ETH_ALEN);
	if (is5325(dev) || is5365(dev))
		b53_arl_from_entry_25(&mac_vid, &ent);
	else
		b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);

	b53_write64(dev, B53_ARLIO_PAGE,
		    B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);

	if (!is5325(dev) && !is5365(dev))
		b53_write32(dev, B53_ARLIO_PAGE,
			    B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
	b53_arl_write_entry(dev, &ent, idx);

	return b53_arl_rw_op(dev, 0);
}
@@ -2044,18 +2052,53 @@ int b53_fdb_del(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_fdb_del);

static int b53_arl_search_wait(struct b53_device *dev)
static void b53_read_arl_srch_ctl(struct b53_device *dev, u8 *val)
{
	unsigned int timeout = 1000;
	u8 reg, offset;
	u8 offset;

	if (is5325(dev) || is5365(dev))
		offset = B53_ARL_SRCH_CTL_25;
	else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev) ||
		 is63xx(dev))
		offset = B53_ARL_SRCH_CTL_89;
	else
		offset = B53_ARL_SRCH_CTL;

	if (is63xx(dev)) {
		u16 val16;

		b53_read16(dev, B53_ARLIO_PAGE, offset, &val16);
		*val = val16 & 0xff;
	} else {
		b53_read8(dev, B53_ARLIO_PAGE, offset, val);
	}
}

static void b53_write_arl_srch_ctl(struct b53_device *dev, u8 val)
{
	u8 offset;

	if (is5325(dev) || is5365(dev))
		offset = B53_ARL_SRCH_CTL_25;
	else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev) ||
		 is63xx(dev))
		offset = B53_ARL_SRCH_CTL_89;
	else
		offset = B53_ARL_SRCH_CTL;

	if (is63xx(dev))
		b53_write16(dev, B53_ARLIO_PAGE, offset, val);
	else
		b53_write8(dev, B53_ARLIO_PAGE, offset, val);
}

static int b53_arl_search_wait(struct b53_device *dev)
{
	unsigned int timeout = 1000;
	u8 reg;

	do {
		b53_read8(dev, B53_ARLIO_PAGE, offset, &reg);
		b53_read_arl_srch_ctl(dev, &reg);
		if (!(reg & ARL_SRCH_STDN))
			return -ENOENT;

@@ -2068,21 +2111,55 @@ static int b53_arl_search_wait(struct b53_device *dev)
	return -ETIMEDOUT;
}

static void b53_arl_search_rd(struct b53_device *dev, u8 idx,
static void b53_arl_search_read_25(struct b53_device *dev, u8 idx,
				   struct b53_arl_entry *ent)
{
	u64 mac_vid;

	if (is5325(dev)) {
	b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25,
		   &mac_vid);
	b53_arl_to_entry_25(ent, mac_vid);
	} else if (is5365(dev)) {
}

static void b53_arl_search_read_65(struct b53_device *dev, u8 idx,
				   struct b53_arl_entry *ent)
{
	u64 mac_vid;

	b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65,
		   &mac_vid);
	b53_arl_to_entry_25(ent, mac_vid);
	} else {
}

static void b53_arl_search_read_89(struct b53_device *dev, u8 idx,
				   struct b53_arl_entry *ent)
{
	u16 fwd_entry;
	u64 mac_vid;

	b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_MACVID_89,
		   &mac_vid);
	b53_read16(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_89, &fwd_entry);
	b53_arl_to_entry_89(ent, mac_vid, fwd_entry);
}

static void b53_arl_search_read_63xx(struct b53_device *dev, u8 idx,
				     struct b53_arl_entry *ent)
{
	u16 fwd_entry;
	u64 mac_vid;

	b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_MACVID_63XX,
		   &mac_vid);
	b53_read16(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_63XX, &fwd_entry);
	b53_arl_search_to_entry_63xx(ent, mac_vid, fwd_entry);
}

static void b53_arl_search_read_95(struct b53_device *dev, u8 idx,
				   struct b53_arl_entry *ent)
{
	u32 fwd_entry;
	u64 mac_vid;

	b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx),
		   &mac_vid);
@@ -2090,7 +2167,6 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx,
		   &fwd_entry);
	b53_arl_to_entry(ent, mac_vid, fwd_entry);
}
}

static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
			dsa_fdb_dump_cb_t *cb, void *data)
@@ -2110,36 +2186,28 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
	unsigned int count = 0, results_per_hit = 1;
	struct b53_device *priv = ds->priv;
	struct b53_arl_entry results[2];
	u8 offset;
	int ret;
	u8 reg;

	if (priv->num_arl_bins > 2)
		results_per_hit = 2;

	mutex_lock(&priv->arl_mutex);

	if (is5325(priv) || is5365(priv))
		offset = B53_ARL_SRCH_CTL_25;
	else
		offset = B53_ARL_SRCH_CTL;

	/* Start search operation */
	reg = ARL_SRCH_STDN;
	b53_write8(priv, B53_ARLIO_PAGE, offset, reg);
	b53_write_arl_srch_ctl(priv, ARL_SRCH_STDN);

	do {
		ret = b53_arl_search_wait(priv);
		if (ret)
			break;

		b53_arl_search_rd(priv, 0, &results[0]);
		b53_arl_search_read(priv, 0, &results[0]);
		ret = b53_fdb_copy(port, &results[0], cb, data);
		if (ret)
			break;

		if (results_per_hit == 2) {
			b53_arl_search_rd(priv, 1, &results[1]);
			b53_arl_search_read(priv, 1, &results[1]);
			ret = b53_fdb_copy(port, &results[1], cb, data);
			if (ret)
				break;
@@ -2668,6 +2736,36 @@ static const struct dsa_switch_ops b53_switch_ops = {
	.port_change_mtu	= b53_change_mtu,
};

static const struct b53_arl_ops b53_arl_ops_25 = {
	.arl_read_entry = b53_arl_read_entry_25,
	.arl_write_entry = b53_arl_write_entry_25,
	.arl_search_read = b53_arl_search_read_25,
};

static const struct b53_arl_ops b53_arl_ops_65 = {
	.arl_read_entry = b53_arl_read_entry_25,
	.arl_write_entry = b53_arl_write_entry_25,
	.arl_search_read = b53_arl_search_read_65,
};

static const struct b53_arl_ops b53_arl_ops_89 = {
	.arl_read_entry = b53_arl_read_entry_89,
	.arl_write_entry = b53_arl_write_entry_89,
	.arl_search_read = b53_arl_search_read_89,
};

static const struct b53_arl_ops b53_arl_ops_63xx = {
	.arl_read_entry = b53_arl_read_entry_89,
	.arl_write_entry = b53_arl_write_entry_89,
	.arl_search_read = b53_arl_search_read_63xx,
};

static const struct b53_arl_ops b53_arl_ops_95 = {
	.arl_read_entry = b53_arl_read_entry_95,
	.arl_write_entry = b53_arl_write_entry_95,
	.arl_search_read = b53_arl_search_read_95,
};

struct b53_chip_data {
	u32 chip_id;
	const char *dev_name;
@@ -2681,6 +2779,7 @@ struct b53_chip_data {
	u8 duplex_reg;
	u8 jumbo_pm_reg;
	u8 jumbo_size_reg;
	const struct b53_arl_ops *arl_ops;
};

#define B53_VTA_REGS	\
@@ -2700,6 +2799,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.arl_buckets = 1024,
		.imp_port = 5,
		.duplex_reg = B53_DUPLEX_STAT_FE,
		.arl_ops = &b53_arl_ops_25,
	},
	{
		.chip_id = BCM5365_DEVICE_ID,
@@ -2710,6 +2810,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.arl_buckets = 1024,
		.imp_port = 5,
		.duplex_reg = B53_DUPLEX_STAT_FE,
		.arl_ops = &b53_arl_ops_65,
	},
	{
		.chip_id = BCM5389_DEVICE_ID,
@@ -2723,6 +2824,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_89,
	},
	{
		.chip_id = BCM5395_DEVICE_ID,
@@ -2736,6 +2838,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM5397_DEVICE_ID,
@@ -2749,6 +2852,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_89,
	},
	{
		.chip_id = BCM5398_DEVICE_ID,
@@ -2762,6 +2866,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_89,
	},
	{
		.chip_id = BCM53101_DEVICE_ID,
@@ -2775,6 +2880,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53115_DEVICE_ID,
@@ -2788,6 +2894,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53125_DEVICE_ID,
@@ -2801,6 +2908,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53128_DEVICE_ID,
@@ -2814,19 +2922,21 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM63XX_DEVICE_ID,
		.dev_name = "BCM63xx",
		.vlans = 4096,
		.enabled_ports = 0, /* pdata must provide them */
		.arl_bins = 4,
		.arl_buckets = 1024,
		.arl_bins = 1,
		.arl_buckets = 4096,
		.imp_port = 8,
		.vta_regs = B53_VTA_REGS_63XX,
		.duplex_reg = B53_DUPLEX_STAT_63XX,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
		.arl_ops = &b53_arl_ops_63xx,
	},
	{
		.chip_id = BCM53010_DEVICE_ID,
@@ -2840,6 +2950,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53011_DEVICE_ID,
@@ -2853,6 +2964,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53012_DEVICE_ID,
@@ -2866,6 +2978,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53018_DEVICE_ID,
@@ -2879,6 +2992,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53019_DEVICE_ID,
@@ -2892,6 +3006,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM58XX_DEVICE_ID,
@@ -2905,6 +3020,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM583XX_DEVICE_ID,
@@ -2918,6 +3034,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	/* Starfighter 2 */
	{
@@ -2932,6 +3049,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM7445_DEVICE_ID,
@@ -2945,6 +3063,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM7278_DEVICE_ID,
@@ -2958,6 +3077,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
	{
		.chip_id = BCM53134_DEVICE_ID,
@@ -2972,6 +3092,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
		.duplex_reg = B53_DUPLEX_STAT_GE,
		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
		.arl_ops = &b53_arl_ops_95,
	},
};

@@ -3000,6 +3121,7 @@ static int b53_switch_init(struct b53_device *dev)
			dev->num_vlans = chip->vlans;
			dev->num_arl_bins = chip->arl_bins;
			dev->num_arl_buckets = chip->arl_buckets;
			dev->arl_ops = chip->arl_ops;
			break;
		}
	}
+71 −0
Original line number Diff line number Diff line
@@ -58,6 +58,17 @@ struct b53_io_ops {
				bool link_up);
};

struct b53_arl_entry;

struct b53_arl_ops {
	void (*arl_read_entry)(struct b53_device *dev,
			       struct b53_arl_entry *ent, u8 idx);
	void (*arl_write_entry)(struct b53_device *dev,
				const struct b53_arl_entry *ent, u8 idx);
	void (*arl_search_read)(struct b53_device *dev, u8 idx,
				struct b53_arl_entry *ent);
};

#define B53_INVALID_LANE	0xff

enum {
@@ -127,6 +138,7 @@ struct b53_device {
	struct mutex stats_mutex;
	struct mutex arl_mutex;
	const struct b53_io_ops *ops;
	const struct b53_arl_ops *arl_ops;

	/* chip specific data */
	u32 chip_id;
@@ -341,6 +353,18 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent,
	ent->vid = mac_vid >> ARLTBL_VID_S_65;
}

static inline void b53_arl_to_entry_89(struct b53_arl_entry *ent,
				       u64 mac_vid, u16 fwd_entry)
{
	memset(ent, 0, sizeof(*ent));
	ent->port = fwd_entry & ARLTBL_DATA_PORT_ID_MASK_89;
	ent->is_valid = !!(fwd_entry & ARLTBL_VALID_89);
	ent->is_age = !!(fwd_entry & ARLTBL_AGE_89);
	ent->is_static = !!(fwd_entry & ARLTBL_STATIC_89);
	u64_to_ether_addr(mac_vid, ent->mac);
	ent->vid = mac_vid >> ARLTBL_VID_S;
}

static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
				      const struct b53_arl_entry *ent)
{
@@ -371,6 +395,53 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid,
		*mac_vid |= ARLTBL_AGE_25;
}

static inline void b53_arl_from_entry_89(u64 *mac_vid, u32 *fwd_entry,
					 const struct b53_arl_entry *ent)
{
	*mac_vid = ether_addr_to_u64(ent->mac);
	*mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK) << ARLTBL_VID_S;
	*fwd_entry = ent->port & ARLTBL_DATA_PORT_ID_MASK_89;
	if (ent->is_valid)
		*fwd_entry |= ARLTBL_VALID_89;
	if (ent->is_static)
		*fwd_entry |= ARLTBL_STATIC_89;
	if (ent->is_age)
		*fwd_entry |= ARLTBL_AGE_89;
}

static inline void b53_arl_search_to_entry_63xx(struct b53_arl_entry *ent,
						u64 mac_vid, u16 fwd_entry)
{
	memset(ent, 0, sizeof(*ent));
	u64_to_ether_addr(mac_vid, ent->mac);
	ent->vid = mac_vid >> ARLTBL_VID_S;

	ent->port = fwd_entry & ARL_SRST_PORT_ID_MASK_63XX;
	ent->port >>= 1;

	ent->is_age = !!(fwd_entry & ARL_SRST_AGE_63XX);
	ent->is_static = !!(fwd_entry & ARL_SRST_STATIC_63XX);
	ent->is_valid = 1;
}

static inline void b53_arl_read_entry(struct b53_device *dev,
				      struct b53_arl_entry *ent, u8 idx)
{
	dev->arl_ops->arl_read_entry(dev, ent, idx);
}

static inline void b53_arl_write_entry(struct b53_device *dev,
				       const struct b53_arl_entry *ent, u8 idx)
{
	dev->arl_ops->arl_write_entry(dev, ent, idx);
}

static inline void b53_arl_search_read(struct b53_device *dev, u8 idx,
				       struct b53_arl_entry *ent)
{
	dev->arl_ops->arl_search_read(dev, idx, ent);
}

#ifdef CONFIG_BCM47XX

#include <linux/bcm47xx_nvram.h>
+22 −0
Original line number Diff line number Diff line
@@ -346,12 +346,20 @@
#define   ARLTBL_STATIC			BIT(15)
#define   ARLTBL_VALID			BIT(16)

/* BCM5389 ARL Table Data Entry N Register format (16 bit) */
#define   ARLTBL_DATA_PORT_ID_MASK_89	GENMASK(8, 0)
#define   ARLTBL_TC_MASK_89		GENMASK(12, 10)
#define   ARLTBL_AGE_89			BIT(13)
#define   ARLTBL_STATIC_89		BIT(14)
#define   ARLTBL_VALID_89		BIT(15)

/* Maximum number of bin entries in the ARL for all switches */
#define B53_ARLTBL_MAX_BIN_ENTRIES	4

/* ARL Search Control Register (8 bit) */
#define B53_ARL_SRCH_CTL		0x50
#define B53_ARL_SRCH_CTL_25		0x20
#define B53_ARL_SRCH_CTL_89		0x30
#define   ARL_SRCH_VLID			BIT(0)
#define   ARL_SRCH_STDN			BIT(7)

@@ -359,10 +367,14 @@
#define B53_ARL_SRCH_ADDR		0x51
#define B53_ARL_SRCH_ADDR_25		0x22
#define B53_ARL_SRCH_ADDR_65		0x24
#define B53_ARL_SRCH_ADDR_89		0x31
#define B53_ARL_SRCH_ADDR_63XX		0x32
#define  ARL_ADDR_MASK			GENMASK(14, 0)

/* ARL Search MAC/VID Result (64 bit) */
#define B53_ARL_SRCH_RSTL_0_MACVID	0x60
#define B53_ARL_SRCH_RSLT_MACVID_89	0x33
#define B53_ARL_SRCH_RSLT_MACVID_63XX	0x34

/* Single register search result on 5325 */
#define B53_ARL_SRCH_RSTL_0_MACVID_25	0x24
@@ -372,9 +384,19 @@
/* ARL Search Data Result (32 bit) */
#define B53_ARL_SRCH_RSTL_0		0x68

/* BCM5389 ARL Search Data Result (16 bit) */
#define B53_ARL_SRCH_RSLT_89		0x3b

#define B53_ARL_SRCH_RSTL_MACVID(x)	(B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10))
#define B53_ARL_SRCH_RSTL(x)		(B53_ARL_SRCH_RSTL_0 + ((x) * 0x10))

/* 63XX ARL Search Data Result (16 bit) */
#define B53_ARL_SRCH_RSLT_63XX		0x3c
#define   ARL_SRST_PORT_ID_MASK_63XX	GENMASK(9, 1)
#define   ARL_SRST_TC_MASK_63XX		GENMASK(13, 11)
#define   ARL_SRST_AGE_63XX		BIT(14)
#define   ARL_SRST_STATIC_63XX		BIT(15)

/*************************************************************************
 * IEEE 802.1X Registers
 *************************************************************************/