realtek: sync latest version realtek
authorBirger Koblitz <git@birger-koblitz.de>
Thu, 26 Nov 2020 07:41:42 +0000 (08:41 +0100)
committerJohn Crispin <john@phrozen.org>
Mon, 28 Dec 2020 18:33:15 +0000 (19:33 +0100)
Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
15 files changed:
target/linux/realtek/config-5.4
target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h
target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c [new file with mode: 0644]
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c [deleted file]
target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c
target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch

index 170bcb7632a5dbaae9b8595adc58ecbae7b303de..8171f6652964c123b84259956b6cf60fc4ed694d 100644 (file)
@@ -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
index b7d2a6f03725bbd0647beb21cfefd8d540d4a72f..b4d4efcb16fafaf6ae105d27c7e0e4d8316a8501 100644 (file)
 #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 */
index 5278afae03429918c9a9ea2b84cdc96750d8d8cc..27da109b13110c3e38d7134ee93563dcb64c9b21 100644 (file)
@@ -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();
 }
index 52cc151a56a7a9374a7ebac1ef86bd3979f34fb3..eeab299fcbb5789b9d69cd5d6f73bd820d088356 100644 (file)
@@ -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
index 1b57ddc92c866f9676e0881837d04cee84bbbcd9..219117b3999f6fc338187d0cfdefb6f37f91bdbc 100644 (file)
@@ -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;
index af24e8fa42a326f69a5670d498c9dec88f320bfa..8634cfbb80e202384facb2f66a9a87c789d6ad2a 100644 (file)
 // 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);
index a0717e1d9a1e40dd98984b99abeb2e77955983e1..77805e35c1227adedee6b4ee445543a4e6c3af3d 100644 (file)
@@ -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 (file)
index 0000000..2fc8d37
--- /dev/null
@@ -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);
+       
+}
index c7b5873e99c30cb94696affb3aa24aa02ae4ae57..f685b7d1c269977dbbe55e5426f51c59d3e5e69e 100644 (file)
@@ -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)
index 1ebb4dff72e75d929e3f0755a17ada750ee076d3..8a4958453a406506c96485b4577c83bedf98f6e9 100644 (file)
@@ -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))
 #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)))
 #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)))
 #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)
 #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)
 #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);
index 8dd123f609f1c1a7403ef5306d3b45ed195a1319..03b92a79147c1dc79af41b06fa864409f85ad225 100644 (file)
@@ -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)
index 39535125255d9170d5965a08b46c6f22ad814690..23f36a85e553b6b934766acfc5a8d5120e2e9e6c 100644 (file)
@@ -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 (file)
index de0af03..0000000
+++ /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);
-}
-
index fec842674e07619e9abb051f43f23375e76709b3..951d936c717bf80b423c1dfad4f2275ac141ba4e 100644 (file)
@@ -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);
        }
index c8a09c50d3805c4fd3441a35afe3226f409eb2d8..07ee5307ae5e1e13a78c67dc788b18edea17022b 100644 (file)
@@ -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)