This second version of the patch is rebased on the work done by Roman
Yeryomin and applied in r23126.
It corrects a minor miscalculation in the port rate code and cleans the
code a bit, plus it adds support for jumbo frames, port priority and storm
control.

Signed-off-by: Luca Niccoli <[email protected]>


Index: target/linux/generic/files/drivers/net/phy/rtl8366rb.c
===================================================================
--- target/linux/generic/files/drivers/net/phy/rtl8366rb.c      (revisione 
23144)
+++ target/linux/generic/files/drivers/net/phy/rtl8366rb.c      (copia locale)
@@ -1,9 +1,10 @@
 /*
- * Platform driver for the Realtek RTL8366S ethernet switch
+ * Platform driver for the Realtek RTL8366RB ethernet switch
  *
  * Copyright (C) 2009-2010 Gabor Juhos <[email protected]>
  * Copyright (C) 2010 Antti Seppälä <[email protected]>
  * Copyright (C) 2010 Roman Yeryomin <[email protected]>
+ * Copyright (C) 2010 Luca Niccoli <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -181,8 +182,8 @@
 #define RTL8366RB_EB_PREIFG_OFFSET     9
 #define RTL8366RB_EB_PREIFG_MASK       (1 << RTL8366RB_EB_PREIFG_OFFSET)
 
-#define RTL8366RB_BDTH_SW_MAX          1048512
-#define RTL8366RB_BDTH_BASE            64
+#define RTL8366RB_BDTH_SW_MAX          1048576
+#define RTL8366RB_BDTH_UNIT            64
 #define RTL8366RB_BDTH_REG_DEFAULT     16383
 
 /* QOS */
@@ -192,6 +193,28 @@
 #define RTL8366RB_QOS_DEFAULT_PREIFG   1
 
 
+/* Port-based priority register */
+#define RTL8366RB_PORT_PRIORITY_BASE           0x020C
+#define RTL8366RB_PORT_PRIORITY_BITS           3
+#define RTL8366RB_PORT_PRIORITY_MASK           0x7
+
+
+/* Storm Control Register
+ * Filter for: broadcast, multicast, unknown address, unknown multicast
+ */
+#define RTL8366RB_STORM_BC_REG         0x03E0
+#define RTL8366RB_STORM_MC_REG         0x03E1
+#define RTL8366RB_STORM_UA_REG         0x03E2
+#define RTL8366RB_STORM_UM_REG         0x03E3
+#define RTL8366RB_STORM_PORT_MASK(pnum)        (1 << pnum)
+#define RTL8366RB_STORM_RATE_BASE      0x03E4
+#define RTL8366RB_STORM_RATE_REG(pnum) (RTL8366RB_STORM_RATE_BASE + pnum)
+#define RTL8366RB_STORM_RATE_MASK      0x3FFF
+#define RTL8366RB_STORM_RATE_MAX       1048576
+#define RTL8366RB_STORM_RATE_UNIT      64
+#define RTL8366RB_STORM_RATE_DEFAULT   0
+
+
 static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
        { 0,  0, 4, "IfInOctets"                                },
        { 0,  4, 4, "EtherStatsOctets"                          },
@@ -679,7 +702,49 @@
        return 0;
 }
 
+static int rtl8366rb_sw_get_max_length(struct switch_dev *dev,
+                                    const struct switch_attr *attr,
+                                    struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
 
+       rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data);
+
+       val->value.i = ((data & (RTL8366RB_SGCR_MAX_LENGTH_MASK)) >> 4);
+
+       return 0;
+}
+
+static int rtl8366rb_sw_set_max_length(struct switch_dev *dev,
+                                   const struct switch_attr *attr,
+                                   struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       char length_code;
+ 
+       switch (val->value.i) {
+               case 0:
+                       length_code = RTL8366RB_SGCR_MAX_LENGTH_1522;
+                       break;
+               case 1:
+                       length_code = RTL8366RB_SGCR_MAX_LENGTH_1536;
+                       break;
+               case 2:
+                       length_code = RTL8366RB_SGCR_MAX_LENGTH_1552;
+                       break;
+               case 3:
+                       length_code = RTL8366RB_SGCR_MAX_LENGTH_9216;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR,
+                               RTL8366RB_SGCR_MAX_LENGTH_MASK,
+                               length_code);
+}
+
+
 static const char *rtl8366rb_speed_str(unsigned speed)
 {
        switch (speed) {
@@ -777,6 +842,61 @@
        return 0;
 }
 
+static int rtl8366rb_sw_set_port_pri(struct switch_dev *dev,
+                                   const struct switch_attr *attr,
+                                   struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 mask;
+       u32 reg;
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       if (val->port_vlan < 5) {
+               mask = RTL8366RB_PORT_PRIORITY_MASK <<
+                               (RTL8366RB_PORT_PRIORITY_BITS * val->port_vlan);
+               reg = RTL8366RB_PORT_PRIORITY_BASE;
+               data = val->value.i <<
+                               (RTL8366RB_PORT_PRIORITY_BITS * val->port_vlan);
+       } else {
+               mask = RTL8366RB_PORT_PRIORITY_MASK;
+               reg = RTL8366RB_PORT_PRIORITY_BASE + 1;
+               data = val->value.i;
+       }
+
+       return rtl8366_smi_rmwr(smi, reg, mask, data);
+}
+
+static int rtl8366rb_sw_get_port_pri(struct switch_dev *dev,
+                                   const struct switch_attr *attr,
+                                   struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 reg;
+       u32 shift;
+       u32 data = 0;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       if (val->port_vlan < 5) {
+               reg = RTL8366RB_PORT_PRIORITY_BASE;
+               shift = RTL8366RB_PORT_PRIORITY_BITS * val->port_vlan;
+
+       } else {
+               reg = RTL8366RB_PORT_PRIORITY_BASE + 1;
+               shift = 0;
+       }
+
+       rtl8366_smi_read_reg(smi, reg, &data);
+
+       val->value.i = ((data >> shift) & RTL8366RB_PORT_PRIORITY_MASK);
+
+       return 0;
+}
+
 static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev,
                                    const struct switch_attr *attr,
                                    struct switch_val *val)
