All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alvin Šipraga" <alvin.sipraga@analog.com>
To: Mieczyslaw Nalewaj <namiltd@yahoo.com>
Cc: linusw@kernel.org, andrew@lunn.ch, olteanv@gmail.com,
	kuba@kernel.org, davem@davemloft.net, edumazet@google.com,
	pabeni@redhat.com, linux@armlinux.org.uk, luizluca@gmail.com,
	maxime.chevallier@bootlin.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v7 09/10] net: dsa: realtek: rtl8365mb: make L2/LUT access work on family D
Date: Tue, 3 Nov 2026 16:36:12 +0100	[thread overview]
Message-ID: <aun7hiSq4MF5BXOc@analog.com> (raw)
In-Reply-To: <88239c31-e161-4623-8dbb-db39f506af6f@yahoo.com>

On Mon, Nov 02, 2026 at 03:44:36PM +0100, Mieczyslaw Nalewaj wrote:
> The L2 lookup table on family D switches (e.g. RTL8367S-VB) differs
> from family C in ways that make the current FDB/MDB code misbehave:
> 
>  - An L2 entry is 5 words instead of 6, with a different field layout
>    in words 3 and 4 (port, age, static and multicast member bits).
>  - There is no EFID and no per-bridge FDB isolation. The register at
>    0x0A32, used as the per-port EFID register on family C, is the LUT
>    aging timer on family D, so writing an EFID there corrupts it.
>  - In the table access interface, the SPA field is 3 bits wide and the
>    address register is 12 bits wide, with no address extension bit.
>  - Only ports 0..7 are present in the LUT and there is no
>    FLUSH_PORT_EXT register.
> 
> Teach the table and L2 code about these differences, selecting the
> layout at runtime with rtl8365mb_get_family(). Family C behaviour is
> unchanged.
> 
> Specifically:
> 
>  - rtl8365mb_table: use the family D port mask and address width, and
>    read the hit address from status bits [11:0].
>  - rtl8365mb_l2: add family D unicast/multicast entry (de)serialisers
>    behind *_any() wrappers, pass the proper entry size to the table
>    layer, reject ports above 7, report SVL (FID) entries with VID 0.
>    Use age 6 for static unicast entries as the vendor code does, and
>    look an entry up before deleting it so that a missing entry is not
>    allocated by the delete.
>  - rtl8365mb_main: make port_set_efid() a no-op on family D, add a LUT
>    init step that clears IPMC_HASH and BCAM_DISABLE and programs the
>    aging timer, and do not advertise fdb_isolation or
>    max_num_bridges. Traffic between bridges is then isolated by the
>    port isolation masks only.
> 
> Register layouts were taken from the family D register description;
> the code itself is an independent implementation.
> 
> No chip uses family D before the last patch of the series, so this code
> is unreachable until then.
> 
> Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
> ---
>  drivers/net/dsa/realtek/rtl8365mb_l2.c    | 216 ++++++++++++++++++++--
>  drivers/net/dsa/realtek/rtl8365mb_main.c  |  46 ++++-
>  drivers/net/dsa/realtek/rtl8365mb_table.c |  46 ++++-
>  3 files changed, 276 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/net/dsa/realtek/rtl8365mb_l2.c b/drivers/net/dsa/realtek/rtl8365mb_l2.c
> index 0494d8a..a7613e2 100644
> --- a/drivers/net/dsa/realtek/rtl8365mb_l2.c
> +++ b/drivers/net/dsa/realtek/rtl8365mb_l2.c
> @@ -8,9 +8,12 @@
>  
>  #include "rtl8365mb_l2.h"
>  #include "rtl8365mb_table.h"
> +#include "rtl8365mb.h"
>  #include <linux/regmap.h>
>  
>  #define RTL8365MB_L2_ENTRY_SIZE			6
> +#define RTL8365MB_D_L2_ENTRY_SIZE		5
> +#define RTL8365MB_D_L2_MAX_PORT			7
>  
>  #define RTL8365MB_L2_UC_D0_MAC5_MSK		GENMASK(7, 0)
>  #define RTL8365MB_L2_UC_D0_MAC4_MSK		GENMASK(15, 8)
> @@ -58,6 +61,21 @@
>  #define RTL8365MB_L2_MC_D5_MBR_HI2_MSK		GENMASK(7, 7)
>  #define   RTL8365MB_L2_MC_MBR_HI2_MSK		GENMASK(10, 10)
>  
> +/* Family D unicast (auto-learn / static) entry */
> +#define RTL8365MB_D_L2_UC_D3_VID_MSK		GENMASK(11, 0)
> +#define RTL8365MB_D_L2_UC_D3_IVL_MSK		BIT(13)
> +#define RTL8365MB_D_L2_UC_D3_PORT_LO_MSK	GENMASK(15, 14)
> +#define RTL8365MB_D_L2_UC_D4_PORT_HI_MSK	BIT(0)
> +#define RTL8365MB_D_L2_UC_D4_AGE_MSK		GENMASK(3, 1)
> +#define RTL8365MB_D_L2_UC_D4_STATIC_MSK		BIT(6)
> +
> +/* Family D multicast entry */
> +#define RTL8365MB_D_L2_MC_D3_VID_MSK		GENMASK(11, 0)
> +#define RTL8365MB_D_L2_MC_D3_IVL_MSK		BIT(13)
> +#define RTL8365MB_D_L2_MC_D3_MBR_LO_MSK		GENMASK(15, 14)
> +#define RTL8365MB_D_L2_MC_D4_MBR_HI_MSK		GENMASK(5, 0)
> +#define RTL8365MB_D_L2_MC_D4_STATIC_MSK		BIT(6)
> +
>  /* Port flush command registers - writing a 1 to the port's MASK bit will
>   * initiate the flush procedure. Completion is signalled when the corresponding
>   * BUSY bit is 0.
> @@ -258,6 +276,130 @@ static void rtl8365mb_l2_mc_to_data(const struct rtl8365mb_l2_mc *mc, u16 *data)
>  	data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_MBR_HI2_MSK, val);
>  }
>  
> +static bool rtl8365mb_l2_is_d(struct realtek_priv *priv)
> +{
> +	return rtl8365mb_get_family(priv) == RTL8365MB_FAMILY_D;
> +}

Shouldn't this be a top-level function, like rtl8365mb_is_d()?

> +
> +static size_t rtl8365mb_l2_entry_size(struct realtek_priv *priv)
> +{
> +	return rtl8365mb_l2_is_d(priv) ? RTL8365MB_D_L2_ENTRY_SIZE :
> +					 RTL8365MB_L2_ENTRY_SIZE;
> +}
> +
> +static void rtl8365mb_l2_mac_to_data(const u8 *m, u16 *data)
> +{
> +	data[0] = (m[4] << 8) | m[5];
> +	data[1] = (m[2] << 8) | m[3];
> +	data[2] = (m[0] << 8) | m[1];
> +}
> +
> +static void rtl8365mb_l2_data_to_mac(const u16 *data, u8 *m)
> +{
> +	m[5] = data[0] & 0xff;
> +	m[4] = data[0] >> 8;
> +	m[3] = data[1] & 0xff;
> +	m[2] = data[1] >> 8;
> +	m[1] = data[2] & 0xff;
> +	m[0] = data[2] >> 8;
> +}

From the diff it would seem that this is specific to the D family, since
you only use it in those functions. But looking over my crappy original
code for the C family, it's quite the same is it not? Can't you update
the C family functions to use these helpers too?

> +
> +static void rtl8365mb_d_l2_data_to_uc(const u16 *data,
> +				      struct rtl8365mb_l2_uc *uc)
> +{
> +	rtl8365mb_l2_data_to_mac(data, uc->key.mac_addr);
> +	uc->key.vid = FIELD_GET(RTL8365MB_D_L2_UC_D3_VID_MSK, data[3]);
> +	uc->key.ivl = FIELD_GET(RTL8365MB_D_L2_UC_D3_IVL_MSK, data[3]);
> +	uc->key.fid = 0;
> +	uc->key.efid = 0;
> +	uc->port = FIELD_GET(RTL8365MB_D_L2_UC_D3_PORT_LO_MSK, data[3]) |
> +		   (FIELD_GET(RTL8365MB_D_L2_UC_D4_PORT_HI_MSK, data[4]) << 2);
> +	uc->age = FIELD_GET(RTL8365MB_D_L2_UC_D4_AGE_MSK, data[4]);
> +	uc->is_static = FIELD_GET(RTL8365MB_D_L2_UC_D4_STATIC_MSK, data[4]);
> +}
> +
> +static void rtl8365mb_d_l2_uc_to_data(const struct rtl8365mb_l2_uc *uc,
> +				      u16 *data)
> +{
> +	memset(data, 0, RTL8365MB_L2_ENTRY_SIZE * 2);
> +	rtl8365mb_l2_mac_to_data(uc->key.mac_addr, data);
> +	data[3] = FIELD_PREP(RTL8365MB_D_L2_UC_D3_VID_MSK, uc->key.vid) |
> +		  FIELD_PREP(RTL8365MB_D_L2_UC_D3_IVL_MSK, uc->key.ivl) |
> +		  FIELD_PREP(RTL8365MB_D_L2_UC_D3_PORT_LO_MSK, uc->port & 0x3);
> +	data[4] = FIELD_PREP(RTL8365MB_D_L2_UC_D4_PORT_HI_MSK,
> +			     (uc->port >> 2) & 0x1) |
> +		  FIELD_PREP(RTL8365MB_D_L2_UC_D4_AGE_MSK, uc->age) |
> +		  FIELD_PREP(RTL8365MB_D_L2_UC_D4_STATIC_MSK, uc->is_static);
> +}
> +
> +static void rtl8365mb_d_l2_data_to_mc(const u16 *data,
> +				      struct rtl8365mb_l2_mc *mc)
> +{
> +	rtl8365mb_l2_data_to_mac(data, mc->key.mac_addr);
> +	mc->key.vid = FIELD_GET(RTL8365MB_D_L2_MC_D3_VID_MSK, data[3]);
> +	mc->key.ivl = FIELD_GET(RTL8365MB_D_L2_MC_D3_IVL_MSK, data[3]);
> +	mc->member = FIELD_GET(RTL8365MB_D_L2_MC_D3_MBR_LO_MSK, data[3]) |
> +		     (FIELD_GET(RTL8365MB_D_L2_MC_D4_MBR_HI_MSK, data[4]) << 2);
> +	mc->is_static = FIELD_GET(RTL8365MB_D_L2_MC_D4_STATIC_MSK, data[4]);
> +	mc->igmpidx = 0;
> +	mc->priority = 0;
> +	mc->fwd_pri = 0;
> +	mc->igmp_asic = 0;
> +}
> +
> +static void rtl8365mb_d_l2_mc_to_data(const struct rtl8365mb_l2_mc *mc,
> +				      u16 *data)
> +{
> +	memset(data, 0, RTL8365MB_L2_ENTRY_SIZE * 2);
> +	rtl8365mb_l2_mac_to_data(mc->key.mac_addr, data);
> +	data[3] = FIELD_PREP(RTL8365MB_D_L2_MC_D3_VID_MSK, mc->key.vid) |
> +		  FIELD_PREP(RTL8365MB_D_L2_MC_D3_IVL_MSK, mc->key.ivl) |
> +		  FIELD_PREP(RTL8365MB_D_L2_MC_D3_MBR_LO_MSK, mc->member & 0x3);
> +	data[4] = FIELD_PREP(RTL8365MB_D_L2_MC_D4_MBR_HI_MSK,
> +			     (mc->member >> 2) & 0x3f) |
> +		  FIELD_PREP(RTL8365MB_D_L2_MC_D4_STATIC_MSK, mc->is_static);
> +}
> +
> +static void rtl8365mb_l2_data_to_uc_any(struct realtek_priv *priv,
> +					const u16 *data,
> +					struct rtl8365mb_l2_uc *uc)
> +{
> +	if (rtl8365mb_l2_is_d(priv))
> +		rtl8365mb_d_l2_data_to_uc(data, uc);
> +	else
> +		rtl8365mb_l2_data_to_uc(data, uc);
> +}

Can't we have:

rtl8365mb_l2_data_to_uc() # same as before at all callsites

call into either:

rtl8365mb_c_l2_data_to_uc()
rtl8365mb_d_l2_data_to_uc()

instead?

Right now it looks quite asymmetric. And the _any() is confusing when
reading the code downstairs. (One wonders, what does "any" mean? Of
course, it's obvious when you read this function.)

Even though family C is the originally supported family, I guess D is an
equal citizen, so it's good to keep things in this driver symmetric.

> +
> +static void rtl8365mb_l2_uc_to_data_any(struct realtek_priv *priv,
> +					const struct rtl8365mb_l2_uc *uc,
> +					u16 *data)
> +{
> +	if (rtl8365mb_l2_is_d(priv))
> +		rtl8365mb_d_l2_uc_to_data(uc, data);
> +	else
> +		rtl8365mb_l2_uc_to_data(uc, data);
> +}
> +
> +static void rtl8365mb_l2_data_to_mc_any(struct realtek_priv *priv,
> +					const u16 *data,
> +					struct rtl8365mb_l2_mc *mc)
> +{
> +	if (rtl8365mb_l2_is_d(priv))
> +		rtl8365mb_d_l2_data_to_mc(data, mc);
> +	else
> +		rtl8365mb_l2_data_to_mc(data, mc);
> +}
> +
> +static void rtl8365mb_l2_mc_to_data_any(struct realtek_priv *priv,
> +					const struct rtl8365mb_l2_mc *mc,
> +					u16 *data)
> +{
> +	if (rtl8365mb_l2_is_d(priv))
> +		rtl8365mb_d_l2_mc_to_data(mc, data);
> +	else
> +		rtl8365mb_l2_mc_to_data(mc, data);
> +}
> +

The above comment applies to all these _any() functions.

Kind regards,
Alvin

  reply	other threads:[~2026-11-03 15:36 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <3bf4dd70-9771-497b-8c27-e925e0ef81eb.ref@yahoo.com>
2026-11-02 14:34 ` [PATCH net-next v7 0/10] net: dsa: realtek: rtl8365mb: add support for RTL8367S-VB Mieczyslaw Nalewaj
2026-11-02 14:36   ` [PATCH net-next v7 01/10] dt-bindings: net: dsa: realtek: add RTL8367S-VB Mieczyslaw Nalewaj
2026-11-02 14:37   ` [PATCH net-next v7 02/10] net: dsa: realtek: rtl8365mb: add chip family infrastructure Mieczyslaw Nalewaj
2026-11-02 14:38   ` [PATCH net-next v7 03/10] net: dsa: realtek: rtl8365mb: set speed for family D Mieczyslaw Nalewaj
2026-11-04 12:20     ` Alvin Šipraga
2026-11-02 14:39   ` [PATCH net-next v7 04/10] net: dsa: realtek: rtl8365mb: set RGMII mode " Mieczyslaw Nalewaj
2026-11-04 12:39     ` Alvin Šipraga
2026-11-05  7:56       ` Mieczyslaw Nalewaj
2026-11-05 12:39         ` Alvin Šipraga
2026-11-05 15:27           ` Mieczyslaw Nalewaj
2026-11-02 14:40   ` [PATCH net-next v7 05/10] net: dsa: realtek: rtl8365mb: set and get vlan 4k " Mieczyslaw Nalewaj
2026-11-04 12:45     ` Alvin Šipraga
2026-11-02 14:41   ` [PATCH net-next v7 06/10] net: dsa: realtek: rtl8365mb: use raw VID for PVID on " Mieczyslaw Nalewaj
2026-11-02 14:42   ` [PATCH net-next v7 07/10] net: dsa: realtek: rtl8365mb: add family D SDS13 PCS support Mieczyslaw Nalewaj
2026-11-02 14:43   ` [PATCH net-next v7 08/10] net: dsa: realtek: rtl8365mb: re-latch the family D SerDes Mieczyslaw Nalewaj
2026-11-04 12:57     ` Alvin Šipraga
2026-11-05  7:18       ` Mieczyslaw Nalewaj
2026-11-05  8:52         ` Alvin Šipraga
2026-11-05 10:24           ` Mieczyslaw Nalewaj
2026-11-05 12:09             ` Alvin Šipraga
2026-11-02 14:44   ` [PATCH net-next v7 09/10] net: dsa: realtek: rtl8365mb: make L2/LUT access work on family D Mieczyslaw Nalewaj
2026-11-03 15:36     ` Alvin Šipraga [this message]
2026-11-03 16:44       ` Mieczyslaw Nalewaj
2026-11-02 14:45   ` [PATCH net-next v7 10/10] net: dsa: realtek: rtl8365mb: add support for RTL8367S-VB Mieczyslaw Nalewaj
2026-11-03 22:52     ` Alvin Šipraga
2026-11-03 23:41       ` Mieczyslaw Nalewaj
2026-11-04  9:40         ` Mieczyslaw Nalewaj
2026-11-04 13:14           ` Alvin Šipraga
2026-11-04 16:37             ` Mieczyslaw Nalewaj

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aun7hiSq4MF5BXOc@analog.com \
    --to=alvin.sipraga@analog.com \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=linusw@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=luizluca@gmail.com \
    --cc=maxime.chevallier@bootlin.com \
    --cc=namiltd@yahoo.com \
    --cc=netdev@vger.kernel.org \
    --cc=olteanv@gmail.com \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.