Commit 6344dbde authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller
Browse files

net: dsa: b53: Rework ARL bin logic



When asking the ARL to read a MAC address, we will get a number of bins
returned in a single read. Out of those bins, there can essentially be 3
states:

- all bins are full, we have no space left, and we can either replace an
  existing address or return that full condition

- the MAC address was found, then we need to return its bin index and
  modify that one, and only that one

- the MAC address was not found and we have a least one bin free, we use
  that bin index location then

The code would unfortunately fail on all counts.

Fixes: 1da6df85 ("net: dsa: b53: Implement ARL add/del/dump operations")
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c2e77a18
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -1483,6 +1483,7 @@ static int b53_arl_read(struct b53_device *dev, u64 mac,
			u16 vid, struct b53_arl_entry *ent, u8 *idx,
			bool is_valid)
{
	DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
	unsigned int i;
	int ret;

@@ -1490,6 +1491,8 @@ static int b53_arl_read(struct b53_device *dev, u64 mac,
	if (ret)
		return ret;

	bitmap_zero(free_bins, dev->num_arl_entries);

	/* Read the bins */
	for (i = 0; i < dev->num_arl_entries; i++) {
		u64 mac_vid;
@@ -1501,16 +1504,24 @@ static int b53_arl_read(struct b53_device *dev, u64 mac,
			   B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
		b53_arl_to_entry(ent, mac_vid, fwd_entry);

		if (!(fwd_entry & ARLTBL_VALID))
		if (!(fwd_entry & ARLTBL_VALID)) {
			set_bit(i, free_bins);
			continue;
		}
		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;
	}

	if (bitmap_weight(free_bins, dev->num_arl_entries) == 0)
		return -ENOSPC;

	*idx = find_first_bit(free_bins, dev->num_arl_entries);

	return -ENOENT;
}

@@ -1540,10 +1551,21 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
	if (op)
		return ret;

	switch (ret) {
	case -ENOSPC:
		dev_dbg(dev->dev, "{%pM,%.4d} no space left in ARL\n",
			addr, vid);
		return is_valid ? ret : 0;
	case -ENOENT:
		/* We could not find a matching MAC, so reset to a new entry */
	if (ret) {
		dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n",
			addr, vid, idx);
		fwd_entry = 0;
		idx = 1;
		break;
	default:
		dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n",
			addr, vid, idx);
		break;
	}

	/* For multicast address, the port is a bitmask and the validity
+3 −0
Original line number Diff line number Diff line
@@ -323,6 +323,9 @@
#define   ARLTBL_STATIC			BIT(15)
#define   ARLTBL_VALID			BIT(16)

/* 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