@@ -821,12 +941,11 @@
 {
        struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
 
-       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
                return -EINVAL;
 
-       if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
-               val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_BASE;
-       else
+       val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+       if (val->value.i < 0)
                val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
 
        return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan),
@@ -848,10 +967,9 @@
 
        rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data);
        data &= RTL8366RB_IB_BDTH_MASK;
-       if (data < RTL8366RB_IB_BDTH_MASK)
-               data += 1;
+       data += 1;
 
-       val->value.i = (int)data * RTL8366RB_BDTH_BASE;
+       val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
 
        return 0;
 }
@@ -862,16 +980,15 @@
 {
        struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
 
-       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
                return -EINVAL;
 
        rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG,
                RTL8366RB_EB_PREIFG_MASK,
                (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET));
 
-       if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
-               val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_BASE;
-       else
+       val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+       if (val->value.i < 0)
                val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
 
        return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan),
@@ -891,14 +1008,175 @@
 
        rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data);
        data &= RTL8366RB_EB_BDTH_MASK;
-       if (data < RTL8366RB_EB_BDTH_MASK)
-               data += 1;
+       data += 1;
 
-       val->value.i = (int)data * RTL8366RB_BDTH_BASE;
+       val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
 
        return 0;
 }
 
+static int rtl8366rb_sw_set_port_bc_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       return rtl8366_smi_rmwr(smi, RTL8366RB_STORM_BC_REG,
+                               RTL8366RB_STORM_PORT_MASK(val->port_vlan),
+                               (val->value.i << val->port_vlan));
+}
+
+static int rtl8366rb_sw_get_port_bc_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       rtl8366_smi_read_reg(smi, RTL8366RB_STORM_BC_REG, &data);
+       val->value.i= (data & RTL8366RB_STORM_PORT_MASK(val->port_vlan))
+                      >> val->port_vlan;
+
+       return 0;
+}
+
+static int rtl8366rb_sw_set_port_mc_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       return rtl8366_smi_rmwr(smi, RTL8366RB_STORM_MC_REG,
+                               RTL8366RB_STORM_PORT_MASK(val->port_vlan),
+                               (val->value.i << val->port_vlan));
+}
+
+static int rtl8366rb_sw_get_port_mc_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       rtl8366_smi_read_reg(smi, RTL8366RB_STORM_MC_REG, &data);
+       val->value.i= (data & RTL8366RB_STORM_PORT_MASK(val->port_vlan))
+                      >> val->port_vlan;
+
+       return 0;
+}
+
+static int rtl8366rb_sw_set_port_ua_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       return rtl8366_smi_rmwr(smi, RTL8366RB_STORM_UA_REG,
+                               RTL8366RB_STORM_PORT_MASK(val->port_vlan),
+                               (val->value.i << val->port_vlan));
+}
+
+static int rtl8366rb_sw_get_port_ua_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       rtl8366_smi_read_reg(smi, RTL8366RB_STORM_UA_REG, &data);
+       val->value.i= (data & RTL8366RB_STORM_PORT_MASK(val->port_vlan))
+                      >> val->port_vlan;
+
+       return 0;
+}
+
+static int rtl8366rb_sw_set_port_um_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       return rtl8366_smi_rmwr(smi, RTL8366RB_STORM_UM_REG,
+                               RTL8366RB_STORM_PORT_MASK(val->port_vlan),
+                               (val->value.i << val->port_vlan));
+}
+
+static int rtl8366rb_sw_get_port_um_stfilter(struct switch_dev *dev,
+                                            const struct switch_attr *attr,
+                                            struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       rtl8366_smi_read_reg(smi, RTL8366RB_STORM_UM_REG, &data);
+       val->value.i= (data & RTL8366RB_STORM_PORT_MASK(val->port_vlan))
+                      >> val->port_vlan;
+
+       return 0;
+}
+
+static int rtl8366rb_sw_set_port_stfilter_rate(struct switch_dev *dev,
+                                              const struct switch_attr *attr,
+                                              struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS || val->value.i > attr->max)
+               return -EINVAL;
+
+       val->value.i = (val->value.i - 1) / RTL8366RB_STORM_RATE_UNIT;
+       if (val->value.i < 0)
+               val->value.i = RTL8366RB_STORM_RATE_DEFAULT;
+       
+       return rtl8366_smi_rmwr(smi, RTL8366RB_STORM_RATE_REG(val->port_vlan),
+                               RTL8366RB_STORM_RATE_MASK,
+                               val->value.i);
+}
+
+static int rtl8366rb_sw_get_port_stfilter_rate(struct switch_dev *dev,
+                                              const struct switch_attr *attr,
+                                              struct switch_val *val)
+{
+       struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+       u32 data;
+
+       if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+               return -EINVAL;
+
+       rtl8366_smi_read_reg(smi, RTL8366RB_STORM_RATE_REG(val->port_vlan),
+                            &data);
+       
+       data &= RTL8366RB_STORM_RATE_MASK;
+       data += 1;
+
+       val->value.i = data * RTL8366RB_STORM_RATE_UNIT;
+
+       return 0;
+}
 static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev,
                                    const struct switch_attr *attr,
                                    struct switch_val *val)
