net: dsa: mv88e6xxx: factorize EEPROM access
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>
Mon, 9 May 2016 17:22:41 +0000 (13:22 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 May 2016 18:26:09 +0000 (14:26 -0400)
Add a MV88E6XXX_FLAG_EEPROM flag to describe switch models featuring an
EEPROM and distribute the EEPROM access routines to all models.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6123.c
drivers/net/dsa/mv88e6131.c
drivers/net/dsa/mv88e6171.c
drivers/net/dsa/mv88e6352.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/dsa/mv88e6xxx.h

index ab5885b68a0742bbb1f5191a97c12cf1eb519e44..8330a8e34bff26306135f731b86c31b1e62ef9da 100644 (file)
@@ -124,6 +124,8 @@ struct dsa_switch_driver mv88e6123_switch_driver = {
 #ifdef CONFIG_NET_DSA_HWMON
        .get_temp               = mv88e6xxx_get_temp,
 #endif
+       .get_eeprom             = mv88e6xxx_get_eeprom,
+       .set_eeprom             = mv88e6xxx_set_eeprom,
        .get_regs_len           = mv88e6xxx_get_regs_len,
        .get_regs               = mv88e6xxx_get_regs,
 };
index 9d21d69de08a1c025ade0700dd71f30ab2b4c3b9..ab8c507b8f8c3036234506c55bc29db2e74b4839 100644 (file)
@@ -153,6 +153,8 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
        .get_strings            = mv88e6xxx_get_strings,
        .get_ethtool_stats      = mv88e6xxx_get_ethtool_stats,
        .get_sset_count         = mv88e6xxx_get_sset_count,
+       .get_eeprom             = mv88e6xxx_get_eeprom,
+       .set_eeprom             = mv88e6xxx_set_eeprom,
        .adjust_link            = mv88e6xxx_adjust_link,
        .port_bridge_join       = mv88e6xxx_port_bridge_join,
        .port_bridge_leave      = mv88e6xxx_port_bridge_leave,
index b190647d2a15d7682e25c5b52f9ba3b765749361..a7afbaa876181a1bff97e7d1f3744f567edbe368 100644 (file)
@@ -133,6 +133,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
 #ifdef CONFIG_NET_DSA_HWMON
        .get_temp               = mv88e6xxx_get_temp,
 #endif
+       .get_eeprom             = mv88e6xxx_get_eeprom,
+       .set_eeprom             = mv88e6xxx_set_eeprom,
        .get_regs_len           = mv88e6xxx_get_regs_len,
        .get_regs               = mv88e6xxx_get_regs,
        .port_bridge_join       = mv88e6xxx_port_bridge_join,
index 6fa7c02f9027cc74c120b20e9c06492a17a86873..3bb271e16035ca8a41e2532fc3f96ddf424d1f03 100644 (file)
@@ -125,8 +125,6 @@ static int mv88e6352_setup(struct dsa_switch *ds)
        if (ret < 0)
                return ret;
 
-       mutex_init(&ps->eeprom_mutex);
-
        ret = mv88e6xxx_switch_reset(ps, true);
        if (ret < 0)
                return ret;
@@ -138,207 +136,6 @@ static int mv88e6352_setup(struct dsa_switch *ds)
        return mv88e6xxx_setup_ports(ds);
 }
 
