Allowing per-port access to Switch Engine Broadcast Throttling Register

Also added lan9303_write_switch_reg_mask()

Signed-off-by: Egil Hjelmeland <pri...@egil-hjelmeland.no>
---
 drivers/net/dsa/lan9303-core.c | 83 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index be6d78f45a5f..b70acb73aad6 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -154,6 +154,7 @@
 # define LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING BIT(1)
 # define LAN9303_SWE_PORT_MIRROR_ENABLE_TX_MIRRORING BIT(0)
 #define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847
+#define LAN9303_SWE_BCST_THROT 0x1848
 #define LAN9303_BM_CFG 0x1c00
 #define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c
 # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT2 (BIT(17) | BIT(16))
@@ -426,6 +427,20 @@ static int lan9303_read_switch_reg(struct lan9303 *chip, 
u16 regnum, u32 *val)
        return ret;
 }
 
+static int lan9303_write_switch_reg_mask(
+       struct lan9303 *chip, u16 regnum, u32 val, u32 mask)
+{
+       int ret;
+       u32 reg;
+
+       ret = lan9303_read_switch_reg(chip, regnum, &reg);
+       if (ret)
+               return ret;
+       reg = (reg & ~mask) | val;
+
+       return lan9303_write_switch_reg(chip, regnum, reg);
+}
+
 static int lan9303_detect_phy_setup(struct lan9303 *chip)
 {
        int reg;
@@ -614,6 +629,66 @@ static int lan9303_check_device(struct lan9303 *chip)
        return 0;
 }
 
+/* ---------------------- Sysfs on slave port --------------------------*/
+/*13.4.3.23 Switch Engine Broadcast Throttling Register (SWE_BCST_THROT)*/
+static ssize_t
+swe_bcst_throt_show(struct device *dev, struct device_attribute *attr,
+                   char *buf)
+{
+       struct dsa_port *dp = dsa_net_device_to_dsa_port(to_net_dev(dev));
+       struct lan9303 *chip = dp->ds->priv;
+       int port = dp->index;
+       int reg;
+
+       if (lan9303_read_switch_reg(chip, LAN9303_SWE_BCST_THROT, &reg))
+               return 0;
+
+       reg = (reg >> (9 * port)) & 0x1ff; /*extract port N*/
+       if (reg & 0x100)
+               reg &= 0xff; /* remove enable bit */
+       else
+               reg = 0;     /* not enabled*/
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", reg);
+}
+
+static ssize_t
+swe_bcst_throt_store(struct device *dev, struct device_attribute *attr,
+                    const char *buf, size_t len)
+{
+       struct dsa_port *dp = dsa_net_device_to_dsa_port(to_net_dev(dev));
+       struct lan9303 *chip = dp->ds->priv;
+       int port = dp->index;
+       int ret;
+       unsigned long level;
+
+       ret = kstrtoul(buf, 0, &level);
+       if (ret)
+               return ret;
+       level &= 0xff; /* ensure valid range */
+       if (level)
+               level |= 0x100; /* Set enable bit  */
+
+       ret = lan9303_write_switch_reg_mask(chip, LAN9303_SWE_BCST_THROT,
+                                           level << (9 * port),
+                                           0x1ff << (9 * port));
+       if (ret)
+               return ret;
+       return len;
+}
+
+static DEVICE_ATTR_RW(swe_bcst_throt);
+
+static struct attribute *lan9303_attrs[] = {
+       &dev_attr_swe_bcst_throt.attr,
+       NULL
+};
+
+static struct attribute_group lan9303_group = {
+       .name = "lan9303",
+       .attrs = lan9303_attrs,
+};
+
 /* ---------------------------- DSA -----------------------------------*/
 
 static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds)
@@ -787,6 +862,11 @@ static int lan9303_port_enable(struct dsa_switch *ds, int 
port,
        switch (port) {
        case 1:
        case 2:
+               /* lan9303_setup is too early to attach sysfs nodes... */
+               if (sysfs_create_group(
+                               &ds->ports[port].netdev->dev.kobj,
+                               &lan9303_group))
+                       dev_dbg(chip->dev, "cannot create sysfs group\n");
                return lan9303_enable_packet_processing(chip, port);
        default:
                dev_dbg(chip->dev,
@@ -805,6 +885,9 @@ static void lan9303_port_disable(struct dsa_switch *ds, int 
port,
        switch (port) {
        case 1:
        case 2:
+               sysfs_remove_group(&ds->ports[port].netdev->dev.kobj,
+                                  &lan9303_group);
+
                lan9303_disable_packet_processing(chip, port);
                lan9303_phy_write(ds, chip->phy_addr_sel_strap + port,
                                  MII_BMCR, BMCR_PDOWN);
-- 
2.11.0

Reply via email to