@@ -1003,6 +1281,14 @@
                .set = rtl8366rb_sw_set_qos_enable,
                .get = rtl8366rb_sw_get_qos_enable,
                .max = 1
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "max_length",
+               .description = "Get/Set the maximum length of valid packets"
+               " (0 = 1522, 1 = 1536, 2 = 1552, 3 = 9216)",
+               .set = rtl8366rb_sw_set_max_length,
+               .get = rtl8366rb_sw_get_max_length,
+               .max = 3,
        },
 };
 
@@ -1054,7 +1340,50 @@
                .max = RTL8366RB_BDTH_SW_MAX,
                .set = rtl8366rb_sw_set_port_rate_out,
                .get = rtl8366rb_sw_get_port_rate_out,
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "priority",
+               .description = "Get/Set port priority (0-7)",
+               .set = rtl8366rb_sw_set_port_pri,
+               .get = rtl8366rb_sw_get_port_pri,
+               .max = 7
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "bc_storm_filter",
+               .description = "Get/Set broadcast storm filtering (enabled or 
disabled)",
+               .max = 1,
+               .set = rtl8366rb_sw_set_port_bc_stfilter,
+               .get = rtl8366rb_sw_get_port_bc_stfilter,
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "mc_storm_filter",
+               .description = "Get/Set multicast storm filtering (enabled or 
disabled)",
+               .max = 1,
+               .set = rtl8366rb_sw_set_port_mc_stfilter,
+               .get = rtl8366rb_sw_get_port_mc_stfilter,
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "ua_storm_filter",
+               .description = "Get/Set unknown address storm filtering 
(enabled or disabled)",
+               .max = 1,
+               .set = rtl8366rb_sw_set_port_ua_stfilter,
+               .get = rtl8366rb_sw_get_port_ua_stfilter,
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "um_storm_filter",
+               .description = "Get/Set unknown multicast storm filtering 
(enabled or disabled)",
+               .max = 1,
+               .set = rtl8366rb_sw_set_port_um_stfilter,
+               .get = rtl8366rb_sw_get_port_um_stfilter,
+       }, {
+               .type = SWITCH_TYPE_INT,
+               .name = "storm_filter_rate",
+               .description = "Get/Set storm filtering rate in kbps",
+               .max = RTL8366RB_STORM_RATE_MAX,
+               .set = rtl8366rb_sw_set_port_stfilter_rate,
+               .get = rtl8366rb_sw_get_port_stfilter_rate,
        },
+
 };
 
 static struct switch_attr rtl8366rb_vlan[] = {
@@ -1347,5 +1676,6 @@
 MODULE_AUTHOR("Gabor Juhos <[email protected]>");
 MODULE_AUTHOR("Antti Seppälä <[email protected]>");
 MODULE_AUTHOR("Roman Yeryomin <[email protected]>");
+MODULE_AUTHOR("Luca Niccoli <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME);
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to