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