[openwrt/openwrt] realtek: sync latest version
LEDE Commits
lede-commits at lists.infradead.org
Mon Dec 28 13:35:59 EST 2020
blogic pushed a commit to openwrt/openwrt.git, branch realtek:
https://git.openwrt.org/4af1445ab671b06d7f3b25e4e0b6536857099631
commit 4af1445ab671b06d7f3b25e4e0b6536857099631
Author: Birger Koblitz <git at birger-koblitz.de>
AuthorDate: Thu Nov 26 08:41:42 2020 +0100
realtek: sync latest version
Signed-off-by: Birger Koblitz <git at birger-koblitz.de>
---
target/linux/realtek/config-5.4 | 1 -
.../mips/include/asm/mach-rtl838x/mach-rtl83xx.h | 4 +
.../realtek/files-5.4/arch/mips/rtl838x/prom.c | 11 +
.../files-5.4/drivers/net/dsa/rtl83xx/Makefile | 2 +-
.../files-5.4/drivers/net/dsa/rtl83xx/common.c | 163 +++++-
.../files-5.4/drivers/net/dsa/rtl83xx/debugfs.c | 403 +++++++++++++-
.../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 4 +-
.../files-5.4/drivers/net/dsa/rtl83xx/qos.c | 576 +++++++++++++++++++++
.../files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c | 8 +
.../files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h | 81 ++-
.../files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c | 16 +-
.../files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h | 3 +-
.../files-5.4/drivers/net/dsa/rtl83xx/storm.c | 64 ---
.../files-5.4/drivers/net/ethernet/rtl838x_eth.c | 198 +++++--
...t-dsa-add-rtl838x-support-for-tag-trailer.patch | 15 +-
15 files changed, 1395 insertions(+), 154 deletions(-)
diff --git a/target/linux/realtek/config-5.4 b/target/linux/realtek/config-5.4
index 170bcb7632..8171f66529 100644
--- a/target/linux/realtek/config-5.4
+++ b/target/linux/realtek/config-5.4
@@ -167,7 +167,6 @@ CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_RTL838X=y
CONFIG_SRCU=y
-CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
diff --git a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h
index b7d2a6f037..b4d4efcb16 100644
--- a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h
+++ b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h
@@ -373,6 +373,9 @@
#define RTL838X_PLL_CML_CTRL (0x0FF8)
#define RTL838X_STRAP_DBG (0x100C)
+#define RTL838X_CPU_PORT 28
+#define RTL839X_CPU_PORT 52
+
/*
* Reset
*/
@@ -446,6 +449,7 @@ struct rtl83xx_soc_info {
unsigned char *compatible;
volatile void *sw_base;
volatile void *icu_base;
+ int cpu_port;
};
/* rtl83xx-related functions used across subsystems */
diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c
index 5278afae03..27da109b13 100644
--- a/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c
+++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c
@@ -119,6 +119,17 @@ void __init prom_init(void)
soc_info.name = "DEFAULT";
soc_info.family = 0;
}
+
pr_info("SoC Type: %s\n", get_system_type());
+
+ switch(soc_info.family) {
+ case RTL8380_FAMILY_ID:
+ soc_info.cpu_port = RTL838X_CPU_PORT;
+ break;
+ case RTL8390_FAMILY_ID:
+ soc_info.cpu_port = RTL839X_CPU_PORT;
+ break;
+ }
+
prom_init_cmdline();
}
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile
index 52cc151a56..eeab299fcb 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_NET_DSA_RTL83XX) += common.o dsa.o \
- rtl838x.o rtl839x.o storm.o debugfs.o
+ rtl838x.o rtl839x.o debugfs.o qos.o
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c
index 1b57ddc92c..219117b399 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c
@@ -36,8 +36,8 @@ static void dump_fdb(struct rtl838x_switch_priv *priv)
mutex_unlock(&priv->reg_mutex);
}
-// TODO: unused
-static void rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
+// TODO: used only in debugfs
+void rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
{
u32 cmd, msti = 0;
u32 port_state[4];
@@ -278,12 +278,152 @@ static int __init rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv)
return t;
}
+/* Caller must hold priv->reg_mutex */
+int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port)
+{
+ struct rtl838x_switch_priv *priv = ds->priv;
+ int i;
+
+ pr_info("%s: Adding port %d to LA-group %d\n", __func__, port, group);
+ if (group >= priv->n_lags) {
+ pr_err("Link Agrregation group too large.\n");
+ return -EINVAL;
+ }
+
+ if (port >= priv->cpu_port) {
+ pr_err("Invalid port number.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < priv->n_lags; i++) {
+ if (priv->lags_port_members[i] & BIT_ULL(i))
+ break;
+ }
+ if (i != priv->n_lags) {
+ pr_err("%s: Port already member of LAG: %d\n", __func__, i);
+ return -ENOSPC;
+ }
+
+ priv->r->mask_port_reg_be(0, BIT_ULL(port), priv->r->trk_mbr_ctr(group));
+ priv->lags_port_members[group] |= BIT_ULL(port);
+
+ pr_info("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]);
+ return 0;
+}
+
+/* Caller must hold priv->reg_mutex */
+int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
+{
+ struct rtl838x_switch_priv *priv = ds->priv;
+
+ pr_info("%s: Removing port %d from LA-group %d\n", __func__, port, group);
+
+ if (group >= priv->n_lags) {
+ pr_err("Link Agrregation group too large.\n");
+ return -EINVAL;
+ }
+
+ if (port >= priv->cpu_port) {
+ pr_err("Invalid port number.\n");
+ return -EINVAL;
+ }
+
+
+ if (!(priv->lags_port_members[group] & BIT_ULL(port))) {
+ pr_err("%s: Port not member of LAG: %d\n", __func__, group
+ );
+ return -ENOSPC;
+ }
+
+ priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group));
+ priv->lags_port_members[group] &= ~BIT_ULL(port);
+
+ pr_info("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]);
+ return 0;
+}
+
+static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv,
+ struct net_device *ndev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct net_device *upper = info->upper_dev;
+ int i, j, err;
+
+ if (!netif_is_lag_master(upper))
+ return 0;
+
+ mutex_lock(&priv->reg_mutex);
+
+ for (i = 0; i < priv->n_lags; i++) {
+ if ((!priv->lag_devs[i]) || (priv->lag_devs[i] == upper))
+ break;
+ }
+ for (j = 0; j < priv->cpu_port; j++) {
+ if (priv->ports[j].dp->slave == ndev)
+ break;
+ }
+ if (j >= priv->cpu_port) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (info->linking) {
+ if (!priv->lag_devs[i])
+ priv->lag_devs[i] = upper;
+ err = rtl83xx_lag_add(priv->ds, i, priv->ports[j].dp->index);
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
+ } else {
+ if (!priv->lag_devs[i])
+ err = -EINVAL;
+ err = rtl83xx_lag_del(priv->ds, i, priv->ports[j].dp->index);
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
+ if (!priv->lags_port_members[i])
+ priv->lag_devs[i] = NULL;
+ }
+
+out:
+ mutex_unlock(&priv->reg_mutex);
+ return 0;
+}
+
+static int rtl83xx_netdevice_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct rtl838x_switch_priv *priv;
+ int err;
+
+ pr_debug("In: %s, event: %lu\n", __func__, event);
+
+ if ((event != NETDEV_CHANGEUPPER) && (event != NETDEV_CHANGELOWERSTATE))
+ return NOTIFY_DONE;
+
+ priv = container_of(this, struct rtl838x_switch_priv, nb);
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ err = rtl83xx_handle_changeupper(priv, ndev, ptr);
+ break;
+ }
+
+ if (err)
+ return err;
+
+ return NOTIFY_DONE;
+}
+
static int __init rtl83xx_sw_probe(struct platform_device *pdev)
{
int err = 0, i;
struct rtl838x_switch_priv *priv;
struct device *dev = &pdev->dev;
u64 irq_mask;
+ u64 bpdu_mask;
pr_debug("Probing RTL838X switch device\n");
if (!pdev->dev.of_node) {
@@ -361,15 +501,26 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
rtl83xx_get_l2aging(priv);
-/*
- if (priv->family_id == RTL8380_FAMILY_ID)
- rtl83xx_storm_control_init(priv);
-*/
+ rtl83xx_setup_qos(priv);
/* Clear all destination ports for mirror groups */
for (i = 0; i < 4; i++)
priv->mirror_group_ports[i] = -1;
+ priv->nb.notifier_call = rtl83xx_netdevice_event;
+ if (register_netdevice_notifier(&priv->nb)) {
+ priv->nb.notifier_call = NULL;
+ dev_err(dev, "Failed to register LAG netdev notifier\n");
+ }
+
+ // Flood BPDUs to all ports including cpu-port
+ bpdu_mask = soc_info.family == RTL8380_FAMILY_ID ? 0x1FFFFFFF : 0x1FFFFFFFFFFFFF;
+ priv->r->set_port_reg_be(bpdu_mask, priv->r->rma_bpdu_fld_pmask);
+
+ // TRAP 802.1X frames (EAPOL) to the CPU-Port, bypass STP and VLANs
+ sw_w32(7, priv->r->spcl_trap_eapol_ctrl);
+
+
rtl838x_dbgfs_init(priv);
return err;
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c
index af24e8fa42..8634cfbb80 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c
@@ -1,12 +1,219 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/debugfs.h>
+#include <linux/kernel.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
-#include "rtl838x.h"
+#include "rtl83xx.h"
#define RTL838X_DRIVER_NAME "rtl838x"
+#define RTL8380_LED_GLB_CTRL (0xA000)
+#define RTL8380_LED_MODE_SEL (0x1004)
+#define RTL8380_LED_MODE_CTRL (0xA004)
+#define RTL8380_LED_P_EN_CTRL (0xA008)
+#define RTL8380_LED_SW_CTRL (0xA00C)
+#define RTL8380_LED0_SW_P_EN_CTRL (0xA010)
+#define RTL8380_LED1_SW_P_EN_CTRL (0xA014)
+#define RTL8380_LED2_SW_P_EN_CTRL (0xA018)
+#define RTL8380_LED_SW_P_CTRL(p) (0xA01C + (((p) << 2)))
+
+#define RTL8390_LED_GLB_CTRL (0x00E4)
+#define RTL8390_LED_SET_2_3_CTRL (0x00E8)
+#define RTL8390_LED_SET_0_1_CTRL (0x00EC)
+#define RTL8390_LED_COPR_SET_SEL_CTRL(p) (0x00F0 + (((p >> 4) << 2)))
+#define RTL8390_LED_FIB_SET_SEL_CTRL(p) (0x0100 + (((p >> 4) << 2)))
+#define RTL8390_LED_COPR_PMASK_CTRL(p) (0x0110 + (((p >> 5) << 2)))
+#define RTL8390_LED_FIB_PMASK_CTRL(p) (0x00118 + (((p >> 5) << 2)))
+#define RTL8390_LED_COMBO_CTRL(p) (0x0120 + (((p >> 5) << 2)))
+#define RTL8390_LED_SW_CTRL (0x0128)
+#define RTL8390_LED_SW_P_EN_CTRL(p) (0x012C + (((p / 10) << 2)))
+#define RTL8390_LED_SW_P_CTRL(p) (0x0144 + (((p) << 2)))
+
+#define RTL838X_MIR_QID_CTRL(grp) (0xAD44 + (((grp) << 2)))
+#define RTL838X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2)))
+#define RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(grp) (0xAA70 + (((grp) << 2)))
+#define RTL838X_MIR_RSPAN_TX_CTRL (0xA350)
+#define RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL (0xAA80)
+#define RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL (0xAA84)
+#define RTL839X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2)))
+#define RTL839X_MIR_RSPAN_TX_CTRL (0x69b0)
+#define RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL (0x2550)
+#define RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL (0x2554)
+#define RTL839X_MIR_SAMPLE_RATE_CTRL (0x2558)
+
+int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port);
+void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
+void rtl83xx_fast_age(struct dsa_switch *ds, int port);
+u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
+u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
+int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
+int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
+
+static ssize_t rtl838x_common_read(char __user *buffer, size_t count,
+ loff_t *ppos, unsigned int value)
+{
+ char *buf;
+ ssize_t len;
+
+ if (*ppos != 0)
+ return 0;
+
+ buf = kasprintf(GFP_KERNEL, "0x%08x\n", value);
+ if (!buf)
+ return -ENOMEM;
+
+ if (count < strlen(buf)) {
+ kfree(buf);
+ return -ENOSPC;
+ }
+
+ len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+ kfree(buf);
+
+ return len;
+}
+
+static ssize_t rtl838x_common_write(const char __user *buffer, size_t count,
+ loff_t *ppos, unsigned int *value)
+{
+ char b[32];
+ ssize_t len;
+ int ret;
+
+ if (*ppos != 0)
+ return -EINVAL;
+
+ if (count >= sizeof(b))
+ return -ENOSPC;
+
+ len = simple_write_to_buffer(b, sizeof(b) - 1, ppos,
+ buffer, count);
+ if (len < 0)
+ return len;
+
+ b[len] = '\0';
+ ret = kstrtouint(b, 16, value);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static ssize_t stp_state_read(struct file *filp, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ struct dsa_switch *ds = p->dp->ds;
+ int value = rtl83xx_port_get_stp_state(ds->priv, p->dp->index);
+
+ if (value < 0)
+ return -EINVAL;
+
+ return rtl838x_common_read(buffer, count, ppos, (u32)value);
+}
+
+static ssize_t stp_state_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ u32 value;
+ size_t res = rtl838x_common_write(buffer, count, ppos, &value);
+ if (res < 0)
+ return res;
+
+ rtl83xx_port_stp_state_set(p->dp->ds, p->dp->index, (u8)value);
+
+ return res;
+}
+
+static const struct file_operations stp_state_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = stp_state_read,
+ .write = stp_state_write,
+};
+
+static ssize_t age_out_read(struct file *filp, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ struct dsa_switch *ds = p->dp->ds;
+ struct rtl838x_switch_priv *priv = ds->priv;
+ int value = sw_r32(priv->r->l2_port_aging_out);
+
+ if (value < 0)
+ return -EINVAL;
+
+ return rtl838x_common_read(buffer, count, ppos, (u32)value);
+}
+
+static ssize_t age_out_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ u32 value;
+ size_t res = rtl838x_common_write(buffer, count, ppos, &value);
+ if (res < 0)
+ return res;
+
+ rtl83xx_fast_age(p->dp->ds, p->dp->index);
+
+ return res;
+}
+
+static const struct file_operations age_out_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = age_out_read,
+ .write = age_out_write,
+};
+
+static ssize_t port_egress_rate_read(struct file *filp, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ struct dsa_switch *ds = p->dp->ds;
+ struct rtl838x_switch_priv *priv = ds->priv;
+ int value;
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ value = rtl838x_get_egress_rate(priv, p->dp->index);
+ else
+ value = rtl839x_get_egress_rate(priv, p->dp->index);
+
+ if (value < 0)
+ return -EINVAL;
+
+ return rtl838x_common_read(buffer, count, ppos, (u32)value);
+}
+
+static ssize_t port_egress_rate_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct rtl838x_port *p = filp->private_data;
+ struct dsa_switch *ds = p->dp->ds;
+ struct rtl838x_switch_priv *priv = ds->priv;
+ u32 value;
+ size_t res = rtl838x_common_write(buffer, count, ppos, &value);
+ if (res < 0)
+ return res;
+
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ rtl838x_set_egress_rate(priv, p->dp->index, value);
+ else
+ rtl839x_set_egress_rate(priv, p->dp->index, value);
+
+ return res;
+}
+
+static const struct file_operations port_egress_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = port_egress_rate_read,
+ .write = port_egress_rate_write,
+};
+
+
static const struct debugfs_reg32 port_ctrl_regs[] = {
{ .name = "port_isolation", .offset = RTL838X_PORT_ISO_CTRL(0), },
{ .name = "mac_force_mode", .offset = RTL838X_MAC_FORCE_MODE_CTRL, },
@@ -27,20 +234,33 @@ static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_
port_dir = debugfs_create_dir(priv->ports[port].dp->name, parent);
- debugfs_create_x32("rate_uc", 0644, port_dir,
- (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_UC(port)));
+ if (priv->family_id == RTL8380_FAMILY_ID) {
+ debugfs_create_x32("storm_rate_uc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_UC(port)));
+
+ debugfs_create_x32("storm_rate_mc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_MC(port)));
- debugfs_create_x32("rate_mc", 0644, port_dir,
- (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port)));
+ debugfs_create_x32("storm_rate_bc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port)));
- debugfs_create_x32("rate_bc", 0644, port_dir,
- (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port)));
+ debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_PORT_TAG_STS_CTRL(port)));
+ } else {
+ debugfs_create_x32("storm_rate_uc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_UC_0(port)));
- debugfs_create_u32("id", 0444, port_dir, &priv->ports[port].dp->index);
+ debugfs_create_x32("storm_rate_mc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_MC_0(port)));
+ debugfs_create_x32("storm_rate_bc", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_BC_0(port)));
- debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir,
- (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_PORT_TAG_STS_CTRL(port)));
+ debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_VLAN_PORT_TAG_STS_CTRL(port)));
+ }
+
+ debugfs_create_u32("id", 0444, port_dir, (u32 *)&priv->ports[port].dp->index);
port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL);
if (!port_ctrl_regset)
@@ -48,9 +268,88 @@ static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_
port_ctrl_regset->regs = port_ctrl_regs;
port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs);
- port_ctrl_regset->base = RTL838X_SW_BASE + (port << 2);
+ port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (port << 2));
debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset);
+ debugfs_create_file("stp_state", 0600, port_dir, &priv->ports[port], &stp_state_fops);
+ debugfs_create_file("age_out", 0600, port_dir, &priv->ports[port], &age_out_fops);
+ debugfs_create_file("port_egress_rate", 0600, port_dir, &priv->ports[port],
+ &port_egress_fops);
+ return 0;
+}
+
+static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv *priv)
+{
+ struct dentry *led_dir;
+ int p;
+ char led_sw_p_ctrl_name[20];
+ char port_led_name[20];
+
+ led_dir = debugfs_create_dir("led", parent);
+
+ if (priv->family_id == RTL8380_FAMILY_ID) {
+ debugfs_create_x32("led_glb_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_GLB_CTRL));
+ debugfs_create_x32("led_mode_sel", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_MODE_SEL));
+ debugfs_create_x32("led_mode_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_MODE_CTRL));
+ debugfs_create_x32("led_p_en_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_P_EN_CTRL));
+ debugfs_create_x32("led_sw_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_SW_CTRL));
+ debugfs_create_x32("led0_sw_p_en_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED0_SW_P_EN_CTRL));
+ debugfs_create_x32("led1_sw_p_en_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED1_SW_P_EN_CTRL));
+ debugfs_create_x32("led2_sw_p_en_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED2_SW_P_EN_CTRL));
+ for (p = 0; p < 28; p++) {
+ snprintf(led_sw_p_ctrl_name, sizeof(led_sw_p_ctrl_name),
+ "led_sw_p_ctrl.%02d", p);
+ debugfs_create_x32(led_sw_p_ctrl_name, 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8380_LED_SW_P_CTRL(p)));
+ }
+ } else if (priv->family_id == RTL8390_FAMILY_ID) {
+ debugfs_create_x32("led_glb_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_GLB_CTRL));
+ debugfs_create_x32("led_set_2_3", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_2_3_CTRL));
+ debugfs_create_x32("led_set_0_1", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_0_1_CTRL));
+ for (p = 0; p < 4; p++) {
+ snprintf(port_led_name, sizeof(port_led_name), "led_copr_set_sel.%1d", p);
+ debugfs_create_x32(port_led_name, 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_SET_SEL_CTRL(p << 4)));
+ snprintf(port_led_name, sizeof(port_led_name), "led_fib_set_sel.%1d", p);
+ debugfs_create_x32(port_led_name, 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_SET_SEL_CTRL(p << 4)));
+ }
+ debugfs_create_x32("led_copr_pmask_ctrl_0", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(0)));
+ debugfs_create_x32("led_copr_pmask_ctrl_1", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(32)));
+ debugfs_create_x32("led_fib_pmask_ctrl_0", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(0)));
+ debugfs_create_x32("led_fib_pmask_ctrl_1", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(32)));
+ debugfs_create_x32("led_combo_ctrl_0", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(0)));
+ debugfs_create_x32("led_combo_ctrl_1", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(32)));
+ debugfs_create_x32("led_sw_ctrl", 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_CTRL));
+ for (p = 0; p < 5; p++) {
+ snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_en_ctrl.%1d", p);
+ debugfs_create_x32(port_led_name, 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_EN_CTRL(p * 10)));
+ }
+ for (p = 0; p < 28; p++) {
+ snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_ctrl.%02d", p);
+ debugfs_create_x32(port_led_name, 0644, led_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_CTRL(p)));
+ }
+ }
return 0;
}
@@ -58,9 +357,13 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
{
struct dentry *rtl838x_dir;
struct dentry *port_dir;
+ struct dentry *mirror_dir;
struct debugfs_regset32 *port_ctrl_regset;
int ret, i;
+ char lag_name[10];
+ char mirror_name[10];
+ pr_info("%s called\n", __func__);
rtl838x_dir = debugfs_lookup(RTL838X_DRIVER_NAME, NULL);
if (!rtl838x_dir)
rtl838x_dir = debugfs_create_dir(RTL838X_DRIVER_NAME, NULL);
@@ -73,7 +376,6 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
/* Create one directory per port */
for (i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
- pr_debug("debugfs, port %d\n", i);
ret = rtl838x_dbgfs_port_init(rtl838x_dir, priv, i);
if (ret)
goto err;
@@ -81,7 +383,8 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
}
/* Create directory for CPU-port */
- port_dir = debugfs_create_dir("cpu_port", rtl838x_dir); port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL);
+ port_dir = debugfs_create_dir("cpu_port", rtl838x_dir);
+ port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL);
if (!port_ctrl_regset) {
ret = -ENOMEM;
goto err;
@@ -89,10 +392,82 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
port_ctrl_regset->regs = port_ctrl_regs;
port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs);
- port_ctrl_regset->base = RTL838X_SW_BASE + (priv->cpu_port << 2);
+ port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (priv->cpu_port << 2));
debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset);
debugfs_create_u8("id", 0444, port_dir, &priv->cpu_port);
+ /* Create entries for LAGs */
+ for (i = 0; i < priv->n_lags; i++) {
+ snprintf(lag_name, sizeof(lag_name), "lag.%02d", i);
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ debugfs_create_x32(lag_name, 0644, rtl838x_dir,
+ (u32 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i)));
+ else
+ debugfs_create_x64(lag_name, 0644, rtl838x_dir,
+ (u64 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i)));
+ }
+
+ /* Create directories for mirror groups */
+ for (i = 0; i < 4; i++) {
+ snprintf(mirror_name, sizeof(mirror_name), "mirror.%1d", i);
+ mirror_dir = debugfs_create_dir(mirror_name, rtl838x_dir);
+ if (priv->family_id == RTL8380_FAMILY_ID) {
+ debugfs_create_x32("ctrl", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_CTRL(i)));
+ debugfs_create_x32("ingress_pm", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + priv->r->mir_spm(i)));
+ debugfs_create_x32("egress_pm", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + priv->r->mir_dpm(i)));
+ debugfs_create_x32("qid", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_QID_CTRL(i)));
+ debugfs_create_x32("rspan_vlan", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL(i)));
+ debugfs_create_x32("rspan_vlan_mac", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(i)));
+ debugfs_create_x32("rspan_tx", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_CTRL));
+ debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL));
+ debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL));
+ } else {
+ debugfs_create_x32("ctrl", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_CTRL(i)));
+ debugfs_create_x64("ingress_pm", 0644, mirror_dir,
+ (u64 *)(RTL838X_SW_BASE + priv->r->mir_spm(i)));
+ debugfs_create_x64("egress_pm", 0644, mirror_dir,
+ (u64 *)(RTL838X_SW_BASE + priv->r->mir_dpm(i)));
+ debugfs_create_x32("rspan_vlan", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_VLAN_CTRL(i)));
+ debugfs_create_x32("rspan_tx", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_CTRL));
+ debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL));
+ debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL));
+ debugfs_create_x64("sample_rate", 0644, mirror_dir,
+ (u64 *)(RTL838X_SW_BASE + RTL839X_MIR_SAMPLE_RATE_CTRL));
+ }
+ }
+
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ debugfs_create_x32("bpdu_flood_mask", 0644, rtl838x_dir,
+ (u32 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask));
+ else
+ debugfs_create_x64("bpdu_flood_mask", 0644, rtl838x_dir,
+ (u64 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask));
+
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_CTRL));
+ else
+ debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir,
+ (u32 *)(RTL838X_SW_BASE + RTL839X_VLAN_CTRL));
+
+ ret = rtl838x_dbgfs_leds(rtl838x_dir, priv);
+ if (ret)
+ goto err;
+
return;
err:
rtl838x_dbgfs_cleanup(priv);
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c
index a0717e1d9a..77805e35c1 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c
@@ -636,7 +636,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port,
mutex_unlock(&priv->reg_mutex);
}
-static void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port,
+void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port,
u8 state)
{
u32 cmd, msti = 0;
@@ -715,7 +715,7 @@ static void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port,
mutex_unlock(&priv->reg_mutex);
}
-static void rtl83xx_fast_age(struct dsa_switch *ds, int port)
+void rtl83xx_fast_age(struct dsa_switch *ds, int port)
{
struct rtl838x_switch_priv *priv = ds->priv;
int s = priv->family_id == RTL8390_FAMILY_ID ? 2 : 0;
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c
new file mode 100644
index 0000000000..2fc8d37f3e
--- /dev/null
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <net/dsa.h>
+#include <linux/delay.h>
+
+#include <asm/mach-rtl838x/mach-rtl83xx.h>
+#include "rtl83xx.h"
+
+static struct rtl838x_switch_priv *switch_priv;
+extern struct rtl83xx_soc_info soc_info;
+
+enum scheduler_type {
+ WEIGHTED_FAIR_QUEUE = 0,
+ WEIGHTED_ROUND_ROBIN,
+};
+
+int max_available_queue[] = {0, 1, 2, 3, 4, 5, 6, 7};
+int default_queue_weights[] = {1, 1, 1, 1, 1, 1, 1, 1};
+int dot1p_priority_remapping[] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+static void rtl839x_read_scheduling_table(int port)
+{
+ u32 cmd = 1 << 9 /* Execute cmd */
+ | 0 << 8 /* Read */
+ | 0 << 6 /* Table type 0b00 */
+ | (port & 0x3f);
+ rtl839x_exec_tbl2_cmd(cmd);
+}
+
+static void rtl839x_write_scheduling_table(int port)
+{
+ u32 cmd = 1 << 9 /* Execute cmd */
+ | 1 << 8 /* Write */
+ | 0 << 6 /* Table type 0b00 */
+ | (port & 0x3f);
+ rtl839x_exec_tbl2_cmd(cmd);
+}
+
+static void rtl839x_read_out_q_table(int port)
+{
+ u32 cmd = 1 << 9 /* Execute cmd */
+ | 0 << 8 /* Read */
+ | 2 << 6 /* Table type 0b10 */
+ | (port & 0x3f);
+ rtl839x_exec_tbl2_cmd(cmd);
+}
+
+static void rtl838x_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable)
+{
+ // Enable Storm control for that port for UC, MC, and BC
+ if (enable)
+ sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port));
+ else
+ sw_w32(0x0, RTL838X_STORM_CTRL_LB_CTRL(port));
+}
+
+u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
+{
+ u32 rate;
+
+ if (port > priv->cpu_port)
+ return 0;
+ rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)) & 0x3fff;
+ return rate;
+}
+
+/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
+int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate)
+{
+ u32 old_rate;
+
+ if (port > priv->cpu_port)
+ return -1;
+
+ old_rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port));
+ sw_w32(rate, RTL838X_SCHED_P_EGR_RATE_CTRL(port));
+
+ return old_rate;
+}
+
+/* Set the rate limit for a particular queue in Bits/s
+ * units of the rate is 16Kbps
+ */
+void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
+ int queue, u32 rate)
+{
+ if (port > priv->cpu_port)
+ return;
+ if (queue > 7)
+ return;
+ sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue));
+}
+
+static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv)
+{
+ int i;
+
+ pr_info("Enabling Storm control\n");
+ // TICK_PERIOD_PPS
+ if (priv->id == 0x8380)
+ sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0);
+
+ // Set burst rate
+ sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); // UC
+ sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); // MC and BC
+
+ // Set burst Packets per Second to 32
+ sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); // UC
+ sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); // MC and BC
+
+ // Include IFG in storm control, rate based on bytes/s (0 = packets)
+ sw_w32_mask(0, 1 << 6 | 1 << 5, RTL838X_STORM_CTRL);
+ // Bandwidth control includes preamble and IFG (10 Bytes)
+ sw_w32_mask(0, 1, RTL838X_SCHED_CTRL);
+
+ // On SoCs except RTL8382M, set burst size of port egress
+ if (priv->id != 0x8382)
+ sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR);
+
+ /* Enable storm control on all ports with a PHY and limit rates,
+ * for UC and MC for both known and unknown addresses */
+ for (i = 0; i < priv->cpu_port; i++) {
+ if (priv->ports[i].phy) {
+ sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i));
+ sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i));
+ sw_w32(0x8000, RTL838X_STORM_CTRL_PORT_BC(i));
+ rtl838x_storm_enable(priv, i, true);
+ }
+ }
+
+ // Attack prevention, enable all attack prevention measures
+ //sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL);
+ /* Attack prevention, drop (bit = 0) problematic packets on all ports.
+ * Setting bit = 1 means: trap to CPU
+ */
+ //sw_w32(0, RTL838X_ATK_PRVNT_ACT);
+ // Enable attack prevention on all ports
+ //sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN);
+}
+
+/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
+u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
+{
+ u32 rate;
+
+ pr_debug("%s: Getting egress rate on port %d to %d\n", __func__, port, rate);
+ if (port >= priv->cpu_port)
+ return 0;
+
+ mutex_lock(&priv->reg_mutex);
+
+ rtl839x_read_scheduling_table(port);
+
+ rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7));
+ rate <<= 12;
+ rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20;
+
+ mutex_unlock(&priv->reg_mutex);
+
+ return rate;
+}
+
+/* Sets the rate limit, 10MBit/s is equal to a rate value of 625, returns previous rate */
+int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate)
+{
+ u32 old_rate;
+
+ pr_debug("%s: Setting egress rate on port %d to %d\n", __func__, port, rate);
+ if (port >= priv->cpu_port)
+ return -1;
+
+ mutex_lock(&priv->reg_mutex);
+
+ rtl839x_read_scheduling_table(port);
+
+ old_rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7)) & 0xff;
+ old_rate <<= 12;
+ old_rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20;
+ sw_w32_mask(0xff, (rate >> 12) & 0xff, RTL839X_TBL_ACCESS_DATA_2(7));
+ sw_w32_mask(0xfff << 20, rate << 20, RTL839X_TBL_ACCESS_DATA_2(8));
+
+ rtl839x_write_scheduling_table(port);
+
+ mutex_unlock(&priv->reg_mutex);
+
+ return old_rate;
+}
+
+/* Set the rate limit for a particular queue in Bits/s
+ * units of the rate is 16Kbps
+ */
+void rtl839x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
+ int queue, u32 rate)
+{
+ int lsb = 128 + queue * 20;
+ int low_byte = 8 - (lsb >> 5);
+ int start_bit = lsb - (low_byte << 5);
+ u32 high_mask = 0xfffff >> (32 - start_bit);
+
+ pr_debug("%s: Setting egress rate on port %d, queue %d to %d\n",
+ __func__, port, queue, rate);
+ if (port >= priv->cpu_port)
+ return;
+ if (queue > 7)
+ return;
+
+ mutex_lock(&priv->reg_mutex);
+
+ rtl839x_read_scheduling_table(port);
+
+ sw_w32_mask(0xfffff << start_bit, (rate & 0xfffff) << start_bit,
+ RTL839X_TBL_ACCESS_DATA_2(low_byte));
+ if (high_mask)
+ sw_w32_mask(high_mask, (rate & 0xfffff) >> (32- start_bit),
+ RTL839X_TBL_ACCESS_DATA_2(low_byte - 1));
+
+ rtl839x_write_scheduling_table(port);
+
+ mutex_unlock(&priv->reg_mutex);
+}
+
+static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
+{
+ int p, q;
+
+ pr_info("%s: enabling rate control\n", __func__);
+ /* Tick length and token size settings for SoC with 250MHz,
+ * RTL8350 family would use 50MHz
+ */
+ // Set the special tick period
+ sw_w32(976563, RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL);
+ // Ingress tick period and token length 10G
+ sw_w32(18 << 11 | 151, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0);
+ // Ingress tick period and token length 1G
+ sw_w32(245 << 11 | 129, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1);
+ // Egress tick period 10G, bytes/token 10G and tick period 1G, bytes/token 1G
+ sw_w32(18 << 24 | 151 << 16 | 185 << 8 | 97, RTL839X_SCHED_LB_TICK_TKN_CTRL);
+ // Set the tick period of the CPU and the Token Len
+ sw_w32(3815 << 8 | 1, RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL);
+
+ // Set the Weighted Fair Queueing burst size
+ sw_w32_mask(0xffff, 4500, RTL839X_SCHED_LB_THR);
+
+ // Storm-rate calculation is based on bytes/sec (bit 5), include IFG (bit 6)
+ sw_w32_mask(0, 1 << 5 | 1 << 6, RTL839X_STORM_CTRL);
+
+ /* Based on the rate control mode being bytes/s
+ * set tick period and token length for 10G
+ */
+ sw_w32(18 << 10 | 151, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_0);
+ /* and for 1G ports */
+ sw_w32(246 << 10 | 129, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_1);
+
+ /* Set default burst rates on all ports (the same for 1G / 10G) with a PHY
+ * for UC, MC and BC
+ * For 1G port, the minimum burst rate is 1700, maximum 65535,
+ * For 10G ports it is 2650 and 1048575 respectively */
+ for (p = 0; p < priv->cpu_port; p++) {
+ if (priv->ports[p].phy && !priv->ports[p].is10G) {
+ sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_UC_1(p));
+ sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_MC_1(p));
+ sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_BC_1(p));
+ }
+ }
+
+ /* Setup ingress/egress per-port rate control */
+ for (p = 0; p < priv->cpu_port; p++) {
+ if (!priv->ports[p].phy)
+ continue;
+
+ if (priv->ports[p].is10G)
+ rtl839x_set_egress_rate(priv, p, 625000); // 10GB/s
+ else
+ rtl839x_set_egress_rate(priv, p, 62500); // 1GB/s
+
+ // Setup queues: all RTL83XX SoCs have 8 queues, maximum rate
+ for (q = 0; q < 8; q++)
+ rtl839x_egress_rate_queue_limit(priv, p, q, 0xfffff);
+
+ if (priv->ports[p].is10G) {
+ // Set high threshold to maximum
+ sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p));
+ } else {
+ // Set high threshold to maximum
+ sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_1(p));
+ }
+ }
+
+ // Set global ingress low watermark rate
+ sw_w32(65532, RTL839X_IGR_BWCTRL_CTRL_LB_THR);
+}
+
+
+
+void rtl838x_setup_prio2queue_matrix(int *min_queues)
+{
+ int i;
+ u32 v;
+
+ pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL838X_QM_INTPRI2QID_CTRL));
+ for (i = 0; i < MAX_PRIOS; i++)
+ v |= i << (min_queues[i] * 3);
+ sw_w32(v, RTL838X_QM_INTPRI2QID_CTRL);
+}
+
+void rtl839x_setup_prio2queue_matrix(int *min_queues)
+{
+ int i, q;
+
+ pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL839X_QM_INTPRI2QID_CTRL(0)));
+ for (i = 0; i < MAX_PRIOS; i++) {
+ q = min_queues[i];
+ sw_w32(i << (q * 3), RTL839X_QM_INTPRI2QID_CTRL(q));
+ }
+}
+
+/* Sets the CPU queue depending on the internal priority of a packet */
+void rtl83xx_setup_prio2queue_cpu_matrix(int *max_queues)
+{
+ int reg = soc_info.family == RTL8380_FAMILY_ID ? RTL838X_QM_PKT2CPU_INTPRI_MAP
+ : RTL839X_QM_PKT2CPU_INTPRI_MAP;
+ int i;
+ u32 v;
+
+ pr_info("QM_PKT2CPU_INTPRI_MAP: %08x\n", sw_r32(reg));
+ for (i = 0; i < MAX_PRIOS; i++)
+ v |= max_queues[i] << (i * 3);
+ sw_w32(v, reg);
+}
+
+void rtl83xx_setup_default_prio2queue(void)
+{
+ if (soc_info.family == RTL8380_FAMILY_ID) {
+ rtl838x_setup_prio2queue_matrix(max_available_queue);
+ } else {
+ rtl839x_setup_prio2queue_matrix(max_available_queue);
+ }
+ rtl83xx_setup_prio2queue_cpu_matrix(max_available_queue);
+}
+
+/* Sets the output queue assigned to a port, the port can be the CPU-port */
+void rtl839x_set_egress_queue(int port, int queue)
+{
+ sw_w32(queue << ((port % 10) *3), RTL839X_QM_PORT_QNUM(port));
+}
+
+/* Sets the priority assigned of an ingress port, the port can be the CPU-port */
+void rtl83xx_set_ingress_priority(int port, int priority)
+{
+ if (soc_info.family == RTL8380_FAMILY_ID)
+ sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port));
+ else
+ sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port));
+
+}
+
+int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
+{
+ u32 v;
+
+ mutex_lock(&priv->reg_mutex);
+
+ rtl839x_read_scheduling_table(port);
+ v = sw_r32(RTL839X_TBL_ACCESS_DATA_2(8));
+
+ mutex_unlock(&priv->reg_mutex);
+
+ if (v & BIT(19))
+ return WEIGHTED_ROUND_ROBIN;
+ return WEIGHTED_FAIR_QUEUE;
+}
+
+void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port,
+ enum scheduler_type sched)
+{
+ enum scheduler_type t = rtl839x_get_scheduling_algorithm(priv, port);
+ u32 v, oam_state, oam_port_state;
+ u32 count;
+ int i, egress_rate;
+
+ mutex_lock(&priv->reg_mutex);
+ /* Check whether we need to empty the egress queue of that port due to Errata E0014503 */
+ if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
+ // Read Operations, Adminstatrion and Management control register
+ oam_state = sw_r32(RTL839X_OAM_CTRL);
+
+ // Get current OAM state
+ oam_port_state = sw_r32(RTL839X_OAM_PORT_ACT_CTRL(port));
+
+ // Disable OAM to block traffice
+ v = sw_r32(RTL839X_OAM_CTRL);
+ sw_w32_mask(0, 1, RTL839X_OAM_CTRL);
+ v = sw_r32(RTL839X_OAM_CTRL);
+
+ // Set to trap action OAM forward (bits 1, 2) and OAM Mux Action Drop (bit 0)
+ sw_w32(0x2, RTL839X_OAM_PORT_ACT_CTRL(port));
+
+ // Set port egress rate to unlimited
+ egress_rate = rtl839x_set_egress_rate(priv, port, 0xFFFFF);
+
+ // Wait until the egress used page count of that port is 0
+ i = 0;
+ do {
+ usleep_range(100, 200);
+ rtl839x_read_out_q_table(port);
+ count = sw_r32(RTL839X_TBL_ACCESS_DATA_2(6));
+ count >>= 20;
+ i++;
+ } while (i < 3500 && count > 0);
+ }
+
+ // Actually set the scheduling algorithm
+ rtl839x_read_scheduling_table(port);
+ sw_w32_mask(BIT(19), sched ? BIT(19) : 0, RTL839X_TBL_ACCESS_DATA_2(8));
+ rtl839x_write_scheduling_table(port);
+
+ if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
+ // Restore OAM state to control register
+ sw_w32(oam_state, RTL839X_OAM_CTRL);
+
+ // Restore trap action state
+ sw_w32(oam_port_state, RTL839X_OAM_PORT_ACT_CTRL(port));
+
+ // Restore port egress rate
+ rtl839x_set_egress_rate(priv, port, egress_rate);
+ }
+
+ mutex_unlock(&priv->reg_mutex);
+}
+
+void rtl839x_set_scheduling_queue_weights(struct rtl838x_switch_priv *priv, int port,
+ int *queue_weights)
+{
+ int i, lsb, low_byte, start_bit, high_mask;
+
+ mutex_lock(&priv->reg_mutex);
+
+ rtl839x_read_scheduling_table(port);
+
+ for (i = 0; i < 8; i++) {
+ lsb = 48 + i * 8;
+ low_byte = 8 - (lsb >> 5);
+ start_bit = lsb - (low_byte << 5);
+ high_mask = 0x3ff >> (32 - start_bit);
+ sw_w32_mask(0x3ff << start_bit, (queue_weights[i] & 0x3ff) << start_bit,
+ RTL839X_TBL_ACCESS_DATA_2(low_byte));
+ if (high_mask)
+ sw_w32_mask(high_mask, (queue_weights[i] & 0x3ff) >> (32- start_bit),
+ RTL839X_TBL_ACCESS_DATA_2(low_byte - 1));
+ }
+
+ rtl839x_write_scheduling_table(port);
+ mutex_unlock(&priv->reg_mutex);
+}
+
+void rtl838x_config_qos(void)
+{
+ int i, p;
+ u32 v;
+
+ pr_info("Setting up RTL838X QoS\n");
+ pr_info("RTL838X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL838X_PRI_SEL_TBL_CTRL(0)));
+ rtl83xx_setup_default_prio2queue();
+
+ // Enable inner (bit 12) and outer (bit 13) priority remapping from DSCP
+ sw_w32_mask(0, BIT(12) | BIT(13), RTL838X_PRI_DSCP_INVLD_CTRL0);
+
+ /* Set default weight for calculating internal priority, in prio selection group 0
+ * Port based (prio 3), Port outer-tag (4), DSCP (5), Inner Tag (6), Outer Tag (7)
+ */
+ v = 3 | (4 << 3) | (5 << 6) | (6 << 9) | (7 << 12);
+ sw_w32(v, RTL838X_PRI_SEL_TBL_CTRL(0));
+
+ // Set the inner and outer priority one-to-one to re-marked outer dot1p priority
+ v = 0;
+ for (p = 0; p < 8; p++)
+ v |= p << (3 * p);
+ sw_w32(v, RTL838X_RMK_OPRI_CTRL);
+ sw_w32(v, RTL838X_RMK_IPRI_CTRL);
+
+ v = 0;
+ for (p = 0; p < 8; p++)
+ v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
+ sw_w32(v, RTL838X_PRI_SEL_IPRI_REMAP);
+
+ // On all ports set scheduler type to WFQ
+ for (i = 0; i <= soc_info.cpu_port; i++)
+ sw_w32(0, RTL838X_SCHED_P_TYPE_CTRL(i));
+
+ // Enable egress scheduler for CPU-Port
+ sw_w32_mask(0, BIT(8), RTL838X_SCHED_LB_CTRL(soc_info.cpu_port));
+
+ // Enable egress drop allways on
+ sw_w32_mask(0, BIT(11), RTL838X_FC_P_EGR_DROP_CTRL(soc_info.cpu_port));
+
+ // Give special trap frames priority 7 (BPDUs) and routing exceptions:
+ sw_w32_mask(0, 7 << 3 | 7, RTL838X_QM_PKT2CPU_INTPRI_2);
+ // Give RMA frames priority 7:
+ sw_w32_mask(0, 7, RTL838X_QM_PKT2CPU_INTPRI_1);
+}
+
+void rtl839x_config_qos(void)
+{
+ int port, p, q;
+ u32 v;
+ struct rtl838x_switch_priv *priv = switch_priv;
+
+ pr_info("Setting up RTL839X QoS\n");
+ pr_info("RTL839X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL839X_PRI_SEL_TBL_CTRL(0)));
+ rtl83xx_setup_default_prio2queue();
+
+ for (port = 0; port < soc_info.cpu_port; port++)
+ sw_w32(7, RTL839X_QM_PORT_QNUM(port));
+
+ // CPU-port gets queue number 7
+ sw_w32(7, RTL839X_QM_PORT_QNUM(soc_info.cpu_port));
+
+ for (port = 0; port <= soc_info.cpu_port; port++) {
+ rtl83xx_set_ingress_priority(port, 0);
+ rtl839x_set_scheduling_algorithm(priv, port, WEIGHTED_FAIR_QUEUE);
+ rtl839x_set_scheduling_queue_weights(priv, port, default_queue_weights);
+ // Do re-marking based on outer tag
+ sw_w32_mask(0, BIT(port % 32), RTL839X_RMK_PORT_DEI_TAG_CTRL(port));
+ }
+
+ // Remap dot1p priorities to internal priority, for this the outer tag needs be re-marked
+ v = 0;
+ for (p = 0; p < 8; p++)
+ v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
+ sw_w32(v, RTL839X_PRI_SEL_IPRI_REMAP);
+
+ /* Configure Drop Precedence for Drop Eligible Indicator (DEI)
+ * Index 0: 0
+ * Index 1: 2
+ * Each indicator is 2 bits long
+ */
+ sw_w32(2 << 2, RTL839X_PRI_SEL_DEI2DP_REMAP);
+
+ // Re-mark DEI: 4 bit-fields of 2 bits each, field 0 is bits 0-1, ...
+ sw_w32((0x1 << 2) | (0x1 << 4), RTL839X_RMK_DEI_CTRL);
+
+ /* Set Congestion avoidance drop probability to 0 for drop precedences 0-2 (bits 24-31)
+ * low threshold (bits 0-11) to 4095 and high threshold (bits 12-23) to 4095
+ * Weighted Random Early Detection (WRED) is used
+ */
+ sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(0));
+ sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(1));
+ sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(2));
+
+ /* Set queue-based congestion avoidance properties, register fields are as
+ * for forward RTL839X_WRED_PORT_THR_CTRL
+ */
+ for (q = 0; q < 8; q++) {
+ sw_w32(255 << 24 | 78 << 12 | 68, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
+ sw_w32(255 << 24 | 74 << 12 | 64, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
+ sw_w32(255 << 24 | 70 << 12 | 60, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
+ }
+}
+
+void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv)
+{
+ switch_priv = priv;
+
+ pr_info("In %s\n", __func__);
+
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ return rtl838x_config_qos();
+ else if (priv->family_id == RTL8390_FAMILY_ID)
+ return rtl839x_config_qos();
+
+ if (priv->family_id == RTL8380_FAMILY_ID)
+ rtl838x_rate_control_init(priv);
+ else if (priv->family_id == RTL8390_FAMILY_ID)
+ rtl839x_rate_control_init(priv);
+
+}
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c
index c7b5873e99..f685b7d1c2 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c
@@ -142,6 +142,11 @@ static inline int rtl838x_mac_link_spd_sts(int p)
return RTL838X_MAC_LINK_SPD_STS(p);
}
+inline static int rtl838x_trk_mbr_ctr(int group)
+{
+ return RTL838X_TRK_MBR_CTR + (group << 2);
+}
+
static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e)
{
u64 entry;
@@ -290,6 +295,9 @@ const struct rtl838x_reg rtl838x_reg = {
.vlan_port_igr_filter = rtl838x_vlan_port_igr_filter,
.vlan_port_pb = rtl838x_vlan_port_pb,
.vlan_port_tag_sts_ctrl = rtl838x_vlan_port_tag_sts_ctrl,
+ .trk_mbr_ctr = rtl838x_trk_mbr_ctr,
+ .rma_bpdu_fld_pmask = RTL838X_RMA_BPDU_FLD_PMSK,
+ .spcl_trap_eapol_ctrl = RTL838X_SPCL_TRAP_EAPOL_CTRL,
};
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h
index 1ebb4dff72..8a4958453a 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h
@@ -55,6 +55,7 @@
#define MAPLE_SDS5_FIB_REG0r (RTL838X_SDS4_REG28 + 0x980)
/* VLAN registers */
+#define RTL838X_VLAN_CTRL (0x3A74)
#define RTL838X_VLAN_PROFILE(idx) (0x3A88 + ((idx) << 2))
#define RTL838X_VLAN_PORT_EGR_FLTR (0x3A84)
#define RTL838X_VLAN_PORT_PB_VLAN(port) (0x3C00 + ((port) << 2))
@@ -128,6 +129,8 @@
#define RTL839X_L2_PORT_NEW_SA_FWD(p) (0x3900 + (((p >> 4) << 2)))
#define RTL838X_L2_PORT_SALRN(p) (0x328c + (((p >> 4) << 2)))
#define RTL839X_L2_PORT_SALRN(p) (0x38F0 + (((p >> 4) << 2)))
+#define RTL838X_RMA_BPDU_FLD_PMSK (0x4348)
+#define RTL839X_RMA_BPDU_FLD_PMSK (0x125C)
/* Port Mirroring */
#define RTL838X_MIR_CTRL(grp) (0x5D00 + (((grp) << 2)))
@@ -137,7 +140,7 @@
#define RTL839X_MIR_DPM_CTRL(grp) (0x2530 + (((grp) << 2)))
#define RTL839X_MIR_SPM_CTRL(grp) (0x2510 + (((grp) << 2)))
-/* Storm control */
+/* Storm/rate control and scheduling */
#define RTL838X_STORM_CTRL (0x4700)
#define RTL839X_STORM_CTRL (0x1800)
#define RTL838X_STORM_CTRL_LB_CTRL(p) (0x4884 + (((p) << 2)))
@@ -145,12 +148,23 @@
#define RTL838X_STORM_CTRL_BURST_PPS_1 (0x4878)
#define RTL838X_STORM_CTRL_BURST_0 (0x487c)
#define RTL838X_STORM_CTRL_BURST_1 (0x4880)
+#define RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_0 (0x1804)
+#define RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_1 (0x1808)
#define RTL838X_SCHED_CTRL (0xB980)
+#define RTL839X_SCHED_CTRL (0x60F4)
#define RTL838X_SCHED_LB_TICK_TKN_CTRL_0 (0xAD58)
#define RTL838X_SCHED_LB_TICK_TKN_CTRL_1 (0xAD5C)
#define RTL839X_SCHED_LB_TICK_TKN_CTRL_0 (0x1804)
#define RTL839X_SCHED_LB_TICK_TKN_CTRL_1 (0x1808)
+#define RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL (0x2000)
+#define RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0 (0x1604)
+#define RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1 (0x1608)
+#define RTL839X_SCHED_LB_TICK_TKN_CTRL (0x60F8)
+#define RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL (0x6200)
#define RTL838X_SCHED_LB_THR (0xB984)
+#define RTL839X_SCHED_LB_THR (0x60FC)
+#define RTL838X_SCHED_P_EGR_RATE_CTRL(p) (0xC008 + (((p) << 7)))
+#define RTL838X_SCHED_Q_EGR_RATE_CTRL(p, q) (0xC00C + (p << 7) + (((q) << 2)))
#define RTL838X_STORM_CTRL_PORT_BC_EXCEED (0x470C)
#define RTL838X_STORM_CTRL_PORT_MC_EXCEED (0x4710)
#define RTL838X_STORM_CTRL_PORT_UC_EXCEED (0x4714)
@@ -160,6 +174,23 @@
#define RTL838X_STORM_CTRL_PORT_UC(p) (0x4718 + (((p) << 2)))
#define RTL838X_STORM_CTRL_PORT_MC(p) (0x478c + (((p) << 2)))
#define RTL838X_STORM_CTRL_PORT_BC(p) (0x4800 + (((p) << 2)))
+#define RTL839X_STORM_CTRL_PORT_UC_0(p) (0x185C + (((p) << 3)))
+#define RTL839X_STORM_CTRL_PORT_UC_1(p) (0x1860 + (((p) << 3)))
+#define RTL839X_STORM_CTRL_PORT_MC_0(p) (0x19FC + (((p) << 3)))
+#define RTL839X_STORM_CTRL_PORT_MC_1(p) (0x1a00 + (((p) << 3)))
+#define RTL839X_STORM_CTRL_PORT_BC_0(p) (0x1B9C + (((p) << 3)))
+#define RTL839X_STORM_CTRL_PORT_BC_1(p) (0x1BA0 + (((p) << 3)))
+#define RTL839X_TBL_ACCESS_CTRL_2 (0x611C)
+#define RTL839X_TBL_ACCESS_DATA_2(i) (0x6120 + (((i) << 2)))
+#define RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p) (0x1618 + (((p) << 3)))
+#define RTL839X_IGR_BWCTRL_PORT_CTRL_10G_1(p) (0x161C + (((p) << 3)))
+#define RTL839X_IGR_BWCTRL_PORT_CTRL_0(p) (0x1640 + (((p) << 3)))
+#define RTL839X_IGR_BWCTRL_PORT_CTRL_1(p) (0x1644 + (((p) << 3)))
+#define RTL839X_IGR_BWCTRL_CTRL_LB_THR (0x1614)
+
+/* Link aggregation (Trunking) */
+#define RTL839X_TRK_MBR_CTR (0x2200)
+#define RTL838X_TRK_MBR_CTR (0x3E00)
/* Attack prevention */
#define RTL838X_ATK_PRVNT_PORT_EN (0x5B00)
@@ -167,6 +198,45 @@
#define RTL838X_ATK_PRVNT_ACT (0x5B08)
#define RTL838X_ATK_PRVNT_STS (0x5B1C)
+/* 802.1X */
+#define RTL838X_SPCL_TRAP_EAPOL_CTRL (0x6988)
+#define RTL839X_SPCL_TRAP_EAPOL_CTRL (0x105C)
+
+/* QoS */
+#define RTL838X_QM_INTPRI2QID_CTRL (0x5F00)
+#define RTL839X_QM_INTPRI2QID_CTRL(q) (0x1110 + (q << 2))
+#define RTL839X_QM_PORT_QNUM(p) (0x1130 + (((p / 10) << 2)))
+#define RTL838X_PRI_SEL_PORT_PRI(p) (0x5FB8 + (((p / 10) << 2)))
+#define RTL839X_PRI_SEL_PORT_PRI(p) (0x10A8 + (((p / 10) << 2)))
+#define RTL838X_QM_PKT2CPU_INTPRI_MAP (0x5F10)
+#define RTL839X_QM_PKT2CPU_INTPRI_MAP (0x1154)
+#define RTL838X_PRI_SEL_CTRL (0x10E0)
+#define RTL839X_PRI_SEL_CTRL (0x10E0)
+#define RTL838X_PRI_SEL_TBL_CTRL(i) (0x5FD8 + (((i) << 2)))
+#define RTL839X_PRI_SEL_TBL_CTRL(i) (0x10D0 + (((i) << 2)))
+#define RTL838X_QM_PKT2CPU_INTPRI_0 (0x5F04)
+#define RTL838X_QM_PKT2CPU_INTPRI_1 (0x5F08)
+#define RTL838X_QM_PKT2CPU_INTPRI_2 (0x5F0C)
+#define RTL839X_OAM_CTRL (0x2100)
+#define RTL839X_OAM_PORT_ACT_CTRL(p) (0x2104 + (((p) << 2)))
+#define RTL839X_RMK_PORT_DEI_TAG_CTRL(p) (0x6A9C + (((p >> 5) << 2)))
+#define RTL839X_PRI_SEL_IPRI_REMAP (0x1080)
+#define RTL838X_PRI_SEL_IPRI_REMAP (0x5F8C)
+#define RTL839X_PRI_SEL_DEI2DP_REMAP (0x10EC)
+#define RTL839X_PRI_SEL_DSCP2DP_REMAP_ADDR(i) (0x10F0 + (((i >> 4) << 2)))
+#define RTL839X_RMK_DEI_CTRL (0x6AA4)
+#define RTL839X_WRED_PORT_THR_CTRL(i) (0x6084 + ((i) << 2))
+#define RTL839X_WRED_QUEUE_THR_CTRL(q, i) (0x6090 + ((q) * 12) + ((i) << 2))
+#define RTL838X_PRI_DSCP_INVLD_CTRL0 (0x5FE8)
+#define RTL838X_RMK_IPRI_CTRL (0xA460)
+#define RTL838X_RMK_OPRI_CTRL (0xA464)
+#define RTL838X_SCHED_P_TYPE_CTRL(p) (0xC04C + (((p) << 7)))
+#define RTL838X_SCHED_LB_CTRL(p) (0xC004 + (((p) << 7)))
+#define RTL838X_FC_P_EGR_DROP_CTRL(p) (0x6B1C + (((p) << 2)))
+
+#define MAX_LAGS 16
+#define MAX_PRIOS 8
+
enum phy_type {
PHY_NONE = 0,
PHY_RTL838X_SDS = 1,
@@ -182,6 +252,7 @@ struct rtl838x_port {
u16 pvid;
bool eee_enabled;
enum phy_type phy;
+ bool is10G;
const struct dsa_port *dp;
};
@@ -267,6 +338,10 @@ struct rtl838x_reg {
int (*vlan_port_igr_filter)(int port);
int (*vlan_port_pb)(int port);
int (*vlan_port_tag_sts_ctrl)(int port);
+ int (*rtl838x_vlan_port_tag_sts_ctrl)(int port);
+ int (*trk_mbr_ctr)(int group);
+ int rma_bpdu_fld_pmask;
+ int spcl_trap_eapol_ctrl;
};
struct rtl838x_switch_priv {
@@ -286,6 +361,10 @@ struct rtl838x_switch_priv {
u8 port_mask;
u32 fib_entries;
struct dentry *dbgfs_dir;
+ int n_lags;
+ u64 lags_port_members[MAX_LAGS];
+ struct net_device *lag_devs[MAX_LAGS];
+ struct notifier_block nb;
};
void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv);
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c
index 8dd123f609..03b92a7914 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c
@@ -4,7 +4,7 @@
#include "rtl83xx.h"
extern struct mutex smi_lock;
-
+extern struct rtl83xx_soc_info soc_info;
static inline void rtl839x_mask_port_reg_be(u64 clear, u64 set, int reg)
{
@@ -70,6 +70,12 @@ static inline void rtl839x_exec_tbl1_cmd(u32 cmd)
do { } while (sw_r32(RTL839X_TBL_ACCESS_CTRL_1) & BIT(16));
}
+inline void rtl839x_exec_tbl2_cmd(u32 cmd)
+{
+ sw_w32(cmd, RTL839X_TBL_ACCESS_CTRL_2);
+ do { } while (sw_r32(RTL839X_TBL_ACCESS_CTRL_2) & (1 << 9));
+}
+
static inline int rtl839x_tbl_access_data_0(int i)
{
return RTL839X_TBL_ACCESS_DATA_0(i);
@@ -181,6 +187,11 @@ static inline int rtl839x_mac_link_spd_sts(int p)
return RTL839X_MAC_LINK_SPD_STS(p);
}
+static inline int rtl839x_trk_mbr_ctr(int group)
+{
+ return RTL839X_TRK_MBR_CTR + (group << 3);
+}
+
static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e)
{
u64 entry;
@@ -358,6 +369,9 @@ const struct rtl838x_reg rtl839x_reg = {
.vlan_port_igr_filter = rtl839x_vlan_port_igr_filter,
.vlan_port_pb = rtl839x_vlan_port_pb,
.vlan_port_tag_sts_ctrl = rtl839x_vlan_port_tag_sts_ctrl,
+ .trk_mbr_ctr = rtl839x_trk_mbr_ctr,
+ .rma_bpdu_fld_pmask = RTL839X_RMA_BPDU_FLD_PMSK,
+ .spcl_trap_eapol_ctrl = RTL839X_SPCL_TRAP_EAPOL_CTRL,
};
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id)
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h
index 3953512525..23f36a85e5 100644
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h
+++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h
@@ -24,7 +24,7 @@ struct rtl83xx_mib_desc {
const char *name;
};
-void __init rtl83xx_storm_control_init(struct rtl838x_switch_priv *priv);
+void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv);
/* RTL838x-specific */
u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed);
@@ -39,6 +39,7 @@ irqreturn_t rtl839x_switch_irq(int irq, void *dev_id);
void rtl8390_get_version(struct rtl838x_switch_priv *priv);
void rtl839x_vlan_profile_dump(int index);
int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val);
+inline void rtl839x_exec_tbl2_cmd(u32 cmd);
#endif /* _NET_DSA_RTL83XX_H */
diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c
deleted file mode 100644
index de0af033f3..0000000000
--- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <asm/mach-rtl838x/mach-rtl83xx.h>
-#include "rtl83xx.h"
-
-
-static void rtl83xx_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable)
-{
- // Enable Storm control for that port for UC, MC, and BC
- if (enable)
- sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port));
- else
- sw_w32(0x0, RTL838X_STORM_CTRL_LB_CTRL(port));
-}
-
-void __init rtl83xx_storm_control_init(struct rtl838x_switch_priv *priv)
-{
- int i;
-
- pr_debug("Enabling Storm control\n");
- // TICK_PERIOD_PPS
- if (priv->id == 0x8380)
- sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0);
-
- // Set burst rate
- sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); // UC
- sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); // MC and BC
-
- // Set burst Packets per Second to 32
- sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); // UC
- sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); // MC and BC
-
- // Include IFG in storm control
- sw_w32_mask(0, BIT(6), RTL838X_STORM_CTRL);
- // Rate control is based on bytes/s (0 = packets)
- sw_w32_mask(0, BIT(5), RTL838X_STORM_CTRL);
- // Bandwidth control includes preamble and IFG (10 Bytes)
- sw_w32_mask(0, 1, RTL838X_SCHED_CTRL);
-
- // On SoCs except RTL8382M, set burst size of port egress
- if (priv->id != 0x8382)
- sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR);
-
- /* Enable storm control on all ports with a PHY and limit rates,
- * for UC and MC for both known and unknown addresses */
- for (i = 0; i < priv->cpu_port; i++) {
- if (priv->ports[i].phy) {
- sw_w32(BIT(18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i));
- sw_w32(BIT(18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i));
- sw_w32(0x000, RTL838X_STORM_CTRL_PORT_BC(i));
- rtl83xx_storm_enable(priv, i, true);
- }
- }
-
- // Attack prevention, enable all attack prevention measures
- //sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL);
- /* Attack prevention, drop (bit = 0) problematic packets on all ports.
- * Setting bit = 1 means: trap to CPU
- */
- //sw_w32(0, RTL838X_ATK_PRVNT_ACT);
- // Enable attack prevention on all ports
- //sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN);
-}
-
diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c
index fec842674e..951d936c71 100644
--- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c
+++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c
@@ -91,14 +91,19 @@ struct notify_b {
u32 reserved2[8];
};
-inline void rtl838x_create_tx_header(struct p_hdr *h, int dest_port)
+inline void rtl838x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
{
+ prio &= 0x7;
+
if (dest_port > 0) {
h->cpu_tag[0] = 0x0400;
h->cpu_tag[1] = 0x0200;
h->cpu_tag[2] = 0x0000;
- h->cpu_tag[3] = (1 << dest_port) >> 16;
- h->cpu_tag[4] = (1 << dest_port) & 0xffff;
+ h->cpu_tag[3] = BIT(dest_port) >> 16;
+ h->cpu_tag[4] = BIT(dest_port) & 0xffff;
+ // Set internal priority and AS_PRIO
+ if (prio >= 0)
+ h->cpu_tag[1] |= (prio | 0x8) << 12;
} else {
h->cpu_tag[0] = 0;
h->cpu_tag[1] = 0;
@@ -108,14 +113,25 @@ inline void rtl838x_create_tx_header(struct p_hdr *h, int dest_port)
}
}
-inline void rtl839x_create_tx_header(struct p_hdr *h, int dest_port)
+inline void rtl839x_create_tx_header(struct p_hdr *h, int dest_port, int prio)
{
+ prio &= 0x7;
+
if (dest_port > 0) {
h->cpu_tag[0] = 0x0100;
- h->cpu_tag[1] = ((1 << (dest_port - 32)) >> 16) | (1 << 21);
- h->cpu_tag[2] = (1 << (dest_port - 32)) & 0xffff;
- h->cpu_tag[3] = (1 << dest_port) >> 16;
- h->cpu_tag[4] = (1 << dest_port) & 0xffff;
+ h->cpu_tag[1] = h->cpu_tag[2] = h->cpu_tag[3] = h->cpu_tag[4] = 0;
+ if (dest_port >= 32) {
+ dest_port -= 32;
+ h->cpu_tag[1] = BIT(dest_port) >> 16;
+ h->cpu_tag[2] = BIT(dest_port) & 0xffff;
+ } else {
+ h->cpu_tag[3] = BIT(dest_port) >> 16;
+ h->cpu_tag[4] = BIT(dest_port) & 0xffff;
+ }
+ h->cpu_tag[1] |= BIT(21); // Enable destination port mask use
+ // Set internal priority and AS_PRIO
+ if (prio >= 0)
+ h->cpu_tag[0] |= prio | BIT(3);
} else {
h->cpu_tag[0] = 0;
h->cpu_tag[1] = 0;
@@ -125,13 +141,19 @@ inline void rtl839x_create_tx_header(struct p_hdr *h, int dest_port)
}
}
+struct rtl838x_rx_q {
+ int id;
+ struct rtl838x_eth_priv *priv;
+ struct napi_struct napi;
+};
+
struct rtl838x_eth_priv {
struct net_device *netdev;
struct platform_device *pdev;
void *membase;
spinlock_t lock;
struct mii_bus *mii_bus;
- struct napi_struct napi;
+ struct rtl838x_rx_q rx_qs[RXRINGS];
struct phylink *phylink;
struct phylink_config phylink_config;
u16 id;
@@ -229,25 +251,25 @@ struct fdb_update_work {
void rtl838x_fdb_sync(struct work_struct *work)
{
- const struct fdb_update_work *uw =
- container_of(work, struct fdb_update_work, work);
- struct switchdev_notifier_fdb_info info;
- u8 addr[ETH_ALEN];
- int i = 0;
- int action;
-
- while (uw->macs[i]) {
- action = (uw->macs[i] & (1ULL << 63)) ? SWITCHDEV_FDB_ADD_TO_BRIDGE
- : SWITCHDEV_FDB_DEL_TO_BRIDGE;
- u64_to_ether_addr(uw->macs[i] & 0xffffffffffffULL, addr);
- info.addr = &addr[0];
- info.vid = 0;
- info.offloaded = 1;
- pr_debug("FDB entry %d: %llx, action %d\n", i, uw->macs[0], action);
- call_switchdev_notifiers(action, uw->ndev, &info.info, NULL);
- i++;
- }
- kfree(work);
+ const struct fdb_update_work *uw =
+ container_of(work, struct fdb_update_work, work);
+ struct switchdev_notifier_fdb_info info;
+ u8 addr[ETH_ALEN];
+ int i = 0;
+ int action;
+
+ while (uw->macs[i]) {
+ action = (uw->macs[i] & (1ULL << 63)) ? SWITCHDEV_FDB_ADD_TO_BRIDGE
+ : SWITCHDEV_FDB_DEL_TO_BRIDGE;
+ u64_to_ether_addr(uw->macs[i] & 0xffffffffffffULL, addr);
+ info.addr = &addr[0];
+ info.vid = 0;
+ info.offloaded = 1;
+ pr_debug("FDB entry %d: %llx, action %d\n", i, uw->macs[0], action);
+ call_switchdev_notifiers(action, uw->ndev, &info.info, NULL);
+ i++;
+ }
+ kfree(work);
}
static void rtl839x_l2_notification_handler(struct rtl838x_eth_priv *priv)
@@ -295,6 +317,7 @@ static irqreturn_t rtl838x_net_irq(int irq, void *dev_id)
u32 status = sw_r32(priv->r->dma_if_intr_sts);
bool triggered = false;
u32 atk = sw_r32(RTL838X_ATK_PRVNT_STS);
+ int i;
u32 storm_uc = sw_r32(RTL838X_STORM_CTRL_PORT_UC_EXCEED);
u32 storm_mc = sw_r32(RTL838X_STORM_CTRL_PORT_MC_EXCEED);
u32 storm_bc = sw_r32(RTL838X_STORM_CTRL_PORT_BC_EXCEED);
@@ -325,12 +348,13 @@ static irqreturn_t rtl838x_net_irq(int irq, void *dev_id)
/* RX interrupt */
if (status & 0x0ff00) {
- /* Disable RX interrupt */
- if (triggered)
- pr_info("RX\n");
- sw_w32_mask(0xff00, 0, priv->r->dma_if_intr_msk);
- sw_w32(0x0000ff00, priv->r->dma_if_intr_sts);
- napi_schedule(&priv->napi);
+ /* Disable RX interrupt for this ring */
+ sw_w32_mask(0xff00 & status, 0, priv->r->dma_if_intr_msk);
+ sw_w32(0x0000ff00 & status, priv->r->dma_if_intr_sts);
+ for (i = 0; i < RXRINGS; i++) {
+ if (status & BIT(i + 8))
+ napi_schedule(&priv->rx_qs[i].napi);
+ }
}
/* RX buffer overrun */
@@ -535,7 +559,7 @@ static int rtl838x_eth_open(struct net_device *ndev)
unsigned long flags;
struct rtl838x_eth_priv *priv = netdev_priv(ndev);
struct ring_b *ring = priv->membase;
- int err;
+ int i, err;
pr_info("%s called: RX rings %d, TX rings %d\n", __func__, RXRINGS, TXRINGS);
@@ -559,8 +583,10 @@ static int rtl838x_eth_open(struct net_device *ndev)
}
phylink_start(priv->phylink);
- napi_enable(&priv->napi);
- netif_start_queue(ndev);
+ for (i = 0; i < RXRINGS; i++)
+ napi_enable(&priv->rx_qs[i].napi);
+
+ netif_tx_start_all_queues(ndev);
if (priv->family_id == RTL8380_FAMILY_ID) {
rtl838x_hw_en_rxtx(priv);
@@ -625,6 +651,7 @@ static void rtl838x_hw_stop(struct rtl838x_eth_priv *priv)
static int rtl838x_eth_stop(struct net_device *ndev)
{
unsigned long flags;
+ int i;
struct rtl838x_eth_priv *priv = netdev_priv(ndev);
pr_info("in %s\n", __func__);
@@ -633,8 +660,12 @@ static int rtl838x_eth_stop(struct net_device *ndev)
phylink_stop(priv->phylink);
rtl838x_hw_stop(priv);
free_irq(ndev->irq, ndev);
- napi_disable(&priv->napi);
- netif_stop_queue(ndev);
+
+ for (i = 0; i < RXRINGS; i++)
+ napi_disable(&priv->rx_qs[i].napi);
+
+ netif_tx_stop_all_queues(ndev);
+
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
@@ -705,6 +736,10 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
struct p_hdr *h;
int dest_port = -1;
+ int q = skb_get_queue_mapping(skb) % TXRINGS;
+
+ if (q)
+ pr_debug("SKB priority: %d\n", skb->priority);
spin_lock_irqsave(&priv->lock, flags);
len = skb->len;
@@ -729,9 +764,9 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
}
/* We can send this packet if CPU owns the descriptor */
- if (!(ring->tx_r[0][ring->c_tx[0]] & 0x1)) {
+ if (!(ring->tx_r[q][ring->c_tx[q]] & 0x1)) {
/* Set descriptor for tx */
- h = &ring->tx_header[0][ring->c_tx[0]];
+ h = &ring->tx_header[q][ring->c_tx[q]];
h->buf = (u8 *)KSEG1ADDR(ring->tx_space);
h->size = len;
@@ -739,17 +774,17 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
/* Create cpu_tag */
if (priv->family_id == RTL8380_FAMILY_ID)
- rtl838x_create_tx_header(h, dest_port);
+ rtl838x_create_tx_header(h, dest_port, skb->priority >> 1);
else
- rtl839x_create_tx_header(h, dest_port);
+ rtl839x_create_tx_header(h, dest_port, skb->priority >> 1);
/* Copy packet data to tx buffer */
memcpy((void *)KSEG1ADDR(h->buf), skb->data, len);
/* Make sure packet data is visible to ASIC */
- mb(); /* wmb() probably works, too */
+ wmb();
/* Hand over to switch */
- ring->tx_r[0][ring->c_tx[0]] = ring->tx_r[0][ring->c_tx[0]] | 0x1;
+ ring->tx_r[q][ring->c_tx[q]] = ring->tx_r[q][ring->c_tx[q]] | 0x1;
/* BUG: before tx fetch, need to make sure right data is accessed
* This might not be necessary on newer RTL839x, though.
@@ -766,7 +801,7 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += len;
dev_kfree_skb(skb);
- ring->c_tx[0] = (ring->c_tx[0] + 1) % TXRINGLEN;
+ ring->c_tx[q] = (ring->c_tx[q] + 1) % TXRINGLEN;
ret = NETDEV_TX_OK;
} else {
dev_warn(&priv->pdev->dev, "Data is owned by switch\n");
@@ -777,6 +812,15 @@ txdone:
return ret;
}
+u16 rtl838x_pick_tx_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev)
+{
+ static u8 last = 0;
+
+ last++;
+ return last % TXRINGS;
+}
+
static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
{
struct rtl838x_eth_priv *priv = netdev_priv(dev);
@@ -789,10 +833,12 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
u32 *last;
struct p_hdr *h;
bool dsa = netdev_uses_dsa(dev);
+ int reason, queue;
spin_lock_irqsave(&priv->lock, flags);
last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur(r)));
+ pr_debug("RX - %d\n", r);
if (&ring->rx_r[r][ring->c_rx[r]] == last) {
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
@@ -845,6 +891,24 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
skb->data[len-1] = 0x00;
}
+ if (priv->family_id == RTL8380_FAMILY_ID) {
+ reason = h->cpu_tag[3] & 0xf;
+ if (reason != 15)
+ pr_debug("Reason: %d\n", reason);
+ queue = (h->cpu_tag[0] & 0xe0) >> 5;
+ if (reason != 4) // NIC_RX_REASON_SPECIAL_TRAP
+ skb->data[len-3] |= 0x40;
+ } else {
+ reason = h->cpu_tag[4] & 0x1f;
+ if (reason != 31)
+ pr_debug("Reason: %d\n", reason);
+ queue = (h->cpu_tag[3] & 0xe000) >> 13;
+ if ((reason != 7) && (reason != 8)) // NIC_RX_REASON_RMA_USR
+ skb->data[len-3] |= 0x40;
+ }
+ if (queue >= 2)
+ pr_debug("Queue: %d\n", queue);
+
skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
@@ -865,6 +929,7 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
ring->rx_r[r][ring->c_rx[r]]
= KSEG1ADDR(h) | 0x1 | (ring->c_rx[r] == (RXRINGLEN-1) ? WRAP : 0x1);
ring->c_rx[r] = (ring->c_rx[r] + 1) % RXRINGLEN;
+ last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur(r)));
} while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -873,18 +938,23 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
static int rtl838x_poll_rx(struct napi_struct *napi, int budget)
{
- struct rtl838x_eth_priv *priv = container_of(napi, struct rtl838x_eth_priv, napi);
- int work_done = 0, r = 0;
-
- while (work_done < budget && r < RXRINGS) {
- work_done += rtl838x_hw_receive(priv->netdev, r, budget - work_done);
- r++;
+ struct rtl838x_rx_q *rx_q = container_of(napi, struct rtl838x_rx_q, napi);
+ struct rtl838x_eth_priv *priv = rx_q->priv;
+ int work_done = 0;
+ int r = rx_q->id;
+ int work;
+
+ while (work_done < budget) {
+ work = rtl838x_hw_receive(priv->netdev, r, budget - work_done);
+ if (!work)
+ break;
+ work_done += work;
}
if (work_done < budget) {
napi_complete_done(napi, work_done);
/* Enable RX interrupt */
- sw_w32_mask(0, 0xfffff, priv->r->dma_if_intr_msk);
+ sw_w32_mask(0, 0xf00ff | BIT(r + 8), priv->r->dma_if_intr_msk);
}
return work_done;
}
@@ -1325,6 +1395,7 @@ static const struct net_device_ops rtl838x_eth_netdev_ops = {
.ndo_open = rtl838x_eth_open,
.ndo_stop = rtl838x_eth_stop,
.ndo_start_xmit = rtl838x_eth_tx,
+ .ndo_select_queue = rtl838x_pick_tx_queue,
.ndo_set_mac_address = rtl838x_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = rtl838x_eth_set_multicast_list,
@@ -1355,6 +1426,7 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
phy_interface_t phy_mode;
struct phylink *phylink;
int err = 0;
+ int i;
pr_info("Probing RTL838X eth device pdev: %x, dev: %x\n",
(u32)pdev, (u32)(&(pdev->dev)));
@@ -1364,7 +1436,7 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
return -EINVAL;
}
- dev = alloc_etherdev(sizeof(struct rtl838x_eth_priv));
+ dev = alloc_etherdev_mqs(sizeof(struct rtl838x_eth_priv), TXRINGS, RXRINGS);
if (!dev) {
err = -ENOMEM;
goto err_free;
@@ -1412,6 +1484,8 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
dev->irq = res->start;
}
dev->ethtool_ops = &rtl838x_ethtool_ops;
+ dev->min_mtu = ETH_ZLEN;
+ dev->max_mtu = 1536;
priv->id = soc_info.id;
priv->family_id = soc_info.family;
@@ -1476,7 +1550,12 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
if (err)
goto err_free;
- netif_napi_add(dev, &priv->napi, rtl838x_poll_rx, 64);
+ for (i = 0; i < RXRINGS; i++) {
+ priv->rx_qs[i].id = i;
+ priv->rx_qs[i].priv = priv;
+ netif_napi_add(dev, &priv->rx_qs[i].napi, rtl838x_poll_rx, 64);
+ }
+
platform_set_drvdata(pdev, dev);
phy_mode = of_get_phy_mode(dn);
@@ -1508,13 +1587,18 @@ static int rtl838x_eth_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct rtl838x_eth_priv *priv = netdev_priv(dev);
+ int i;
if (dev) {
pr_info("Removing platform driver for rtl838x-eth\n");
rtl838x_mdio_remove(priv);
rtl838x_hw_stop(priv);
- netif_stop_queue(dev);
- netif_napi_del(&priv->napi);
+
+ netif_tx_stop_all_queues(dev);
+
+ for (i = 0; i < RXRINGS; i++)
+ netif_napi_del(&priv->rx_qs[i].napi);
+
unregister_netdev(dev);
free_netdev(dev);
}
diff --git a/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch b/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch
index c8a09c50d3..07ee5307ae 100644
--- a/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch
+++ b/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch
@@ -5,25 +5,28 @@
trailer = skb_put(nskb, 4);
trailer[0] = 0x80;
+
-+#ifdef CONFIG_NET_DSA_RTL83XX
++#ifdef CONFIG_NET_DSA_RTL838X
+ trailer[1] = dp->index;
+#else
trailer[1] = 1 << dp->index;
-+#endif /* CONFIG_NET_DSA_RTL83XX */
++#endif /* CONFIG_NET_DSA_RTL838X */
trailer[2] = 0x10;
trailer[3] = 0x00;
-@@ -61,12 +66,20 @@ static struct sk_buff *trailer_rcv(struc
+@@ -61,12 +69,23 @@ static struct sk_buff *trailer_rcv(struc
return NULL;
trailer = skb_tail_pointer(skb) - 4;
+
-+#ifdef CONFIG_NET_DSA_RTL83XX
-+ if (trailer[0] != 0x80 || (trailer[1] & 0xe0) != 0x00 ||
++#ifdef CONFIG_NET_DSA_RTL838X
++ if (trailer[0] != 0x80 || (trailer[1] & 0x80) != 0x00 ||
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
+ return NULL;
+
-+ source_port = trailer[1] & 0x1f;
++ if (!(trailer[1] & 0x40))
++ skb->offload_fwd_mark = 1;
++
++ source_port = trailer[1] & 0x3f;
+#else
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
More information about the lede-commits
mailing list