diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6060.c')
-rw-r--r-- | drivers/net/dsa/mv88e6060.c | 114 |
1 files changed, 38 insertions, 76 deletions
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 9093577755f6..0527f485c3dc 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c | |||
@@ -15,9 +15,7 @@ | |||
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/phy.h> | 16 | #include <linux/phy.h> |
17 | #include <net/dsa.h> | 17 | #include <net/dsa.h> |
18 | 18 | #include "mv88e6060.h" | |
19 | #define REG_PORT(p) (8 + (p)) | ||
20 | #define REG_GLOBAL 0x0f | ||
21 | 19 | ||
22 | static int reg_read(struct dsa_switch *ds, int addr, int reg) | 20 | static int reg_read(struct dsa_switch *ds, int addr, int reg) |
23 | { | 21 | { |
@@ -67,13 +65,14 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr) | |||
67 | if (bus == NULL) | 65 | if (bus == NULL) |
68 | return NULL; | 66 | return NULL; |
69 | 67 | ||
70 | ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03); | 68 | ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID); |
71 | if (ret >= 0) { | 69 | if (ret >= 0) { |
72 | if (ret == 0x0600) | 70 | if (ret == PORT_SWITCH_ID_6060) |
73 | return "Marvell 88E6060 (A0)"; | 71 | return "Marvell 88E6060 (A0)"; |
74 | if (ret == 0x0601 || ret == 0x0602) | 72 | if (ret == PORT_SWITCH_ID_6060_R1 || |
73 | ret == PORT_SWITCH_ID_6060_R2) | ||
75 | return "Marvell 88E6060 (B0)"; | 74 | return "Marvell 88E6060 (B0)"; |
76 | if ((ret & 0xfff0) == 0x0600) | 75 | if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060) |
77 | return "Marvell 88E6060"; | 76 | return "Marvell 88E6060"; |
78 | } | 77 | } |
79 | 78 | ||
@@ -87,22 +86,26 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds) | |||
87 | unsigned long timeout; | 86 | unsigned long timeout; |
88 | 87 | ||
89 | /* Set all ports to the disabled state. */ | 88 | /* Set all ports to the disabled state. */ |
90 | for (i = 0; i < 6; i++) { | 89 | for (i = 0; i < MV88E6060_PORTS; i++) { |
91 | ret = REG_READ(REG_PORT(i), 0x04); | 90 | ret = REG_READ(REG_PORT(i), PORT_CONTROL); |
92 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | 91 | REG_WRITE(REG_PORT(i), PORT_CONTROL, |
92 | ret & ~PORT_CONTROL_STATE_MASK); | ||
93 | } | 93 | } |
94 | 94 | ||
95 | /* Wait for transmit queues to drain. */ | 95 | /* Wait for transmit queues to drain. */ |
96 | usleep_range(2000, 4000); | 96 | usleep_range(2000, 4000); |
97 | 97 | ||
98 | /* Reset the switch. */ | 98 | /* Reset the switch. */ |
99 | REG_WRITE(REG_GLOBAL, 0x0a, 0xa130); | 99 | REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, |
100 | GLOBAL_ATU_CONTROL_SWRESET | | ||
101 | GLOBAL_ATU_CONTROL_ATUSIZE_1024 | | ||
102 | GLOBAL_ATU_CONTROL_ATE_AGE_5MIN); | ||
100 | 103 | ||
101 | /* Wait up to one second for reset to complete. */ | 104 | /* Wait up to one second for reset to complete. */ |
102 | timeout = jiffies + 1 * HZ; | 105 | timeout = jiffies + 1 * HZ; |
103 | while (time_before(jiffies, timeout)) { | 106 | while (time_before(jiffies, timeout)) { |
104 | ret = REG_READ(REG_GLOBAL, 0x00); | 107 | ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); |
105 | if ((ret & 0x8000) == 0x0000) | 108 | if (ret & GLOBAL_STATUS_INIT_READY) |
106 | break; | 109 | break; |
107 | 110 | ||
108 | usleep_range(1000, 2000); | 111 | usleep_range(1000, 2000); |
@@ -119,13 +122,15 @@ static int mv88e6060_setup_global(struct dsa_switch *ds) | |||
119 | * set the maximum frame size to 1536 bytes, and mask all | 122 | * set the maximum frame size to 1536 bytes, and mask all |
120 | * interrupt sources. | 123 | * interrupt sources. |
121 | */ | 124 | */ |
122 | REG_WRITE(REG_GLOBAL, 0x04, 0x0800); | 125 | REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536); |
123 | 126 | ||
124 | /* Enable automatic address learning, set the address | 127 | /* Enable automatic address learning, set the address |
125 | * database size to 1024 entries, and set the default aging | 128 | * database size to 1024 entries, and set the default aging |
126 | * time to 5 minutes. | 129 | * time to 5 minutes. |
127 | */ | 130 | */ |
128 | REG_WRITE(REG_GLOBAL, 0x0a, 0x2130); | 131 | REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, |
132 | GLOBAL_ATU_CONTROL_ATUSIZE_1024 | | ||
133 | GLOBAL_ATU_CONTROL_ATE_AGE_5MIN); | ||
129 | 134 | ||
130 | return 0; | 135 | return 0; |
131 | } | 136 | } |
@@ -139,25 +144,30 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) | |||
139 | * state to Forwarding. Additionally, if this is the CPU | 144 | * state to Forwarding. Additionally, if this is the CPU |
140 | * port, enable Ingress and Egress Trailer tagging mode. | 145 | * port, enable Ingress and Egress Trailer tagging mode. |
141 | */ | 146 | */ |
142 | REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003); | 147 | REG_WRITE(addr, PORT_CONTROL, |
148 | dsa_is_cpu_port(ds, p) ? | ||
149 | PORT_CONTROL_TRAILER | | ||
150 | PORT_CONTROL_INGRESS_MODE | | ||
151 | PORT_CONTROL_STATE_FORWARDING : | ||
152 | PORT_CONTROL_STATE_FORWARDING); | ||
143 | 153 | ||
144 | /* Port based VLAN map: give each port its own address | 154 | /* Port based VLAN map: give each port its own address |
145 | * database, allow the CPU port to talk to each of the 'real' | 155 | * database, allow the CPU port to talk to each of the 'real' |
146 | * ports, and allow each of the 'real' ports to only talk to | 156 | * ports, and allow each of the 'real' ports to only talk to |
147 | * the CPU port. | 157 | * the CPU port. |
148 | */ | 158 | */ |
149 | REG_WRITE(addr, 0x06, | 159 | REG_WRITE(addr, PORT_VLAN_MAP, |
150 | ((p & 0xf) << 12) | | 160 | ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | |
151 | (dsa_is_cpu_port(ds, p) ? | 161 | (dsa_is_cpu_port(ds, p) ? |
152 | ds->phys_port_mask : | 162 | ds->phys_port_mask : |
153 | (1 << ds->dst->cpu_port))); | 163 | BIT(ds->dst->cpu_port))); |
154 | 164 | ||
155 | /* Port Association Vector: when learning source addresses | 165 | /* Port Association Vector: when learning source addresses |
156 | * of packets, add the address to the address database using | 166 | * of packets, add the address to the address database using |
157 | * a port bitmap that has only the bit for this port set and | 167 | * a port bitmap that has only the bit for this port set and |
158 | * the other bits clear. | 168 | * the other bits clear. |
159 | */ | 169 | */ |
160 | REG_WRITE(addr, 0x0b, 1 << p); | 170 | REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p)); |
161 | 171 | ||
162 | return 0; | 172 | return 0; |
163 | } | 173 | } |
@@ -177,7 +187,7 @@ static int mv88e6060_setup(struct dsa_switch *ds) | |||
177 | if (ret < 0) | 187 | if (ret < 0) |
178 | return ret; | 188 | return ret; |
179 | 189 | ||
180 | for (i = 0; i < 6; i++) { | 190 | for (i = 0; i < MV88E6060_PORTS; i++) { |
181 | ret = mv88e6060_setup_port(ds, i); | 191 | ret = mv88e6060_setup_port(ds, i); |
182 | if (ret < 0) | 192 | if (ret < 0) |
183 | return ret; | 193 | return ret; |
@@ -188,16 +198,17 @@ static int mv88e6060_setup(struct dsa_switch *ds) | |||
188 | 198 | ||
189 | static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr) | 199 | static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr) |
190 | { | 200 | { |
191 | REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); | 201 | /* Use the same MAC Address as FD Pause frames for all ports */ |
192 | REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); | 202 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 9) | addr[1]); |
193 | REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); | 203 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); |
204 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); | ||
194 | 205 | ||
195 | return 0; | 206 | return 0; |
196 | } | 207 | } |
197 | 208 | ||
198 | static int mv88e6060_port_to_phy_addr(int port) | 209 | static int mv88e6060_port_to_phy_addr(int port) |
199 | { | 210 | { |
200 | if (port >= 0 && port <= 5) | 211 | if (port >= 0 && port < MV88E6060_PORTS) |
201 | return port; | 212 | return port; |
202 | return -1; | 213 | return -1; |
203 | } | 214 | } |
@@ -225,54 +236,6 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | |||
225 | return reg_write(ds, addr, regnum, val); | 236 | return reg_write(ds, addr, regnum, val); |
226 | } | 237 | } |
227 | 238 | ||
228 | static void mv88e6060_poll_link(struct dsa_switch *ds) | ||
229 | { | ||
230 | int i; | ||
231 | |||
232 | for (i = 0; i < DSA_MAX_PORTS; i++) { | ||
233 | struct net_device *dev; | ||
234 | int uninitialized_var(port_status); | ||
235 | int link; | ||
236 | int speed; | ||
237 | int duplex; | ||
238 | int fc; | ||
239 | |||
240 | dev = ds->ports[i]; | ||
241 | if (dev == NULL) | ||
242 | continue; | ||
243 | |||
244 | link = 0; | ||
245 | if (dev->flags & IFF_UP) { | ||
246 | port_status = reg_read(ds, REG_PORT(i), 0x00); | ||
247 | if (port_status < 0) | ||
248 | continue; | ||
249 | |||
250 | link = !!(port_status & 0x1000); | ||
251 | } | ||
252 | |||
253 | if (!link) { | ||
254 | if (netif_carrier_ok(dev)) { | ||
255 | netdev_info(dev, "link down\n"); | ||
256 | netif_carrier_off(dev); | ||
257 | } | ||
258 | continue; | ||
259 | } | ||
260 | |||
261 | speed = (port_status & 0x0100) ? 100 : 10; | ||
262 | duplex = (port_status & 0x0200) ? 1 : 0; | ||
263 | fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0; | ||
264 | |||
265 | if (!netif_carrier_ok(dev)) { | ||
266 | netdev_info(dev, | ||
267 | "link up, %d Mb/s, %s duplex, flow control %sabled\n", | ||
268 | speed, | ||
269 | duplex ? "full" : "half", | ||
270 | fc ? "en" : "dis"); | ||
271 | netif_carrier_on(dev); | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static struct dsa_switch_driver mv88e6060_switch_driver = { | 239 | static struct dsa_switch_driver mv88e6060_switch_driver = { |
277 | .tag_protocol = DSA_TAG_PROTO_TRAILER, | 240 | .tag_protocol = DSA_TAG_PROTO_TRAILER, |
278 | .probe = mv88e6060_probe, | 241 | .probe = mv88e6060_probe, |
@@ -280,7 +243,6 @@ static struct dsa_switch_driver mv88e6060_switch_driver = { | |||
280 | .set_addr = mv88e6060_set_addr, | 243 | .set_addr = mv88e6060_set_addr, |
281 | .phy_read = mv88e6060_phy_read, | 244 | .phy_read = mv88e6060_phy_read, |
282 | .phy_write = mv88e6060_phy_write, | 245 | .phy_write = mv88e6060_phy_write, |
283 | .poll_link = mv88e6060_poll_link, | ||
284 | }; | 246 | }; |
285 | 247 | ||
286 | static int __init mv88e6060_init(void) | 248 | static int __init mv88e6060_init(void) |