-static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
-{
-       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       int ret;
-
-       mutex_lock(&ps->eeprom_mutex);
-
-       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
-                                 GLOBAL2_EEPROM_OP_READ |
-                                 (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
-       if (ret < 0)
-               goto error;
-
-       ret = mv88e6xxx_eeprom_busy_wait(ds);
-       if (ret < 0)
-               goto error;
-
-       ret = mv88e6xxx_reg_read(ps, REG_GLOBAL2, GLOBAL2_EEPROM_DATA);
-error:
-       mutex_unlock(&ps->eeprom_mutex);
-       return ret;
-}
-
-static int mv88e6352_get_eeprom(struct dsa_switch *ds,
-                               struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int offset;
-       int len;
-       int ret;
-
-       offset = eeprom->offset;
-       len = eeprom->len;
-       eeprom->len = 0;
-
-       eeprom->magic = 0xc3ec4951;
-
-       ret = mv88e6xxx_eeprom_load_wait(ds);
-       if (ret < 0)
-               return ret;
-
-       if (offset & 1) {
-               int word;
-
-               word = mv88e6352_read_eeprom_word(ds, offset >> 1);
-               if (word < 0)
-                       return word;
-
-               *data++ = (word >> 8) & 0xff;
-
-               offset++;
-               len--;
-               eeprom->len++;
-       }
-
-       while (len >= 2) {
-               int word;
-
-               word = mv88e6352_read_eeprom_word(ds, offset >> 1);
-               if (word < 0)
-                       return word;
-
-               *data++ = word & 0xff;
-               *data++ = (word >> 8) & 0xff;
-
-               offset += 2;
-               len -= 2;
-               eeprom->len += 2;
-       }
-
-       if (len) {
-               int word;
-
-               word = mv88e6352_read_eeprom_word(ds, offset >> 1);
-               if (word < 0)
-                       return word;
-
-               *data++ = word & 0xff;
-
-               offset++;
-               len--;
-               eeprom->len++;
-       }
-
-       return 0;
-}
-
-static int mv88e6352_eeprom_is_readonly(struct dsa_switch *ds)
-{
-       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       int ret;
-
-       ret = mv88e6xxx_reg_read(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP);
-       if (ret < 0)
-               return ret;
-
-       if (!(ret & GLOBAL2_EEPROM_OP_WRITE_EN))
-               return -EROFS;
-
-       return 0;
-}
-
-static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr,
-                                      u16 data)
-{
-       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       int ret;
-
-       mutex_lock(&ps->eeprom_mutex);
-
-       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data);
-       if (ret < 0)
-               goto error;
-
-       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
-                                 GLOBAL2_EEPROM_OP_WRITE |
-                                 (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
-       if (ret < 0)
-               goto error;
-
-       ret = mv88e6xxx_eeprom_busy_wait(ds);
-error:
-       mutex_unlock(&ps->eeprom_mutex);
-       return ret;
-}
-
-static int mv88e6352_set_eeprom(struct dsa_switch *ds,
-                               struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int offset;
-       int ret;
-       int len;
-
-       if (eeprom->magic != 0xc3ec4951)
-               return -EINVAL;
-
-       ret = mv88e6352_eeprom_is_readonly(ds);
-       if (ret)
-               return ret;
-
-       offset = eeprom->offset;
-       len = eeprom->len;
-       eeprom->len = 0;
-
-       ret = mv88e6xxx_eeprom_load_wait(ds);
-       if (ret < 0)
-               return ret;
-
-       if (offset & 1) {
-               int word;
-
-               word = mv88e6352_read_eeprom_word(ds, offset >> 1);
-               if (word < 0)
-                       return word;
-
-               word = (*data++ << 8) | (word & 0xff);
-
-               ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
-               if (ret < 0)
-                       return ret;
-
-               offset++;
-               len--;
-               eeprom->len++;
-       }
-
-       while (len >= 2) {
-               int word;
-
-               word = *data++;
-               word |= *data++ << 8;
-
-               ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
-               if (ret < 0)
-                       return ret;
-
-               offset += 2;
-               len -= 2;
-               eeprom->len += 2;
-       }
-
-       if (len) {
-               int word;
-
-               word = mv88e6352_read_eeprom_word(ds, offset >> 1);
-               if (word < 0)
-                       return word;
-
-               word = (word & 0xff00) | *data++;
-
-               ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
-               if (ret < 0)
-                       return ret;
-
-               offset++;
-               len--;
-               eeprom->len++;
-       }
-
-       return 0;
-}
-
 struct dsa_switch_driver mv88e6352_switch_driver = {
        .tag_protocol           = DSA_TAG_PROTO_EDSA,
        .probe                  = mv88e6352_drv_probe,
@@ -358,8 +155,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
        .set_temp_limit         = mv88e6xxx_set_temp_limit,
        .get_temp_alarm         = mv88e6xxx_get_temp_alarm,
 #endif
-       .get_eeprom             = mv88e6352_get_eeprom,
-       .set_eeprom             = mv88e6352_set_eeprom,
+       .get_eeprom             = mv88e6xxx_get_eeprom,
+       .set_eeprom             = mv88e6xxx_set_eeprom,
        .get_regs_len           = mv88e6xxx_get_regs_len,
        .get_regs               = mv88e6xxx_get_regs,
        .port_bridge_join       = mv88e6xxx_port_bridge_join,
index 2c8c5e1d16bce59029bad334ab004115f953e125..d277350069d07676a10b6b9901811f4cd0744bfd 100644 (file)
@@ -823,7 +823,7 @@ static int _mv88e6xxx_phy_wait(struct mv88e6xxx_priv_state *ps)
                               GLOBAL2_SMI_OP_BUSY);
 }
 
