Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9 521 lines 11 kB view raw
1/* 2 * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support 3 * Copyright (c) 2008 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 */ 10 11#include <linux/delay.h> 12#include <linux/jiffies.h> 13#include <linux/list.h> 14#include <linux/module.h> 15#include <linux/netdevice.h> 16#include <linux/phy.h> 17#include <net/dsa.h> 18#include "mv88e6xxx.h" 19 20/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will 21 * use all 32 SMI bus addresses on its SMI bus, and all switch registers 22 * will be directly accessible on some {device address,register address} 23 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch 24 * will only respond to SMI transactions to that specific address, and 25 * an indirect addressing mechanism needs to be used to access its 26 * registers. 27 */ 28static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) 29{ 30 int ret; 31 int i; 32 33 for (i = 0; i < 16; i++) { 34 ret = mdiobus_read(bus, sw_addr, 0); 35 if (ret < 0) 36 return ret; 37 38 if ((ret & 0x8000) == 0) 39 return 0; 40 } 41 42 return -ETIMEDOUT; 43} 44 45int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) 46{ 47 int ret; 48 49 if (sw_addr == 0) 50 return mdiobus_read(bus, addr, reg); 51 52 /* Wait for the bus to become free. */ 53 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); 54 if (ret < 0) 55 return ret; 56 57 /* Transmit the read command. */ 58 ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg); 59 if (ret < 0) 60 return ret; 61 62 /* Wait for the read command to complete. */ 63 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); 64 if (ret < 0) 65 return ret; 66 67 /* Read the data. */ 68 ret = mdiobus_read(bus, sw_addr, 1); 69 if (ret < 0) 70 return ret; 71 72 return ret & 0xffff; 73} 74 75int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg) 76{ 77 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 78 int ret; 79 80 mutex_lock(&ps->smi_mutex); 81 ret = __mv88e6xxx_reg_read(ds->master_mii_bus, 82 ds->pd->sw_addr, addr, reg); 83 mutex_unlock(&ps->smi_mutex); 84 85 return ret; 86} 87 88int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, 89 int reg, u16 val) 90{ 91 int ret; 92 93 if (sw_addr == 0) 94 return mdiobus_write(bus, addr, reg, val); 95 96 /* Wait for the bus to become free. */ 97 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); 98 if (ret < 0) 99 return ret; 100 101 /* Transmit the data to write. */ 102 ret = mdiobus_write(bus, sw_addr, 1, val); 103 if (ret < 0) 104 return ret; 105 106 /* Transmit the write command. */ 107 ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg); 108 if (ret < 0) 109 return ret; 110 111 /* Wait for the write command to complete. */ 112 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); 113 if (ret < 0) 114 return ret; 115 116 return 0; 117} 118 119int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) 120{ 121 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 122 int ret; 123 124 mutex_lock(&ps->smi_mutex); 125 ret = __mv88e6xxx_reg_write(ds->master_mii_bus, 126 ds->pd->sw_addr, addr, reg, val); 127 mutex_unlock(&ps->smi_mutex); 128 129 return ret; 130} 131 132int mv88e6xxx_config_prio(struct dsa_switch *ds) 133{ 134 /* Configure the IP ToS mapping registers. */ 135 REG_WRITE(REG_GLOBAL, 0x10, 0x0000); 136 REG_WRITE(REG_GLOBAL, 0x11, 0x0000); 137 REG_WRITE(REG_GLOBAL, 0x12, 0x5555); 138 REG_WRITE(REG_GLOBAL, 0x13, 0x5555); 139 REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa); 140 REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa); 141 REG_WRITE(REG_GLOBAL, 0x16, 0xffff); 142 REG_WRITE(REG_GLOBAL, 0x17, 0xffff); 143 144 /* Configure the IEEE 802.1p priority mapping register. */ 145 REG_WRITE(REG_GLOBAL, 0x18, 0xfa41); 146 147 return 0; 148} 149 150int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) 151{ 152 REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); 153 REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); 154 REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); 155 156 return 0; 157} 158 159int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) 160{ 161 int i; 162 int ret; 163 164 for (i = 0; i < 6; i++) { 165 int j; 166 167 /* Write the MAC address byte. */ 168 REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]); 169 170 /* Wait for the write to complete. */ 171 for (j = 0; j < 16; j++) { 172 ret = REG_READ(REG_GLOBAL2, 0x0d); 173 if ((ret & 0x8000) == 0) 174 break; 175 } 176 if (j == 16) 177 return -ETIMEDOUT; 178 } 179 180 return 0; 181} 182 183int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) 184{ 185 if (addr >= 0) 186 return mv88e6xxx_reg_read(ds, addr, regnum); 187 return 0xffff; 188} 189 190int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val) 191{ 192 if (addr >= 0) 193 return mv88e6xxx_reg_write(ds, addr, regnum, val); 194 return 0; 195} 196 197#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU 198static int mv88e6xxx_ppu_disable(struct dsa_switch *ds) 199{ 200 int ret; 201 unsigned long timeout; 202 203 ret = REG_READ(REG_GLOBAL, 0x04); 204 REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000); 205 206 timeout = jiffies + 1 * HZ; 207 while (time_before(jiffies, timeout)) { 208 ret = REG_READ(REG_GLOBAL, 0x00); 209 usleep_range(1000, 2000); 210 if ((ret & 0xc000) != 0xc000) 211 return 0; 212 } 213 214 return -ETIMEDOUT; 215} 216 217static int mv88e6xxx_ppu_enable(struct dsa_switch *ds) 218{ 219 int ret; 220 unsigned long timeout; 221 222 ret = REG_READ(REG_GLOBAL, 0x04); 223 REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000); 224 225 timeout = jiffies + 1 * HZ; 226 while (time_before(jiffies, timeout)) { 227 ret = REG_READ(REG_GLOBAL, 0x00); 228 usleep_range(1000, 2000); 229 if ((ret & 0xc000) == 0xc000) 230 return 0; 231 } 232 233 return -ETIMEDOUT; 234} 235 236static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) 237{ 238 struct mv88e6xxx_priv_state *ps; 239 240 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work); 241 if (mutex_trylock(&ps->ppu_mutex)) { 242 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1; 243 244 if (mv88e6xxx_ppu_enable(ds) == 0) 245 ps->ppu_disabled = 0; 246 mutex_unlock(&ps->ppu_mutex); 247 } 248} 249 250static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) 251{ 252 struct mv88e6xxx_priv_state *ps = (void *)_ps; 253 254 schedule_work(&ps->ppu_work); 255} 256 257static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds) 258{ 259 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 260 int ret; 261 262 mutex_lock(&ps->ppu_mutex); 263 264 /* If the PHY polling unit is enabled, disable it so that 265 * we can access the PHY registers. If it was already 266 * disabled, cancel the timer that is going to re-enable 267 * it. 268 */ 269 if (!ps->ppu_disabled) { 270 ret = mv88e6xxx_ppu_disable(ds); 271 if (ret < 0) { 272 mutex_unlock(&ps->ppu_mutex); 273 return ret; 274 } 275 ps->ppu_disabled = 1; 276 } else { 277 del_timer(&ps->ppu_timer); 278 ret = 0; 279 } 280 281 return ret; 282} 283 284static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds) 285{ 286 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 287 288 /* Schedule a timer to re-enable the PHY polling unit. */ 289 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10)); 290 mutex_unlock(&ps->ppu_mutex); 291} 292 293void mv88e6xxx_ppu_state_init(struct dsa_switch *ds) 294{ 295 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 296 297 mutex_init(&ps->ppu_mutex); 298 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work); 299 init_timer(&ps->ppu_timer); 300 ps->ppu_timer.data = (unsigned long)ps; 301 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer; 302} 303 304int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum) 305{ 306 int ret; 307 308 ret = mv88e6xxx_ppu_access_get(ds); 309 if (ret >= 0) { 310 ret = mv88e6xxx_reg_read(ds, addr, regnum); 311 mv88e6xxx_ppu_access_put(ds); 312 } 313 314 return ret; 315} 316 317int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr, 318 int regnum, u16 val) 319{ 320 int ret; 321 322 ret = mv88e6xxx_ppu_access_get(ds); 323 if (ret >= 0) { 324 ret = mv88e6xxx_reg_write(ds, addr, regnum, val); 325 mv88e6xxx_ppu_access_put(ds); 326 } 327 328 return ret; 329} 330#endif 331 332void mv88e6xxx_poll_link(struct dsa_switch *ds) 333{ 334 int i; 335 336 for (i = 0; i < DSA_MAX_PORTS; i++) { 337 struct net_device *dev; 338 int uninitialized_var(port_status); 339 int link; 340 int speed; 341 int duplex; 342 int fc; 343 344 dev = ds->ports[i]; 345 if (dev == NULL) 346 continue; 347 348 link = 0; 349 if (dev->flags & IFF_UP) { 350 port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00); 351 if (port_status < 0) 352 continue; 353 354 link = !!(port_status & 0x0800); 355 } 356 357 if (!link) { 358 if (netif_carrier_ok(dev)) { 359 netdev_info(dev, "link down\n"); 360 netif_carrier_off(dev); 361 } 362 continue; 363 } 364 365 switch (port_status & 0x0300) { 366 case 0x0000: 367 speed = 10; 368 break; 369 case 0x0100: 370 speed = 100; 371 break; 372 case 0x0200: 373 speed = 1000; 374 break; 375 default: 376 speed = -1; 377 break; 378 } 379 duplex = (port_status & 0x0400) ? 1 : 0; 380 fc = (port_status & 0x8000) ? 1 : 0; 381 382 if (!netif_carrier_ok(dev)) { 383 netdev_info(dev, 384 "link up, %d Mb/s, %s duplex, flow control %sabled\n", 385 speed, 386 duplex ? "full" : "half", 387 fc ? "en" : "dis"); 388 netif_carrier_on(dev); 389 } 390 } 391} 392 393static int mv88e6xxx_stats_wait(struct dsa_switch *ds) 394{ 395 int ret; 396 int i; 397 398 for (i = 0; i < 10; i++) { 399 ret = REG_READ(REG_GLOBAL, 0x1d); 400 if ((ret & 0x8000) == 0) 401 return 0; 402 } 403 404 return -ETIMEDOUT; 405} 406 407static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) 408{ 409 int ret; 410 411 /* Snapshot the hardware statistics counters for this port. */ 412 REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port); 413 414 /* Wait for the snapshotting to complete. */ 415 ret = mv88e6xxx_stats_wait(ds); 416 if (ret < 0) 417 return ret; 418 419 return 0; 420} 421 422static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) 423{ 424 u32 _val; 425 int ret; 426 427 *val = 0; 428 429 ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat); 430 if (ret < 0) 431 return; 432 433 ret = mv88e6xxx_stats_wait(ds); 434 if (ret < 0) 435 return; 436 437 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e); 438 if (ret < 0) 439 return; 440 441 _val = ret << 16; 442 443 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f); 444 if (ret < 0) 445 return; 446 447 *val = _val | ret; 448} 449 450void mv88e6xxx_get_strings(struct dsa_switch *ds, 451 int nr_stats, struct mv88e6xxx_hw_stat *stats, 452 int port, uint8_t *data) 453{ 454 int i; 455 456 for (i = 0; i < nr_stats; i++) { 457 memcpy(data + i * ETH_GSTRING_LEN, 458 stats[i].string, ETH_GSTRING_LEN); 459 } 460} 461 462void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, 463 int nr_stats, struct mv88e6xxx_hw_stat *stats, 464 int port, uint64_t *data) 465{ 466 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); 467 int ret; 468 int i; 469 470 mutex_lock(&ps->stats_mutex); 471 472 ret = mv88e6xxx_stats_snapshot(ds, port); 473 if (ret < 0) { 474 mutex_unlock(&ps->stats_mutex); 475 return; 476 } 477 478 /* Read each of the counters. */ 479 for (i = 0; i < nr_stats; i++) { 480 struct mv88e6xxx_hw_stat *s = stats + i; 481 u32 low; 482 u32 high; 483 484 mv88e6xxx_stats_read(ds, s->reg, &low); 485 if (s->sizeof_stat == 8) 486 mv88e6xxx_stats_read(ds, s->reg + 1, &high); 487 else 488 high = 0; 489 490 data[i] = (((u64)high) << 32) | low; 491 } 492 493 mutex_unlock(&ps->stats_mutex); 494} 495 496static int __init mv88e6xxx_init(void) 497{ 498#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) 499 register_switch_driver(&mv88e6131_switch_driver); 500#endif 501#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65) 502 register_switch_driver(&mv88e6123_61_65_switch_driver); 503#endif 504 return 0; 505} 506module_init(mv88e6xxx_init); 507 508static void __exit mv88e6xxx_cleanup(void) 509{ 510#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65) 511 unregister_switch_driver(&mv88e6123_61_65_switch_driver); 512#endif 513#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) 514 unregister_switch_driver(&mv88e6131_switch_driver); 515#endif 516} 517module_exit(mv88e6xxx_cleanup); 518 519MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 520MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 521MODULE_LICENSE("GPL");