1/* 2 * Broadcom BCM5325E/536x switch configuration utility 3 * 4 * Copyright (C) 2005 Oleg I. Vdovikin 5 * Copyright (C) 2005 Dmitry 'dimss' Ivanov of "Telecentrs" (Riga, Latvia) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 * 02110-1301, USA. 21 */ 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26#include <sys/param.h> 27#include <sys/ioctl.h> 28#include <sys/socket.h> 29 30/* linux stuff */ 31typedef u_int64_t u64; 32typedef u_int32_t u32; 33typedef u_int16_t u16; 34typedef u_int8_t u8; 35 36#include <linux/if.h> 37#include <linux/sockios.h> 38#include <linux/ethtool.h> 39#include <linux/types.h> 40#include <linux/mii.h> 41 42#include "etc53xx.h" 43#define ROBO_PHY_ADDR 0x1E /* robo switch phy address */ 44 45/* MII registers */ 46#define REG_MII_PAGE 0x10 /* MII Page register */ 47#define REG_MII_ADDR 0x11 /* MII Address register */ 48#define REG_MII_DATA0 0x18 /* MII Data register 0 */ 49 50#define REG_MII_PAGE_ENABLE 1 51#define REG_MII_ADDR_WRITE 1 52#define REG_MII_ADDR_READ 2 53 54/* Private et.o ioctls */ 55#define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9) 56#define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10) 57#define SIOCGETCPHYRD2 (SIOCDEVPRIVATE + 12) 58#define SIOCSETCPHYWR2 (SIOCDEVPRIVATE + 13) 59#define SIOCGETCROBORD (SIOCDEVPRIVATE + 14) 60#define SIOCSETCROBOWR (SIOCDEVPRIVATE + 15) 61 62#define ROBO_DEVICE_ID 0x30 63 64typedef struct { 65 struct ifreq ifr; 66 int fd; 67 u8 et; /* use private ioctls */ 68 u8 gmii; /* gigabit mii */ 69} robo_t; 70 71#ifndef BCM5301X 72static u16 __mdio_access(robo_t *robo, u16 phy_id, u8 reg, u16 val, u16 wr) 73{ 74 static int __ioctl_args[2][3] = { {SIOCGETCPHYRD, SIOCGETCPHYRD2, SIOCGMIIREG}, 75 {SIOCSETCPHYWR, SIOCSETCPHYWR2, SIOCSMIIREG} }; 76 77 if (robo->et) { 78 int args[2] = { reg, val }; 79 int cmd = 0; 80 81 if (phy_id != ROBO_PHY_ADDR) { 82 cmd = 1; 83 args[0] |= phy_id << 16; 84 } 85 robo->ifr.ifr_data = (caddr_t) args; 86 if (ioctl(robo->fd, __ioctl_args[wr][cmd], (caddr_t)&robo->ifr) < 0) { 87 if (phy_id != ROBO_PHY_ADDR) { 88 fprintf(stderr, 89 "Access to real 'phy' registers unavaliable.\n" 90 "Upgrade kernel driver.\n"); 91 return 0xffff; 92 } 93 perror("ET ioctl"); 94 exit(1); 95 } 96 return args[1]; 97 } else { 98 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data; 99 mii->phy_id = phy_id; 100 mii->reg_num = reg; 101 mii->val_in = val; 102 if (ioctl(robo->fd, __ioctl_args[wr][2], &robo->ifr) < 0) { 103 perror("MII ioctl"); 104 exit(1); 105 } 106 return mii->val_out; 107 } 108} 109 110static inline u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg) 111{ 112 return __mdio_access(robo, phy_id, reg, 0, 0); 113} 114 115static inline void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val) 116{ 117 __mdio_access(robo, phy_id, reg, val, 1); 118} 119 120static int _robo_reg(robo_t *robo, u8 page, u8 reg, u8 op) 121{ 122 int i = 3; 123 124 /* set page number */ 125 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_PAGE, 126 (page << 8) | REG_MII_PAGE_ENABLE); 127 128 /* set register address */ 129 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_ADDR, 130 (reg << 8) | op); 131 132 /* check if operation completed */ 133 while (i--) { 134 if ((mdio_read(robo, ROBO_PHY_ADDR, REG_MII_ADDR) & 3) == 0) 135 return 0; 136 } 137 138 return -1; 139} 140 141static int robo_reg(robo_t *robo, u8 page, u8 reg, u8 op) 142{ 143 if (_robo_reg(robo, page, reg, op)) 144 { 145 fprintf(stderr, "robo_reg: %x/%x timeout\n", page, reg); 146 exit(1); 147 } 148 149 return 0; 150} 151#else 152 153static u16 robo_read16(robo_t *robo, u8 page, u8 reg); 154static u32 robo_read32(robo_t *robo, u8 page, u8 reg); 155static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16); 156static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32); 157 158static inline u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg) 159{ 160 return robo_read16(robo, 0x10 + phy_id, reg); 161} 162 163static inline void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val) 164{ 165 robo_write16(robo, 0x10 + phy_id, reg, val); 166} 167 168static int _robo_reg(robo_t *robo, u8 page, u8 reg, u8 op) 169{ 170 return 0; 171} 172#endif 173 174static void robo_read(robo_t *robo, u8 page, u8 reg, u16 *val, int count) 175{ 176#ifdef BCM5301X 177 int args[5]; 178 179 args[0] = (page << 16) | (reg & 0xffff); 180 args[1] = count * 2; 181 args[2] = 0; 182 183 robo->ifr.ifr_data = (caddr_t) args; 184 185 if (ioctl(robo->fd, SIOCGETCROBORD, (caddr_t)&robo->ifr) < 0) 186 return; 187 188 memcpy(val, &args[2], count * 2); 189#else 190 int i; 191 192 robo_reg(robo, page, reg, REG_MII_ADDR_READ); 193 194 for (i = 0; i < count; i++) 195 val[i] = mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i); 196#endif 197} 198 199static u16 robo_read16(robo_t *robo, u8 page, u8 reg) 200{ 201#ifdef BCM5301X 202 u16 val16; 203 204 robo_read(robo, page, reg, &val16, 1); 205 return val16; 206#else 207 robo_reg(robo, page, reg, REG_MII_ADDR_READ); 208 209 return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0); 210#endif 211} 212 213static u32 robo_read32(robo_t *robo, u8 page, u8 reg) 214{ 215#ifdef BCM5301X 216 u32 val32; 217 218 robo_read(robo, page, reg, (u16 *) &val32, 2); 219 return val32; 220#else 221 robo_reg(robo, page, reg, REG_MII_ADDR_READ); 222 223 return ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0)) | 224 ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1) << 16); 225#endif 226} 227 228static void robo_write(robo_t *robo, u8 page, u8 reg, u16 *val, int count) 229{ 230#ifdef BCM5301X 231 int args[5]; 232 233 args[0] = (page << 16) | (reg & 0xffff); 234 args[1] = count * 2; 235 memcpy(&args[2], val, count * 2); 236 237 robo->ifr.ifr_data = (caddr_t) args; 238 239 ioctl(robo->fd, SIOCSETCROBOWR, (caddr_t)&robo->ifr); 240#else 241 int i; 242 243 for (i = 0; i < count; i++) 244 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i, val[i]); 245 246 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE); 247#endif 248} 249 250static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16) 251{ 252#ifdef BCM5301X 253 robo_write(robo, page, reg, &val16, 1); 254#else 255 /* write data */ 256 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val16); 257 258 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE); 259#endif 260} 261 262static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32) 263{ 264#ifdef BCM5301X 265 robo_write(robo, page, reg, (u16 *) &val32, 2); 266#else 267 /* write data */ 268 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, (u16 )(val32 & 0xFFFF)); 269 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1, (u16 )(val32 >> 16)); 270 271 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE); 272#endif 273} 274 275/* checks that attached switch is 5325/5352/5354/5356/5357/53115/5301x */ 276static int robo_vlan535x(robo_t *robo, u32 phyid) 277{ 278#ifdef BCM5301X 279 if ((robo_read32(robo, ROBO_MGMT_PAGE, ROBO_DEVICE_ID) & 0xfffffff0) == 0x53010) 280 return 5; 281#else 282 /* set vlan access id to 15 and read it back */ 283 u16 val16 = 15; 284 robo_write16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); 285 286 /* 5365 will refuse this as it does not have this reg */ 287 if (robo_read16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) != val16) 288 return 0; 289 /* gigabit ? */ 290 if (robo->et != 1 && (mdio_read(robo, 0, ROBO_MII_STAT) & 0x0100)) 291 robo->gmii = ((mdio_read(robo, 0, 0x0f) & 0xf000) != 0); 292 /* 53115 ? */ 293 if (robo->gmii && robo_read32(robo, ROBO_STAT_PAGE, ROBO_LSA_IM_PORT) != 0) { 294 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, val16); 295 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395, 296 (1 << 7) /* start */ | 1 /* read */); 297 if (robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395) == 1 298 && robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395) == val16) 299 return 4; 300 } 301 /* dirty trick for 5356/5357 */ 302 if ((phyid & 0xfff0ffff ) == 0x5da00362 || 303 (phyid & 0xfff0ffff ) == 0x5e000362) 304 return 3; 305 /* 5325/5352/5354*/ 306 return 1; 307#endif 308} 309 310u8 port[9] = { 0, 1, 2, 3, 4, 8, 0, 0, 8}; 311char ports[] = "01234???5???????"; 312char *speed[4] = { "10", "100", "1000" , "4" }; 313char *rxtx[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" }; 314char *stp[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" }; 315char *jumbo[2] = { "off", "on" }; 316 317struct { 318 char *name; 319 u16 bmcr; 320} media[7] = { 321 { "auto", BMCR_ANENABLE | BMCR_ANRESTART }, 322 { "10HD", 0 }, 323 { "10FD", BMCR_FULLDPLX }, 324 { "100HD", BMCR_SPEED100 }, 325 { "100FD", BMCR_SPEED100 | BMCR_FULLDPLX }, 326 { "1000HD", BMCR_SPEED1000 }, 327 { "1000FD", BMCR_SPEED1000 | BMCR_FULLDPLX } 328}; 329 330struct { 331 char *name; 332 u16 value; 333 u16 value1; 334 u16 value2; 335 u16 value3; 336} mdix[3] = { 337 { "auto", 0x0000, 0x0000, 0x8207, 0x0000 }, 338 { "on", 0x1800, 0x4000, 0x8007, 0x0080 }, 339 { "off", 0x0800, 0x4000, 0x8007, 0x0000 } 340}; 341 342void usage() 343{ 344 fprintf(stderr, "Broadcom BCM5325/535x/536x/5311x switch configuration utility\n" 345 "Copyright (C) 2005-2008 Oleg I. Vdovikin (oleg@cs.msu.su)\n" 346 "Copyright (C) 2005 Dmitry 'dimss' Ivanov of \"Telecentrs\" (Riga, Latvia)\n\n" 347 "This program is distributed in the hope that it will be useful,\n" 348 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 349 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 350 "GNU General Public License for more details.\n\n"); 351 352 fprintf(stderr, "Usage: robocfg <op> ... <op>\n" 353 "Operations are as below:\n" 354 "\tshow -- show current config\n" 355 "\tshowmacs -- show known MAC addresses\n" 356 "\tswitch <enable|disable>\n" 357 "\tport <port_number> [state <%s|%s|%s|%s>]\n" 358 "\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n" 359 "\t\t[media %s|%s|%s|%s|%s|%s|%s]\n" 360 "\t\t[mdi-x %s|%s|%s] [jumbo %s|%s]\n" 361 "\tvlan <vlan_number> [ports <ports_list>]\n" 362 "\tvlans <enable|disable|reset>\n\n" 363 "\tports_list should be one argument, space separated, quoted if needed,\n" 364 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n" 365 "\tport default) or by 'u' to untag packet (other ports default) before \n" 366 "\tbringing it to the port, '*' is ignored\n" 367 "\nSamples:\n" 368 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n" 369 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\"" 370 " port 0 state enabled stp none switch enable\n" 371 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n" 372 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\"" 373 " port 0 state enabled stp none switch enable\n", 374 rxtx[0], rxtx[1], rxtx[2], rxtx[3], stp[0], stp[1], stp[2], stp[3], stp[4], stp[5], 375 media[0].name, media[1].name, media[2].name, media[3].name, media[4].name, media[5].name, media[6].name, 376 mdix[0].name, mdix[1].name, mdix[2].name, 377 jumbo[0], jumbo[1]); 378} 379 380int 381main(int argc, char *argv[]) 382{ 383 u16 val16; 384 u32 val32; 385 u16 mac[3]; 386 int i = 0, j; 387 int robo535x = 0; /* 0 - 5365, 1 - 5325/5352/5354, 3 - 5356, 4 - 53115, 5 - 5301x */ 388 u32 phyid; 389 390 static robo_t robo; 391 struct ethtool_drvinfo info; 392 393 if ((robo.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 394 perror("socket"); 395 exit(1); 396 } 397 398 /* the only interface for now */ 399 strcpy(robo.ifr.ifr_name, "eth0"); 400 401 memset(&info, 0, sizeof(info)); 402 info.cmd = ETHTOOL_GDRVINFO; 403 robo.ifr.ifr_data = (caddr_t)&info; 404 if (ioctl(robo.fd, SIOCETHTOOL, (caddr_t)&robo.ifr) < 0) { 405 perror("SIOCETHTOOL: your ethernet module is either unsupported or outdated"); 406 exit(1); 407 } else 408 if (strcmp(info.driver, "et0") && strcmp(info.driver, "et1") && strcmp(info.driver, "et2") && 409 strcmp(info.driver, "b44")) { 410 fprintf(stderr, "No suitable module found for %s (managed by %s)\n", 411 robo.ifr.ifr_name, info.driver); 412 exit(1); 413 } 414 415 /* try access using MII ioctls - get phy address */ 416 if (ioctl(robo.fd, SIOCGMIIPHY, &robo.ifr) < 0) { 417 int args[2] = { ROBO_PHY_ADDR << 16, 0x0 }; 418 419 robo.ifr.ifr_data = (caddr_t) args; 420 if (ioctl(robo.fd, SIOCGETCPHYRD2, &robo.ifr) < 0) 421 robo.et = 1; 422 else robo.et = 2; 423 } else { 424 /* got phy address check for robo address */ 425 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data; 426 if (mii->phy_id != ROBO_PHY_ADDR) { 427 fprintf(stderr, "Invalid phy address (%d)\n", mii->phy_id); 428 exit(1); 429 } 430 } 431 432 phyid = mdio_read(&robo, ROBO_PHY_ADDR, 0x2) | 433 (mdio_read(&robo, ROBO_PHY_ADDR, 0x3) << 16); 434 if (phyid == 0 && robo.et != 1) 435 phyid = mdio_read(&robo, 0, 0x2) | 436 (mdio_read(&robo, 0, 0x3) << 16); 437 438 if (phyid == 0xffffffff || phyid == 0x55210022) { 439 fprintf(stderr, "No Robo switch in managed mode found\n"); 440 exit(1); 441 } 442 443 robo535x = robo_vlan535x(&robo, phyid); 444 /* fprintf(stderr, "phyid %08x id %d\n", phyid, robo535x); */ 445 446 for (i = 1; i < argc;) { 447 if (strcasecmp(argv[i], "showmacs") == 0) 448 { 449 /* show MAC table of switch */ 450 u16 buf[6]; 451 int idx, off, base_vlan; 452 453 base_vlan = 0; /*get_vid_by_idx(&robo, 0);*/ 454 455 printf( 456 "--------------------------------------\n" 457 "VLAN MAC Type Port\n" 458 "--------------------------------------\n"); 459 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_RW_CTRL, 0x81); 460 robo_write16(&robo, ROBO_ARLIO_PAGE, (robo535x >= 4) ? 461 ROBO_ARL_SEARCH_CTRL_53115 : ROBO_ARL_SEARCH_CTRL, 0x80); 462 for (idx = 0; idx < ((robo535x >= 4) ? 463 NUM_ARL_TABLE_ENTRIES_53115 : robo535x ? 464 NUM_ARL_TABLE_ENTRIES_5350 : NUM_ARL_TABLE_ENTRIES); idx++) 465 { 466 if (robo535x >= 4) 467 { 468 off = (idx & 0x01) << 4; 469 if (!off && (robo_read16(&robo, ROBO_ARLIO_PAGE, 470 ROBO_ARL_SEARCH_CTRL_53115) & 0x80) == 0) break; 471 robo_read(&robo, ROBO_ARLIO_PAGE, 472 ROBO_ARL_SEARCH_RESULT_53115 + off, buf, 4); 473 robo_read(&robo, ROBO_ARLIO_PAGE, 474 ROBO_ARL_SEARCH_RESULT_EXT_53115 + off, &buf[4], 2); 475 } else 476 robo_read(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_SEARCH_RESULT, 477 buf, robo535x ? 4 : 5); 478 if ((robo535x >= 4) ? (buf[5] & 0x01) : (buf[3] & 0x8000) /* valid */) 479 { 480 printf("%04i %02x:%02x:%02x:%02x:%02x:%02x %7s %c\n", 481 (base_vlan | (robo535x >= 4) ? 482 (base_vlan | (buf[3] & 0xfff)) : 483 ((buf[3] >> 5) & 0x0f) | 484 (robo535x ? 0 : ((buf[4] & 0x0f) << 4))), 485 buf[2] >> 8, buf[2] & 255, 486 buf[1] >> 8, buf[1] & 255, 487 buf[0] >> 8, buf[0] & 255, 488 ((robo535x >= 4 ? 489 (buf[4] & 0x8000) : (buf[3] & 0x4000)) ? "STATIC" : "DYNAMIC"), 490 ((robo535x >= 4) ? 491 '0'+(buf[4] & 0x0f) : ports[buf[3] & 0x0f]) 492 ); 493 } 494 } 495 i++; 496 } else 497 if (strcasecmp(argv[i], "port") == 0 && (i + 1) < argc) 498 { 499 int index = atoi(argv[++i]); 500 /* read port specs */ 501 while (++i < argc) { 502 if (strcasecmp(argv[i], "state") == 0 && ++i < argc) { 503 for (j = 0; j < 4 && strcasecmp(argv[i], rxtx[j]); j++); 504 if (j < 4) { 505 /* change state */ 506 robo_write16(&robo,ROBO_CTRL_PAGE, port[index], 507 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(3 << 0)) | (j << 0)); 508 } else { 509 fprintf(stderr, "Invalid state '%s'.\n", argv[i]); 510 exit(1); 511 } 512 } else 513 if (strcasecmp(argv[i], "stp") == 0 && ++i < argc) { 514 for (j = 0; j < 8 && strcasecmp(argv[i], stp[j]); j++); 515 if (j < 8) { 516 /* change stp */ 517 robo_write16(&robo,ROBO_CTRL_PAGE, port[index], 518 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(7 << 5)) | (j << 5)); 519 } else { 520 fprintf(stderr, "Invalid stp '%s'.\n", argv[i]); 521 exit(1); 522 } 523 } else 524 if (strcasecmp(argv[i], "media") == 0 && ++i < argc) { 525 for (j = 0; j < 7 && strcasecmp(argv[i], media[j].name); j++); 526 if (j < ((robo535x >= 4) ? 7 : 5)) { 527 /* change media */ 528 mdio_write(&robo, port[index], MII_BMCR, media[j].bmcr); 529 } else { 530 fprintf(stderr, "Invalid media '%s'.\n", argv[i]); 531 exit(1); 532 } 533 } else 534 if (strcasecmp(argv[i], "mdi-x") == 0 && ++i < argc) { 535 for (j = 0; j < 3 && strcasecmp(argv[i], mdix[j].name); j++); 536 if (j < 3) { 537 /* change mdi-x */ 538 if (robo535x >= 4) { 539 mdio_write(&robo, port[index], 0x10, mdix[j].value1 | 540 (mdio_read(&robo, port[index], 0x10) & ~0x4000)); 541 mdio_write(&robo, port[index], 0x18, 0x7007); 542 mdio_write(&robo, port[index], 0x18, mdix[j].value2 | 543 (mdio_read(&robo, port[index], 0x18) & ~0x8207)); 544 mdio_write(&robo, port[index], 0x1e, mdix[j].value3 | 545 (mdio_read(&robo, port[index], 0x1e) & ~0x0080)); 546 } else 547 mdio_write(&robo, port[index], 0x1c, mdix[j].value | 548 (mdio_read(&robo, port[index], 0x1c) & ~0x1800)); 549 } else { 550 fprintf(stderr, "Invalid mdi-x '%s'.\n", argv[i]); 551 exit(1); 552 } 553 } else 554 if (strcasecmp(argv[i], "tag") == 0 && ++i < argc) { 555 j = atoi(argv[i]); 556 /* change vlan tag */ 557 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (index << 1), j); 558 } else 559 if (strcasecmp(argv[i], "jumbo") == 0 && ++i < argc) { 560 for (j = 0; j < 2 && strcasecmp(argv[i], jumbo[j]); j++); 561 if (robo535x >= 4 && j < 2) { 562 /* change jumbo frame feature */ 563 robo_write32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL, 564 (robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) & 565 ~(1 << port[index])) | (j << port[index])); 566 } else { 567 fprintf(stderr, "Invalid jumbo state '%s'.\n", argv[i]); 568 exit(1); 569 } 570 } else break; 571 } 572 } else 573 if (strcasecmp(argv[i], "vlan") == 0 && (i + 1) < argc) 574 { 575 int vid = atoi(argv[++i]); 576 while (++i < argc) { 577 if (strcasecmp(argv[i], "ports") == 0 && ++i < argc) { 578 char *ports = argv[i]; 579 int untag = 0; 580 int member = 0; 581 582 while (*ports >= '0' && *ports <= '9') { 583 j = *ports++ - '0'; 584 member |= 1 << j; 585 586 /* untag if needed, CPU port requires special handling */ 587 if (*ports == 'u' || (j != 5 && (*ports == ' ' || *ports == 0))) 588 { 589 untag |= 1 << j; 590 if (*ports) ports++; 591 /* change default vlan tag */ 592 robo_write16(&robo, ROBO_VLAN_PAGE, 593 ROBO_VLAN_PORT0_DEF_TAG + (j << 1), vid); 594 } else 595 if (*ports == '*' || *ports == 't' || *ports == ' ') ports++; 596 else break; 597 598 while (*ports == ' ') ports++; 599 } 600 601 if (*ports) { 602 fprintf(stderr, "Invalid ports '%s'.\n", argv[i]); 603 exit(1); 604 } else { 605 /* write config now */ 606 val16 = (vid) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; 607 if (robo535x >= 4) { 608 val32 = (untag << 9) | member; 609 /* entry */ 610 robo_write32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395, val32); 611 /* index */ 612 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, vid); 613 /* access */ 614 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395, 615 (1 << 7) /* start */ | 0 /* write */); 616 } else if (robo535x) { 617 if (robo535x == 3) 618 val32 = (1 << 24) /* valid */ | (untag << 6) | member | (vid << 12); 619 else 620 val32 = (1 << 20) /* valid */ | (untag << 6) | member | ((vid >> 4) << 12); 621 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, val32); 622 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); 623 } else { 624 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 625 (1 << 14) /* valid */ | (untag << 7) | member); 626 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); 627 } 628 } 629 } else break; 630 } 631 } else 632 if (strcasecmp(argv[i], "switch") == 0 && (i + 1) < argc) 633 { 634 /* enable/disable switching */ 635 robo_write16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE, 636 (robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) | 637 (*argv[++i] == 'e' ? 2 : 0)); 638 i++; 639 } else 640 if (strcasecmp(argv[i], "vlans") == 0 && (i + 1) < argc) 641 { 642 while (++i < argc) { 643 if (strcasecmp(argv[i], "reset") == 0) { 644 if (robo535x >= 4) { 645 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395, 646 (1 << 7) /* start */ | 2 /* flush */); 647 } else 648 /* reset vlan validity bit */ 649 for (j = 0; j <= ((robo535x == 1) ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++) 650 { 651 /* write config now */ 652 val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; 653 if (robo535x) { 654 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0); 655 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); 656 } else { 657 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0); 658 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); 659 } 660 } 661 } else 662 if (strcasecmp(argv[i], "enable") == 0 || strcasecmp(argv[i], "disable") == 0) 663 { 664 int disable = (*argv[i] == 'd') || (*argv[i] == 'D'); 665 /* enable/disable vlans */ 666 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 : 667 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */); 668 669 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 : 670 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */); 671 672 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 : 673 (1 << 6) /* drop invalid VID frames */); 674 675 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 : 676 (1 << 3) /* drop miss V table frames */); 677 678 } else break; 679 } 680 } else 681 if (strcasecmp(argv[i], "show") == 0) 682 { 683 break; 684 } else 685 if (strncasecmp(argv[i], "robowr", 6) == 0 && (i + 2) < argc) 686 { 687 long pagereg = strtoul(argv[i + 1], NULL, 0); 688 int size = strtoul(argv[i] + 6, NULL, 0); 689 int k; 690 unsigned long long int v; 691 u16 buf[4]; 692 693 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1; 694 695 v = strtoull(argv[i + 2], NULL, 0); 696 for (k = 0; k < size; k++) 697 { 698 buf[k] = (u16 )(v & 0xFFFF); 699 v >>= 16; 700 } 701 robo_write(&robo, pagereg >> 8, pagereg & 255, buf, size); 702 703 printf("Page 0x%02x, Reg 0x%02x: ", 704 (u16 )(pagereg >> 8), (u8 )(pagereg & 255)); 705 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size); 706 while (size > 0) 707 printf("%04x", buf[--size]); 708 printf("\n"); 709 710 i += 3; 711 } else 712 if (strncasecmp(argv[i], "robord", 6) == 0 && (i + 1) < argc) 713 { 714 long pagereg = strtoul(argv[i + 1], NULL, 0); 715 int size = strtoul(argv[i] + 6, NULL, 0); 716 u16 buf[4]; 717 718 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1; 719 720 printf("Page 0x%02x, Reg 0x%02x: ", 721 (u16 )(pagereg >> 8), (u8 )(pagereg & 255)); 722 723 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size); 724 while (size > 0) 725 printf("%04x", buf[--size]); 726 printf("\n"); 727 728 i += 2; 729 } else 730 if (strcasecmp(argv[i], "dump") == 0) 731 { 732 for (i = 0; i < 256; i++) 733 { 734 if (_robo_reg(&robo, i, 0, REG_MII_ADDR_READ)) 735 continue; 736 737 printf("Page %02x\n", i); 738 739 for (j = 0; j < 128; j++) { 740 printf(" %04x%s", 741 robo_read16(&robo, i, j), (j % 16) == 15 ? "\n" : ""); 742 } 743 } 744 745 i = 2; 746 } else { 747 fprintf(stderr, "Invalid option %s\n", argv[i]); 748 usage(); 749 exit(1); 750 } 751 } 752 753 if (i == argc) { 754 if (argc == 1) usage(); 755 return 0; 756 } 757 758 /* show config */ 759 760 printf("Switch: %sabled %s\n", robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2 ? "en" : "dis", 761 robo.gmii ? "gigabit" : ""); 762 763 for (i = 0; i < 6; i++) { 764 printf(robo_read16(&robo, ROBO_STAT_PAGE, ROBO_LINK_STAT_SUMMARY) & (1 << port[i]) ? 765 "Port %d: %4s%s " : "Port %d: DOWN ", 766 (robo535x >= 4) ? port[i] : i, 767 speed[(robo535x >= 4) ? 768 (robo_read32(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i] * 2) & 3 : 769 (robo_read16(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i]) & 1], 770 robo_read16(&robo, ROBO_STAT_PAGE, (robo535x >= 4) ? 771 ROBO_DUPLEX_STAT_SUMMARY_53115 : ROBO_DUPLEX_STAT_SUMMARY) & (1 << port[i]) ? "FD" : "HD"); 772 773 val16 = robo_read16(&robo, ROBO_CTRL_PAGE, port[i]); 774 775 printf("%s stp: %s vlan: %d ", rxtx[val16 & 3], stp[(val16 >> 5) & 7], 776 robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (i << 1))); 777 778 if (robo535x >= 4) 779 printf("jumbo: %s ", jumbo[(robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) >> port[i]) & 1]); 780 781 robo_read(&robo, ROBO_STAT_PAGE, ROBO_LSA_PORT0 + port[i] * 6, mac, 3); 782 783 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 784 mac[2] >> 8, mac[2] & 255, mac[1] >> 8, mac[1] & 255, mac[0] >> 8, mac[0] & 255); 785 } 786 787 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0); 788 789 printf("VLANs: %s %sabled%s%s\n", 790 (robo535x == 5) ? "BCM5301x" : 791 (robo535x == 4) ? "BCM53115" : (robo535x ? "BCM5325/535x" : "BCM536x"), 792 (val16 & (1 << 7)) ? "en" : "dis", 793 (val16 & (1 << 6)) ? " mac_check" : "", 794 (val16 & (1 << 5)) ? " mac_hash" : ""); 795 796 /* scan VLANs */ 797 for (i = 0; i <= ((robo535x >= 4) ? VLAN_ID_MAX5395 /* slow, needs rework, but how? */ : 798 (robo535x ? VLAN_ID_MAX5350 : VLAN_ID_MAX)); i++) 799 { 800 /* issue read */ 801 val16 = (i) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */; 802 803 if (robo535x >= 4) { 804 /* index */ 805 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, i); 806 /* access */ 807 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395, 808 (1 << 7) /* start */ | 1 /* read */); 809 /* actual read */ 810 val32 = robo_read32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395); 811 if ((val32)) { 812 printf("%4d: vlan%d:", i, i); 813 for (j = 0; j <= 8; j++) { 814 if (val32 & (1 << j)) { 815 printf(" %d%s", j, (val32 & (1 << (j + 9))) ? 816 (j == 8 ? "u" : "") : "t"); 817 } 818 } 819 printf("\n"); 820 } 821 } else if (robo535x) { 822 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); 823 /* actual read */ 824 val32 = robo_read32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ); 825 if ((val32 & (robo535x == 3 ? (1 << 24) : (1 << 20))) /* valid */) { 826 val16 = (robo535x == 3) 827 ? ((val32 & 0x00fff000) >> 12) 828 : (((val32 & 0xff000) >> 12) << 4) | i; 829 printf("%4d: vlan%d:", i, val16); 830 for (j = 0; j < 6; j++) { 831 if (val32 & (1 << j)) { 832 printf(" %d%s", j, (val32 & (1 << (j + 6))) ? 833 (j == 5 ? "u" : "") : "t"); 834 } 835 } 836 printf("\n"); 837 } 838 } else { 839 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); 840 /* actual read */ 841 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ); 842 if ((val16 & (1 << 14)) /* valid */) { 843 printf("%4d: vlan%d:", i, i); 844 for (j = 0; j < 6; j++) { 845 if (val16 & (1 << j)) { 846 printf(" %d%s", j, (val16 & (1 << (j + 7))) ? 847 (j == 5 ? "u" : "") : "t"); 848 } 849 } 850 printf("\n"); 851 } 852 } 853 } 854 855 return (0); 856} 857