-int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
+static int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
@@ -831,7 +831,7 @@ int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
                              GLOBAL2_EEPROM_OP_LOAD);
 }
 
-int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
+static int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
@@ -839,6 +839,215 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
                              GLOBAL2_EEPROM_OP_BUSY);
 }
 
+static int mv88e6xxx_read_eeprom_word(struct dsa_switch *ds, int addr)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       int ret;
+
+       mutex_lock(&ps->eeprom_mutex);
+
+       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
+                                 GLOBAL2_EEPROM_OP_READ |
+                                 (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
+       if (ret < 0)
+               goto error;
+
+       ret = mv88e6xxx_eeprom_busy_wait(ds);
+       if (ret < 0)
+               goto error;
+
+       ret = mv88e6xxx_reg_read(ps, REG_GLOBAL2, GLOBAL2_EEPROM_DATA);
+error:
+       mutex_unlock(&ps->eeprom_mutex);
+       return ret;
+}
+
+int mv88e6xxx_get_eeprom(struct dsa_switch *ds, struct ethtool_eeprom *eeprom,
+                        u8 *data)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       int offset;
+       int len;
+       int ret;
+
+       if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM))
+               return -EOPNOTSUPP;
+
+       offset = eeprom->offset;
+       len = eeprom->len;
+       eeprom->len = 0;
+
+       eeprom->magic = 0xc3ec4951;
+
+       ret = mv88e6xxx_eeprom_load_wait(ds);
+       if (ret < 0)
+               return ret;
+
+       if (offset & 1) {
+               int word;
+
+               word = mv88e6xxx_read_eeprom_word(ds, offset >> 1);
+               if (word < 0)
+                       return word;
+
+               *data++ = (word >> 8) & 0xff;
+
+               offset++;
+               len--;
+               eeprom->len++;
+       }
+
+       while (len >= 2) {
+               int word;
+
+               word = mv88e6xxx_read_eeprom_word(ds, offset >> 1);
+               if (word < 0)
+                       return word;
+
+               *data++ = word & 0xff;
+               *data++ = (word >> 8) & 0xff;
+
+               offset += 2;
+               len -= 2;
+               eeprom->len += 2;
+       }
+
+       if (len) {
+               int word;
+
+               word = mv88e6xxx_read_eeprom_word(ds, offset >> 1);
+               if (word < 0)
+                       return word;
+
+               *data++ = word & 0xff;
+
+               offset++;
+               len--;
+               eeprom->len++;
+       }
+
+       return 0;
+}
+
+static int mv88e6xxx_eeprom_is_readonly(struct dsa_switch *ds)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       int ret;
+
+       ret = mv88e6xxx_reg_read(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP);
+       if (ret < 0)
+               return ret;
+
+       if (!(ret & GLOBAL2_EEPROM_OP_WRITE_EN))
+               return -EROFS;
+
+       return 0;
+}
+
+static int mv88e6xxx_write_eeprom_word(struct dsa_switch *ds, int addr,
+                                      u16 data)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       int ret;
+
+       mutex_lock(&ps->eeprom_mutex);
+
+       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data);
+       if (ret < 0)
+               goto error;
+
+       ret = mv88e6xxx_reg_write(ps, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
+                                 GLOBAL2_EEPROM_OP_WRITE |
+                                 (addr & GLOBAL2_EEPROM_OP_ADDR_MASK));
+       if (ret < 0)
+               goto error;
+
+       ret = mv88e6xxx_eeprom_busy_wait(ds);
+error:
+       mutex_unlock(&ps->eeprom_mutex);
+       return ret;
+}
+
+int mv88e6xxx_set_eeprom(struct dsa_switch *ds, struct ethtool_eeprom *eeprom,
+                        u8 *data)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       int offset;
+       int ret;
+       int len;
+
+       if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM))
+               return -EOPNOTSUPP;
+
+       if (eeprom->magic != 0xc3ec4951)
+               return -EINVAL;
+
+       ret = mv88e6xxx_eeprom_is_readonly(ds);
+       if (ret)
+               return ret;
+
+       offset = eeprom->offset;
+       len = eeprom->len;
+       eeprom->len = 0;
+
+       ret = mv88e6xxx_eeprom_load_wait(ds);
+       if (ret < 0)
+               return ret;
+
+       if (offset & 1) {
+               int word;
+
+               word = mv88e6xxx_read_eeprom_word(ds, offset >> 1);
+               if (word < 0)
+                       return word;
+
+               word = (*data++ << 8) | (word & 0xff);
+
+               ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word);
+               if (ret < 0)
+                       return ret;
+
+               offset++;
+               len--;
+               eeprom->len++;
+       }
+
+       while (len >= 2) {
+               int word;
+
+               word = *data++;
+               word |= *data++ << 8;
+
+               ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word);
+               if (ret < 0)
+                       return ret;
+
+               offset += 2;
+               len -= 2;
+               eeprom->len += 2;
+       }
+
+       if (len) {
+               int word;
+
+               word = mv88e6xxx_read_eeprom_word(ds, offset >> 1);
+               if (word < 0)
+                       return word;
+
+               word = (word & 0xff00) | *data++;
+
+               ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word);
+               if (ret < 0)
+                       return ret;
+
+               offset++;
+               len--;
+               eeprom->len++;
+       }
+
+       return 0;
+}
+
 static int _mv88e6xxx_atu_wait(struct mv88e6xxx_priv_state *ps)
 {
        return _mv88e6xxx_wait(ps, REG_GLOBAL, GLOBAL_ATU_OP,
@@ -2596,6 +2805,9 @@ int mv88e6xxx_setup_common(struct mv88e6xxx_priv_state *ps)
 
        INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
 
+       if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM))
+               mutex_init(&ps->eeprom_mutex);
+
        if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU))
                mv88e6xxx_ppu_state_init(ps);
 
