diff options
| author | David S. Miller <davem@davemloft.net> | 2019-04-27 20:23:05 -0400 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2019-04-27 20:23:05 -0400 | 
| commit | 6acda8fbbda585acc44efd0f66f34a21b4dd2d31 (patch) | |
| tree | a107bd7eb2f574134373ea062d8924bd49a8f9f8 | |
| parent | e56e2515669af9f2444228db39699d02c5a4989a (diff) | |
| parent | 1ba22bf547a3c92d3e6c5c8d3e3ebe48a7bc26b3 (diff) | |
Merge branch 'mv88e6060-cleanups'
Andrew Lunn says:
====================
mv88e6060 cleanups
This patchset performs some cleanups of the mv88e6060 DSA driver, as a
step towards making it an MDIO device, rather than use the old probing
method. The changes here are all pretty mechanical and only compile
tested.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/dsa/mv88e6060.c | 132 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6060.h | 1 | 
2 files changed, 67 insertions, 66 deletions
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 0b3e51f248c2..4ca06b3b9d4f 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c  | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 1 | /* | 2 | /* | 
| 2 | * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips | 3 | * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips | 
| 3 | * Copyright (c) 2008-2009 Marvell Semiconductor | 4 | * Copyright (c) 2008-2009 Marvell Semiconductor | 
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | */ | 5 | */ | 
| 10 | 6 | ||
| 11 | #include <linux/delay.h> | 7 | #include <linux/delay.h> | 
| @@ -18,40 +14,16 @@ | |||
| 18 | #include <net/dsa.h> | 14 | #include <net/dsa.h> | 
| 19 | #include "mv88e6060.h" | 15 | #include "mv88e6060.h" | 
| 20 | 16 | ||
| 21 | static int reg_read(struct dsa_switch *ds, int addr, int reg) | 17 | static int reg_read(struct mv88e6060_priv *priv, int addr, int reg) | 
| 22 | { | 18 | { | 
| 23 | struct mv88e6060_priv *priv = ds->priv; | ||
| 24 | |||
| 25 | return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg); | 19 | return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg); | 
| 26 | } | 20 | } | 
| 27 | 21 | ||
| 28 | #define REG_READ(addr, reg) \ | 22 | static int reg_write(struct mv88e6060_priv *priv, int addr, int reg, u16 val) | 
| 29 | ({ \ | ||
| 30 | int __ret; \ | ||
| 31 | \ | ||
| 32 | __ret = reg_read(ds, addr, reg); \ | ||
| 33 | if (__ret < 0) \ | ||
| 34 | return __ret; \ | ||
| 35 | __ret; \ | ||
| 36 | }) | ||
| 37 | |||
| 38 | |||
| 39 | static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) | ||
| 40 | { | 23 | { | 
| 41 | struct mv88e6060_priv *priv = ds->priv; | ||
| 42 | |||
| 43 | return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val); | 24 | return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val); | 
| 44 | } | 25 | } | 
| 45 | 26 | ||
| 46 | #define REG_WRITE(addr, reg, val) \ | ||
| 47 | ({ \ | ||
| 48 | int __ret; \ | ||
| 49 | \ | ||
| 50 | __ret = reg_write(ds, addr, reg, val); \ | ||
| 51 | if (__ret < 0) \ | ||
| 52 | return __ret; \ | ||
| 53 | }) | ||
| 54 | |||
| 55 | static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr) | 27 | static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr) | 
| 56 | { | 28 | { | 
| 57 | int ret; | 29 | int ret; | 
| @@ -97,7 +69,7 @@ static const char *mv88e6060_drv_probe(struct device *dsa_dev, | |||
| 97 | return name; | 69 | return name; | 
| 98 | } | 70 | } | 
| 99 | 71 | ||
| 100 | static int mv88e6060_switch_reset(struct dsa_switch *ds) | 72 | static int mv88e6060_switch_reset(struct mv88e6060_priv *priv) | 
| 101 | { | 73 | { | 
| 102 | int i; | 74 | int i; | 
| 103 | int ret; | 75 | int ret; | 
| @@ -105,23 +77,32 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds) | |||
| 105 | 77 | ||
| 106 | /* Set all ports to the disabled state. */ | 78 | /* Set all ports to the disabled state. */ | 
| 107 | for (i = 0; i < MV88E6060_PORTS; i++) { | 79 | for (i = 0; i < MV88E6060_PORTS; i++) { | 
| 108 | ret = REG_READ(REG_PORT(i), PORT_CONTROL); | 80 | ret = reg_read(priv, REG_PORT(i), PORT_CONTROL); | 
| 109 | REG_WRITE(REG_PORT(i), PORT_CONTROL, | 81 | if (ret < 0) | 
| 110 | ret & ~PORT_CONTROL_STATE_MASK); | 82 | return ret; | 
| 83 | ret = reg_write(priv, REG_PORT(i), PORT_CONTROL, | ||
| 84 | ret & ~PORT_CONTROL_STATE_MASK); | ||
| 85 | if (ret) | ||
| 86 | return ret; | ||
| 111 | } | 87 | } | 
| 112 | 88 | ||
| 113 | /* Wait for transmit queues to drain. */ | 89 | /* Wait for transmit queues to drain. */ | 
| 114 | usleep_range(2000, 4000); | 90 | usleep_range(2000, 4000); | 
| 115 | 91 | ||
| 116 | /* Reset the switch. */ | 92 | /* Reset the switch. */ | 
| 117 | REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, | 93 | ret = reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL, | 
| 118 | GLOBAL_ATU_CONTROL_SWRESET | | 94 | GLOBAL_ATU_CONTROL_SWRESET | | 
| 119 | GLOBAL_ATU_CONTROL_LEARNDIS); | 95 | GLOBAL_ATU_CONTROL_LEARNDIS); | 
| 96 | if (ret) | ||
| 97 | return ret; | ||
| 120 | 98 | ||
| 121 | /* Wait up to one second for reset to complete. */ | 99 | /* Wait up to one second for reset to complete. */ | 
| 122 | timeout = jiffies + 1 * HZ; | 100 | timeout = jiffies + 1 * HZ; | 
| 123 | while (time_before(jiffies, timeout)) { | 101 | while (time_before(jiffies, timeout)) { | 
| 124 | ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); | 102 | ret = reg_read(priv, REG_GLOBAL, GLOBAL_STATUS); | 
| 103 | if (ret < 0) | ||
| 104 | return ret; | ||
| 105 | |||
| 125 | if (ret & GLOBAL_STATUS_INIT_READY) | 106 | if (ret & GLOBAL_STATUS_INIT_READY) | 
| 126 | break; | 107 | break; | 
| 127 | 108 | ||
| @@ -133,61 +114,69 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds) | |||
| 133 | return 0; | 114 | return 0; | 
| 134 | } | 115 | } | 
| 135 | 116 | ||
| 136 | static int mv88e6060_setup_global(struct dsa_switch *ds) | 117 | static int mv88e6060_setup_global(struct mv88e6060_priv *priv) | 
| 137 | { | 118 | { | 
| 119 | int ret; | ||
| 120 | |||
| 138 | /* Disable discarding of frames with excessive collisions, | 121 | /* Disable discarding of frames with excessive collisions, | 
| 139 | * set the maximum frame size to 1536 bytes, and mask all | 122 | * set the maximum frame size to 1536 bytes, and mask all | 
| 140 | * interrupt sources. | 123 | * interrupt sources. | 
| 141 | */ | 124 | */ | 
| 142 | REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536); | 125 | ret = reg_write(priv, REG_GLOBAL, GLOBAL_CONTROL, | 
| 126 | GLOBAL_CONTROL_MAX_FRAME_1536); | ||
| 127 | if (ret) | ||
| 128 | return ret; | ||
| 143 | 129 | ||
| 144 | /* Disable automatic address learning. | 130 | /* Disable automatic address learning. | 
| 145 | */ | 131 | */ | 
| 146 | REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, | 132 | return reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL, | 
| 147 | GLOBAL_ATU_CONTROL_LEARNDIS); | 133 | GLOBAL_ATU_CONTROL_LEARNDIS); | 
| 148 | |||
| 149 | return 0; | ||
| 150 | } | 134 | } | 
| 151 | 135 | ||
| 152 | static int mv88e6060_setup_port(struct dsa_switch *ds, int p) | 136 | static int mv88e6060_setup_port(struct mv88e6060_priv *priv, int p) | 
| 153 | { | 137 | { | 
| 154 | int addr = REG_PORT(p); | 138 | int addr = REG_PORT(p); | 
| 139 | int ret; | ||
| 155 | 140 | ||
| 156 | /* Do not force flow control, disable Ingress and Egress | 141 | /* Do not force flow control, disable Ingress and Egress | 
| 157 | * Header tagging, disable VLAN tunneling, and set the port | 142 | * Header tagging, disable VLAN tunneling, and set the port | 
| 158 | * state to Forwarding. Additionally, if this is the CPU | 143 | * state to Forwarding. Additionally, if this is the CPU | 
| 159 | * port, enable Ingress and Egress Trailer tagging mode. | 144 | * port, enable Ingress and Egress Trailer tagging mode. | 
| 160 | */ | 145 | */ | 
| 161 | REG_WRITE(addr, PORT_CONTROL, | 146 | ret = reg_write(priv, addr, PORT_CONTROL, | 
| 162 | dsa_is_cpu_port(ds, p) ? | 147 | dsa_is_cpu_port(priv->ds, p) ? | 
| 163 | PORT_CONTROL_TRAILER | | 148 | PORT_CONTROL_TRAILER | | 
| 164 | PORT_CONTROL_INGRESS_MODE | | 149 | PORT_CONTROL_INGRESS_MODE | | 
| 165 | PORT_CONTROL_STATE_FORWARDING : | 150 | PORT_CONTROL_STATE_FORWARDING : | 
| 166 | PORT_CONTROL_STATE_FORWARDING); | 151 | PORT_CONTROL_STATE_FORWARDING); | 
| 152 | if (ret) | ||
| 153 | return ret; | ||
| 167 | 154 | ||
| 168 | /* Port based VLAN map: give each port its own address | 155 | /* Port based VLAN map: give each port its own address | 
| 169 | * database, allow the CPU port to talk to each of the 'real' | 156 | * database, allow the CPU port to talk to each of the 'real' | 
| 170 | * ports, and allow each of the 'real' ports to only talk to | 157 | * ports, and allow each of the 'real' ports to only talk to | 
| 171 | * the CPU port. | 158 | * the CPU port. | 
| 172 | */ | 159 | */ | 
| 173 | REG_WRITE(addr, PORT_VLAN_MAP, | 160 | ret = reg_write(priv, addr, PORT_VLAN_MAP, | 
| 174 | ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | | 161 | ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | | 
| 175 | (dsa_is_cpu_port(ds, p) ? dsa_user_ports(ds) : | 162 | (dsa_is_cpu_port(priv->ds, p) ? | 
| 176 | BIT(dsa_to_port(ds, p)->cpu_dp->index))); | 163 | dsa_user_ports(priv->ds) : | 
| 164 | BIT(dsa_to_port(priv->ds, p)->cpu_dp->index))); | ||
| 165 | if (ret) | ||
| 166 | return ret; | ||
| 177 | 167 | ||
| 178 | /* Port Association Vector: when learning source addresses | 168 | /* Port Association Vector: when learning source addresses | 
| 179 | * of packets, add the address to the address database using | 169 | * of packets, add the address to the address database using | 
| 180 | * a port bitmap that has only the bit for this port set and | 170 | * a port bitmap that has only the bit for this port set and | 
| 181 | * the other bits clear. | 171 | * the other bits clear. | 
| 182 | */ | 172 | */ | 
| 183 | REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p)); | 173 | return reg_write(priv, addr, PORT_ASSOC_VECTOR, BIT(p)); | 
| 184 | |||
| 185 | return 0; | ||
| 186 | } | 174 | } | 
| 187 | 175 | ||
| 188 | static int mv88e6060_setup_addr(struct dsa_switch *ds) | 176 | static int mv88e6060_setup_addr(struct mv88e6060_priv *priv) | 
| 189 | { | 177 | { | 
| 190 | u8 addr[ETH_ALEN]; | 178 | u8 addr[ETH_ALEN]; | 
| 179 | int ret; | ||
| 191 | u16 val; | 180 | u16 val; | 
| 192 | 181 | ||
| 193 | eth_random_addr(addr); | 182 | eth_random_addr(addr); | 
| @@ -199,34 +188,43 @@ static int mv88e6060_setup_addr(struct dsa_switch *ds) | |||
| 199 | */ | 188 | */ | 
| 200 | val &= 0xfeff; | 189 | val &= 0xfeff; | 
| 201 | 190 | ||
| 202 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, val); | 191 | ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_01, val); | 
| 203 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); | 192 | if (ret) | 
| 204 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); | 193 | return ret; | 
| 205 | 194 | ||
| 206 | return 0; | 195 | ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_23, | 
| 196 | (addr[2] << 8) | addr[3]); | ||
| 197 | if (ret) | ||
| 198 | return ret; | ||
| 199 | |||
| 200 | return reg_write(priv, REG_GLOBAL, GLOBAL_MAC_45, | ||
| 201 | (addr[4] << 8) | addr[5]); | ||
| 207 | } | 202 | } | 
| 208 | 203 | ||
| 209 | static int mv88e6060_setup(struct dsa_switch *ds) | 204 | static int mv88e6060_setup(struct dsa_switch *ds) | 
| 210 | { | 205 | { | 
| 206 | struct mv88e6060_priv *priv = ds->priv; | ||
| 211 | int ret; | 207 | int ret; | 
| 212 | int i; | 208 | int i; | 
| 213 | 209 | ||
| 214 | ret = mv88e6060_switch_reset(ds); | 210 | priv->ds = ds; | 
| 211 | |||
| 212 | ret = mv88e6060_switch_reset(priv); | ||
| 215 | if (ret < 0) | 213 | if (ret < 0) | 
| 216 | return ret; | 214 | return ret; | 
| 217 | 215 | ||
| 218 | /* @@@ initialise atu */ | 216 | /* @@@ initialise atu */ | 
| 219 | 217 | ||
| 220 | ret = mv88e6060_setup_global(ds); | 218 | ret = mv88e6060_setup_global(priv); | 
| 221 | if (ret < 0) | 219 | if (ret < 0) | 
| 222 | return ret; | 220 | return ret; | 
| 223 | 221 | ||
| 224 | ret = mv88e6060_setup_addr(ds); | 222 | ret = mv88e6060_setup_addr(priv); | 
| 225 | if (ret < 0) | 223 | if (ret < 0) | 
| 226 | return ret; | 224 | return ret; | 
| 227 | 225 | ||
| 228 | for (i = 0; i < MV88E6060_PORTS; i++) { | 226 | for (i = 0; i < MV88E6060_PORTS; i++) { | 
| 229 | ret = mv88e6060_setup_port(ds, i); | 227 | ret = mv88e6060_setup_port(priv, i); | 
| 230 | if (ret < 0) | 228 | if (ret < 0) | 
| 231 | return ret; | 229 | return ret; | 
| 232 | } | 230 | } | 
| @@ -243,25 +241,27 @@ static int mv88e6060_port_to_phy_addr(int port) | |||
| 243 | 241 | ||
| 244 | static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum) | 242 | static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum) | 
| 245 | { | 243 | { | 
| 244 | struct mv88e6060_priv *priv = ds->priv; | ||
| 246 | int addr; | 245 | int addr; | 
| 247 | 246 | ||
| 248 | addr = mv88e6060_port_to_phy_addr(port); | 247 | addr = mv88e6060_port_to_phy_addr(port); | 
| 249 | if (addr == -1) | 248 | if (addr == -1) | 
| 250 | return 0xffff; | 249 | return 0xffff; | 
| 251 | 250 | ||
| 252 | return reg_read(ds, addr, regnum); | 251 | return reg_read(priv, addr, regnum); | 
| 253 | } | 252 | } | 
| 254 | 253 | ||
| 255 | static int | 254 | static int | 
| 256 | mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | 255 | mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | 
| 257 | { | 256 | { | 
| 257 | struct mv88e6060_priv *priv = ds->priv; | ||
| 258 | int addr; | 258 | int addr; | 
| 259 | 259 | ||
| 260 | addr = mv88e6060_port_to_phy_addr(port); | 260 | addr = mv88e6060_port_to_phy_addr(port); | 
| 261 | if (addr == -1) | 261 | if (addr == -1) | 
| 262 | return 0xffff; | 262 | return 0xffff; | 
| 263 | 263 | ||
| 264 | return reg_write(ds, addr, regnum, val); | 264 | return reg_write(priv, addr, regnum, val); | 
| 265 | } | 265 | } | 
| 266 | 266 | ||
| 267 | static const struct dsa_switch_ops mv88e6060_switch_ops = { | 267 | static const struct dsa_switch_ops mv88e6060_switch_ops = { | 
diff --git a/drivers/net/dsa/mv88e6060.h b/drivers/net/dsa/mv88e6060.h index 10249bd16292..c0e7a0f2fb6a 100644 --- a/drivers/net/dsa/mv88e6060.h +++ b/drivers/net/dsa/mv88e6060.h  | |||
| @@ -117,6 +117,7 @@ struct mv88e6060_priv { | |||
| 117 | */ | 117 | */ | 
| 118 | struct mii_bus *bus; | 118 | struct mii_bus *bus; | 
| 119 | int sw_addr; | 119 | int sw_addr; | 
| 120 | struct dsa_switch *ds; | ||
| 120 | }; | 121 | }; | 
| 121 | 122 | ||
| 122 | #endif | 123 | #endif | 
