realtek: table: separate table access from DSA

The Otto SoCs reach most of their switch state through indirect table
access: a command word carrying table, index and direction goes into
one register, and the entry itself appears in a window of data
registers. That mechanism is not layer 2 and has no natural home in a
DSA driver; it sits in common.c only because DSA happens to be its
first consumer.

Move the descriptor array, struct table_reg and the rtl_table_*
functions verbatim into table.c and table.h. Nothing is renamed and no
line of the implementation changes; rtl-otto.h includes the new header,
so every consumer compiles unchanged.

The consumers already called these symbols externally, so relocating
the definitions only moves them from common.o to table.o. Built for
realtek/rtl930x before and after: rtl838x.o, rtl839x.o, rtl930x.o,
rtl931x.o and l3.o are identical once debug sections are stripped, and
common.o loses 1536 bytes of code and data, 1004 of text and 532 of
data. The raw objects do differ,
because CONFIG_DEBUG_INFO records line numbers from rtl-otto.h.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25062
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
Gennaro Cimmino authored and Markus Stockhausen committed 2026-09-08 20:18:58 +02:00
1 parent 870c10eb8f
commit 11ee1eed06
5 files changed
+184 -166

No files matched your search

@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_NET_DSA_RTL83XX) += rtl_otto_dsa.o
rtl_otto_dsa-objs := common.o dsa.o rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o tc.o l3.o
rtl_otto_dsa-objs := common.o table.o dsa.o rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o tc.o l3.o
@@ -33,122 +33,6 @@ int rtldsa_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
return state;
}
static struct table_reg rtl838x_tbl_regs[] = {
TBL_DESC(0x6900, 0x6908, 3, 15, 13, 1), /* RTL8380_TBL_L2 */
TBL_DESC(0x6914, 0x6918, 18, 14, 12, 1), /* RTL8380_TBL_0 */
TBL_DESC(0xA4C8, 0xA4CC, 6, 14, 12, 1), /* RTL8380_TBL_1 */
TBL_DESC(0x1180, 0x1184, 3, 16, 14, 0), /* RTL8390_TBL_L2 */
TBL_DESC(0x1190, 0x1194, 17, 15, 12, 0), /* RTL8390_TBL_0 */
TBL_DESC(0x6B80, 0x6B84, 4, 14, 12, 0), /* RTL8390_TBL_1 */
TBL_DESC(0x611C, 0x6120, 9, 8, 6, 0), /* RTL8390_TBL_2 */
TBL_DESC(0xB320, 0xB334, 3, 18, 16, 0), /* RTL9300_TBL_L2 */
TBL_DESC(0xB340, 0xB344, 19, 16, 12, 0), /* RTL9300_TBL_0 */
TBL_DESC(0xB3A0, 0xB3A4, 20, 16, 13, 0), /* RTL9300_TBL_1 */
TBL_DESC(0xCE04, 0xCE08, 6, 14, 12, 0), /* RTL9300_TBL_2 */
TBL_DESC(0xD600, 0xD604, 30, 7, 6, 0), /* RTL9300_TBL_HSB */
TBL_DESC(0x7880, 0x7884, 22, 9, 8, 0), /* RTL9300_TBL_HSA */
TBL_DESC(0x8500, 0x8508, 8, 19, 15, 0), /* RTL9310_TBL_0 */
TBL_DESC(0x40C0, 0x40C4, 22, 16, 14, 0), /* RTL9310_TBL_1 */
TBL_DESC(0x8528, 0x852C, 6, 18, 14, 0), /* RTL9310_TBL_2 */
TBL_DESC(0x0200, 0x0204, 9, 15, 12, 0), /* RTL9310_TBL_3 */
TBL_DESC(0x20dc, 0x20e0, 29, 7, 6, 0), /* RTL9310_TBL_4 */
TBL_DESC(0x7e1c, 0x7e20, 53, 8, 6, 0), /* RTL9310_TBL_5 */
};
void rtl_table_init(void)
{
for (int i = 0; i < RTL_TBL_END; i++)
mutex_init(&rtl838x_tbl_regs[i].lock);
}
/* Request access to table t in table access register r
* Returns a handle to a lock for that table
*/
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
{
if (r >= RTL_TBL_END)
return NULL;
if (t >= BIT(rtl838x_tbl_regs[r].c_bit - rtl838x_tbl_regs[r].t_bit))
return NULL;
mutex_lock(&rtl838x_tbl_regs[r].lock);
rtl838x_tbl_regs[r].tbl = t;
return &rtl838x_tbl_regs[r];
}
/* Release a table r, unlock the corresponding lock */
void rtl_table_release(struct table_reg *r)
{
if (!r)
return;
/* pr_info("Unlocking %08x\n", (u32)r); */
mutex_unlock(&r->lock);
/* pr_info("Unlock done\n"); */
}
static int rtl_table_exec(struct table_reg *r, bool is_write, int idx)
{
int ret = 0;
u32 cmd, val;
/* Read/write bit has inverted meaning on RTL838x */
if (r->rmode)
cmd = is_write ? 0 : BIT(r->c_bit);
else
cmd = is_write ? BIT(r->c_bit) : 0;
cmd |= BIT(r->c_bit + 1); /* Execute bit */
cmd |= r->tbl << r->t_bit; /* Table type */
cmd |= idx & (BIT(r->t_bit) - 1); /* Index */
sw_w32(cmd, r->addr);
ret = readx_poll_timeout(sw_r32, r->addr, val,
!(val & BIT(r->c_bit + 1)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/* Reads table index idx into the data registers of the table */
int rtl_table_read(struct table_reg *r, int idx)
{
return rtl_table_exec(r, false, idx);
}
/* Writes the content of the table data registers into the table at index idx */
int rtl_table_write(struct table_reg *r, int idx)
{
return rtl_table_exec(r, true, idx);
}
/* Returns the address of the ith data register of table register r
* the address is relative to the beginning of the Switch-IO block at 0xbb000000
*/
inline u16 rtl_table_data(struct table_reg *r, int i)
{
if (i >= r->max_data)
i = r->max_data - 1;
return r->data + i * 4;
}
inline u32 rtl_table_data_r(struct table_reg *r, int i)
{
return sw_r32(rtl_table_data(r, i));
}
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i)
{
sw_w32(v, rtl_table_data(r, i));
}
/* Port register accessor functions for the RTL838x and RTL930X SoCs */
void rtl838x_mask_port_reg(u64 clear, u64 set, int reg)
{
@@ -6,6 +6,8 @@
#include <asm/mach-rtl-otto/mach-rtl-otto.h>
#include <net/dsa.h>
#include "table.h"
/* Register definition */
#define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7)))
#define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7)))
@@ -1634,55 +1636,6 @@ struct rtldsa_mib_desc {
const struct rtldsa_mib_list_item *list;
};
/* API for switch table access */
struct table_reg {
u16 addr;
u16 data;
u8 max_data;
u8 c_bit;
u8 t_bit;
u8 rmode;
u8 tbl;
struct mutex lock;
};
#define TBL_DESC(_addr, _data, _max_data, _c_bit, _t_bit, _rmode) \
{ .addr = _addr, .data = _data, .max_data = _max_data, .c_bit = _c_bit, \
.t_bit = _t_bit, .rmode = _rmode \
}
typedef enum {
RTL8380_TBL_L2 = 0,
RTL8380_TBL_0,
RTL8380_TBL_1,
RTL8390_TBL_L2,
RTL8390_TBL_0,
RTL8390_TBL_1,
RTL8390_TBL_2,
RTL9300_TBL_L2,
RTL9300_TBL_0,
RTL9300_TBL_1,
RTL9300_TBL_2,
RTL9300_TBL_HSB,
RTL9300_TBL_HSA,
RTL9310_TBL_0,
RTL9310_TBL_1,
RTL9310_TBL_2,
RTL9310_TBL_3,
RTL9310_TBL_4,
RTL9310_TBL_5,
RTL_TBL_END
} rtl838x_tbl_reg_t;
void rtl_table_init(void);
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t);
void rtl_table_release(struct table_reg *r);
int rtl_table_read(struct table_reg *r, int idx);
int rtl_table_write(struct table_reg *r, int idx);
inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
struct netdev_lag_upper_info *info);
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/iopoll.h>
#include <linux/mutex.h>
#include <asm/mach-rtl-otto/mach-rtl-otto.h>
#include "table.h"
static struct table_reg rtl838x_tbl_regs[] = {
TBL_DESC(0x6900, 0x6908, 3, 15, 13, 1), /* RTL8380_TBL_L2 */
TBL_DESC(0x6914, 0x6918, 18, 14, 12, 1), /* RTL8380_TBL_0 */
TBL_DESC(0xA4C8, 0xA4CC, 6, 14, 12, 1), /* RTL8380_TBL_1 */
TBL_DESC(0x1180, 0x1184, 3, 16, 14, 0), /* RTL8390_TBL_L2 */
TBL_DESC(0x1190, 0x1194, 17, 15, 12, 0), /* RTL8390_TBL_0 */
TBL_DESC(0x6B80, 0x6B84, 4, 14, 12, 0), /* RTL8390_TBL_1 */
TBL_DESC(0x611C, 0x6120, 9, 8, 6, 0), /* RTL8390_TBL_2 */
TBL_DESC(0xB320, 0xB334, 3, 18, 16, 0), /* RTL9300_TBL_L2 */
TBL_DESC(0xB340, 0xB344, 19, 16, 12, 0), /* RTL9300_TBL_0 */
TBL_DESC(0xB3A0, 0xB3A4, 20, 16, 13, 0), /* RTL9300_TBL_1 */
TBL_DESC(0xCE04, 0xCE08, 6, 14, 12, 0), /* RTL9300_TBL_2 */
TBL_DESC(0xD600, 0xD604, 30, 7, 6, 0), /* RTL9300_TBL_HSB */
TBL_DESC(0x7880, 0x7884, 22, 9, 8, 0), /* RTL9300_TBL_HSA */
TBL_DESC(0x8500, 0x8508, 8, 19, 15, 0), /* RTL9310_TBL_0 */
TBL_DESC(0x40C0, 0x40C4, 22, 16, 14, 0), /* RTL9310_TBL_1 */
TBL_DESC(0x8528, 0x852C, 6, 18, 14, 0), /* RTL9310_TBL_2 */
TBL_DESC(0x0200, 0x0204, 9, 15, 12, 0), /* RTL9310_TBL_3 */
TBL_DESC(0x20dc, 0x20e0, 29, 7, 6, 0), /* RTL9310_TBL_4 */
TBL_DESC(0x7e1c, 0x7e20, 53, 8, 6, 0), /* RTL9310_TBL_5 */
};
void rtl_table_init(void)
{
for (int i = 0; i < RTL_TBL_END; i++)
mutex_init(&rtl838x_tbl_regs[i].lock);
}
/* Request access to table t in table access register r
* Returns a handle to a lock for that table
*/
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
{
if (r >= RTL_TBL_END)
return NULL;
if (t >= BIT(rtl838x_tbl_regs[r].c_bit - rtl838x_tbl_regs[r].t_bit))
return NULL;
mutex_lock(&rtl838x_tbl_regs[r].lock);
rtl838x_tbl_regs[r].tbl = t;
return &rtl838x_tbl_regs[r];
}
/* Release a table r, unlock the corresponding lock */
void rtl_table_release(struct table_reg *r)
{
if (!r)
return;
/* pr_info("Unlocking %08x\n", (u32)r); */
mutex_unlock(&r->lock);
/* pr_info("Unlock done\n"); */
}
static int rtl_table_exec(struct table_reg *r, bool is_write, int idx)
{
int ret = 0;
u32 cmd, val;
/* Read/write bit has inverted meaning on RTL838x */
if (r->rmode)
cmd = is_write ? 0 : BIT(r->c_bit);
else
cmd = is_write ? BIT(r->c_bit) : 0;
cmd |= BIT(r->c_bit + 1); /* Execute bit */
cmd |= r->tbl << r->t_bit; /* Table type */
cmd |= idx & (BIT(r->t_bit) - 1); /* Index */
sw_w32(cmd, r->addr);
ret = readx_poll_timeout(sw_r32, r->addr, val,
!(val & BIT(r->c_bit + 1)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/* Reads table index idx into the data registers of the table */
int rtl_table_read(struct table_reg *r, int idx)
{
return rtl_table_exec(r, false, idx);
}
/* Writes the content of the table data registers into the table at index idx */
int rtl_table_write(struct table_reg *r, int idx)
{
return rtl_table_exec(r, true, idx);
}
/* Returns the address of the ith data register of table register r
* the address is relative to the beginning of the Switch-IO block at 0xbb000000
*/
inline u16 rtl_table_data(struct table_reg *r, int i)
{
if (i >= r->max_data)
i = r->max_data - 1;
return r->data + i * 4;
}
inline u32 rtl_table_data_r(struct table_reg *r, int i)
{
return sw_r32(rtl_table_data(r, i));
}
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i)
{
sw_w32(v, rtl_table_data(r, i));
}
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _OTTO_TABLE_H
#define _OTTO_TABLE_H
#include <linux/mutex.h>
#include <linux/types.h>
/* API for switch table access */
struct table_reg {
u16 addr;
u16 data;
u8 max_data;
u8 c_bit;
u8 t_bit;
u8 rmode;
u8 tbl;
struct mutex lock;
};
#define TBL_DESC(_addr, _data, _max_data, _c_bit, _t_bit, _rmode) \
{ .addr = _addr, .data = _data, .max_data = _max_data, .c_bit = _c_bit, \
.t_bit = _t_bit, .rmode = _rmode \
}
typedef enum {
RTL8380_TBL_L2 = 0,
RTL8380_TBL_0,
RTL8380_TBL_1,
RTL8390_TBL_L2,
RTL8390_TBL_0,
RTL8390_TBL_1,
RTL8390_TBL_2,
RTL9300_TBL_L2,
RTL9300_TBL_0,
RTL9300_TBL_1,
RTL9300_TBL_2,
RTL9300_TBL_HSB,
RTL9300_TBL_HSA,
RTL9310_TBL_0,
RTL9310_TBL_1,
RTL9310_TBL_2,
RTL9310_TBL_3,
RTL9310_TBL_4,
RTL9310_TBL_5,
RTL_TBL_END
} rtl838x_tbl_reg_t;
void rtl_table_init(void);
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t);
void rtl_table_release(struct table_reg *r);
int rtl_table_read(struct table_reg *r, int idx);
int rtl_table_write(struct table_reg *r, int idx);
inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
#endif /* _OTTO_TABLE_H */