index 597257123ca77e816b90b1aaaf154f121aefa5e6..0181f6775bfcbe0621d36879549378b39d3947f6 100644 (file)
@@ -351,6 +351,11 @@ enum mv88e6xxx_family {
 };
 
 enum mv88e6xxx_cap {
+       /* EEPROM Command and Data registers.
+        * See GLOBAL2_EEPROM_OP and GLOBAL2_EEPROM_DATA.
+        */
+       MV88E6XXX_CAP_EEPROM,
+
        /* PHY Polling Unit.
         * See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING.
         */
@@ -364,6 +369,7 @@ enum mv88e6xxx_cap {
 };
 
 /* Bitmask of capabilities */
+#define MV88E6XXX_FLAG_EEPROM          BIT(MV88E6XXX_CAP_EEPROM)
 #define MV88E6XXX_FLAG_PPU             BIT(MV88E6XXX_CAP_PPU)
 #define MV88E6XXX_FLAG_SMI_PHY         BIT(MV88E6XXX_CAP_SMI_PHY)
 
@@ -379,13 +385,15 @@ enum mv88e6xxx_cap {
        MV88E6XXX_FLAG_PPU
 
 #define MV88E6XXX_FLAGS_FAMILY_6320    \
-       MV88E6XXX_FLAG_SMI_PHY
+       (MV88E6XXX_FLAG_EEPROM |        \
+        MV88E6XXX_FLAG_SMI_PHY)
 
 #define MV88E6XXX_FLAGS_FAMILY_6351    \
        MV88E6XXX_FLAG_SMI_PHY
 
 #define MV88E6XXX_FLAGS_FAMILY_6352    \
-       MV88E6XXX_FLAG_SMI_PHY
+       (MV88E6XXX_FLAG_EEPROM |        \
+        MV88E6XXX_FLAG_SMI_PHY)
 
 struct mv88e6xxx_info {
        enum mv88e6xxx_family family;
@@ -521,8 +529,10 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp);
 int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp);
 int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp);
 int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm);
-int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds);
-int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds);
+int mv88e6xxx_get_eeprom(struct dsa_switch *ds, struct ethtool_eeprom *eeprom,
+                        u8 *data);
+int mv88e6xxx_set_eeprom(struct dsa_switch *ds, struct ethtool_eeprom *eeprom,
+                        u8 *data);
 int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
 int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
                      struct phy_device *phydev, struct ethtool_eee *e);