2 * Broadcom BCM5325E/536x switch configuration utility
4 * Copyright (C) 2005 Oleg I. Vdovikin
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include <sys/param.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
30 typedef u_int64_t u64
;
31 typedef u_int32_t u32
;
32 typedef u_int16_t u16
;
36 #include <linux/sockios.h>
37 #include <linux/ethtool.h>
38 #include <linux/mii.h>
43 #define REG_MII_PAGE 0x10 /* MII Page register */
44 #define REG_MII_ADDR 0x11 /* MII Address register */
45 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
47 #define REG_MII_PAGE_ENABLE 1
48 #define REG_MII_ADDR_WRITE 1
49 #define REG_MII_ADDR_READ 2
51 /* Private et.o ioctls */
52 #define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
53 #define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
58 int et
; /* use private ioctls */
61 static u16
mdio_read(robo_t
*robo
, u8 reg
)
64 int args
[2] = { reg
};
66 robo
->ifr
.ifr_data
= (caddr_t
) args
;
67 if (ioctl(robo
->fd
, SIOCGETCPHYRD
, (caddr_t
)&robo
->ifr
) < 0) {
68 perror("SIOCGETCPHYRD");
74 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
->ifr
.ifr_data
;
76 if (ioctl(robo
->fd
, SIOCGMIIREG
, &robo
->ifr
) < 0) {
77 perror("SIOCGMIIREG");
84 static void mdio_write(robo_t
*robo
, u8 reg
, u16 val
)
87 int args
[2] = { reg
, val
};
89 robo
->ifr
.ifr_data
= (caddr_t
) args
;
90 if (ioctl(robo
->fd
, SIOCSETCPHYWR
, (caddr_t
)&robo
->ifr
) < 0) {
91 perror("SIOCGETCPHYWR");
95 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
->ifr
.ifr_data
;
98 if (ioctl(robo
->fd
, SIOCSMIIREG
, &robo
->ifr
) < 0) {
99 perror("SIOCSMIIREG");
105 static int robo_reg(robo_t
*robo
, u8 page
, u8 reg
, u8 op
)
109 /* set page number */
110 mdio_write(robo
, REG_MII_PAGE
,
111 (page
<< 8) | REG_MII_PAGE_ENABLE
);
113 /* set register address */
114 mdio_write(robo
, REG_MII_ADDR
, (reg
<< 8) | op
);
116 /* check if operation completed */
118 if ((mdio_read(robo
, REG_MII_ADDR
) & 3) == 0)
122 fprintf(stderr
, "robo_reg: timeout\n");
128 static void robo_read(robo_t
*robo
, u8 page
, u8 reg
, u16
*val
, int count
)
132 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
134 for (i
= 0; i
< count
; i
++)
135 val
[i
] = mdio_read(robo
, REG_MII_DATA0
+ i
);
138 static u16
robo_read16(robo_t
*robo
, u8 page
, u8 reg
)
140 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
142 return mdio_read(robo
, REG_MII_DATA0
);
145 static u32
robo_read32(robo_t
*robo
, u8 page
, u8 reg
)
147 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
149 return mdio_read(robo
, REG_MII_DATA0
) +
150 (mdio_read(robo
, REG_MII_DATA0
+ 1) << 16);
153 static void robo_write16(robo_t
*robo
, u8 page
, u8 reg
, u16 val16
)
156 mdio_write(robo
, REG_MII_DATA0
, val16
);
158 robo_reg(robo
, page
, reg
, REG_MII_ADDR_WRITE
);
161 static void robo_write32(robo_t
*robo
, u8 page
, u8 reg
, u32 val32
)
164 mdio_write(robo
, REG_MII_DATA0
, val32
& 65535);
165 mdio_write(robo
, REG_MII_DATA0
+ 1, val32
>> 16);
167 robo_reg(robo
, page
, reg
, REG_MII_ADDR_WRITE
);
170 /* checks that attached switch is 5325E/5350 */
171 static int robo_vlan5350(robo_t
*robo
)
173 /* set vlan access id to 15 and read it back */
175 robo_write16(robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
177 /* 5365 will refuse this as it does not have this reg */
178 return (robo_read16(robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
) == val16
);
181 u8 port
[6] = { 0, 1, 2, 3, 4, 8 };
182 char ports
[6] = { 'W', '4', '3', '2', '1', 'C' };
183 char *rxtx
[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
184 char *stp
[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
188 fprintf(stderr
, "Broadcom BCM5325E/536x switch configuration utility\n"
189 "Copyright (C) 2005 Oleg I. Vdovikin\n\n"
190 "This program is distributed in the hope that it will be useful,\n"
191 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
192 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
193 "GNU General Public License for more details.\n\n");
195 fprintf(stderr
, "Usage: robocfg <op> ... <op>\n"
196 "Operations are as below:\n"
198 "\tswitch <enable|disable>\n"
199 "\tport <port_number> [state <%s|%s|%s|%s>]\n\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
200 "\tvlan <vlan_number> [ports <ports_list>]\n"
201 "\tvlans <enable|disable|reset>\n\n"
202 "\tports_list should be one argument, space separated, quoted if needed,\n"
203 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
204 "\tport default) or by 'u' to untag packet (other ports default) before \n"
205 "\tbringing it to the port, '*' is ignored\n"
207 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
208 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
209 " port 0 state enabled stp none switch enable\n"
210 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
211 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
212 " port 0 state enabled stp none switch enable\n",
213 rxtx
[0], rxtx
[1], rxtx
[2], rxtx
[3], stp
[0], stp
[1], stp
[2], stp
[3], stp
[4], stp
[5]);
217 main(int argc
, char *argv
[])
226 struct ethtool_drvinfo info
;
228 if ((robo
.fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
233 /* the only interface for now */
234 strcpy(robo
.ifr
.ifr_name
, "eth0");
236 memset(&info
, 0, sizeof(info
));
237 info
.cmd
= ETHTOOL_GDRVINFO
;
238 robo
.ifr
.ifr_data
= (caddr_t
)&info
;
239 if (ioctl(robo
.fd
, SIOCETHTOOL
, (caddr_t
)&robo
.ifr
) < 0) {
240 perror("SIOCETHTOOL: your ethernet module is either unsupported or outdated");
243 if (strcmp(info
.driver
, "et0") && strcmp(info
.driver
, "b44")) {
244 fprintf(stderr
, "No suitable module found for %s (managed by %s)\n",
245 robo
.ifr
.ifr_name
, info
.driver
);
249 /* try access using MII ioctls - get phy address */
250 if (ioctl(robo
.fd
, SIOCGMIIPHY
, &robo
.ifr
) < 0) {
253 /* got phy address check for robo address */
254 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
.ifr
.ifr_data
;
255 if (mii
->phy_id
!= 30) {
256 fprintf(stderr
, "Invalid phy address (%d)\n", mii
->phy_id
);
261 phyid
= mdio_read(&robo
, 0x2) | (mdio_read(&robo
, 0x3) << 16);
263 if (phyid
== 0xffffffff || phyid
== 0x55210022) {
264 fprintf(stderr
, "No Robo switch in managed mode found\n");
268 robo5350
= robo_vlan5350(&robo
);
270 for (i
= 1; i
< argc
;) {
271 if (strcmp(argv
[i
], "port") == 0 && (i
+ 1) < argc
)
273 int index
= atoi(argv
[++i
]);
274 /* read port specs */
276 if (strcmp(argv
[i
], "state") == 0 && ++i
< argc
) {
277 for (j
= 0; j
< 4 && strcmp(argv
[i
], rxtx
[j
]); j
++);
280 robo_write16(&robo
,ROBO_CTRL_PAGE
, port
[index
],
281 (robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[index
]) & ~(3 << 0)) | (j
<< 0));
283 fprintf(stderr
, "Invalid state '%s'.\n", argv
[i
]);
287 if (strcmp(argv
[i
], "stp") == 0 && ++i
< argc
) {
288 for (j
= 0; j
< 8 && strcmp(argv
[i
], stp
[j
]); j
++);
291 robo_write16(&robo
,ROBO_CTRL_PAGE
, port
[index
],
292 (robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[index
]) & ~(7 << 5)) | (j
<< 5));
294 fprintf(stderr
, "Invalid stp '%s'.\n", argv
[i
]);
298 if (strcmp(argv
[i
], "tag") == 0 && ++i
< argc
) {
300 /* change vlan tag */
301 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_PORT0_DEF_TAG
+ (index
<< 1), j
);
305 if (strcmp(argv
[i
], "vlan") == 0 && (i
+ 1) < argc
)
307 int index
= atoi(argv
[++i
]);
309 if (strcmp(argv
[i
], "ports") == 0 && ++i
< argc
) {
310 char *ports
= argv
[i
];
314 while (*ports
>= '0' && *ports
<= '9') {
318 /* untag if needed, CPU port requires special handling */
319 if (*ports
== 'u' || (j
!= 5 && (*ports
== ' ' || *ports
== 0)))
323 /* change default vlan tag */
324 robo_write16(&robo
, ROBO_VLAN_PAGE
,
325 ROBO_VLAN_PORT0_DEF_TAG
+ (j
<< 1), index
);
327 if (*ports
== '*' || *ports
== 't' || *ports
== ' ') ports
++;
330 while (*ports
== ' ') ports
++;
334 fprintf(stderr
, "Invalid ports '%s'.\n", argv
[i
]);
337 /* write config now */
338 val16
= (index
) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
340 robo_write32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE_5350
,
341 (1 << 20) /* valid */ | (untag
<< 6) | member
);
342 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
344 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE
,
345 (1 << 14) /* valid */ | (untag
<< 7) | member
);
346 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
352 if (strcmp(argv
[i
], "switch") == 0 && (i
+ 1) < argc
)
354 /* enable/disable switching */
355 robo_write16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
,
356 (robo_read16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
) & ~2) |
357 (*argv
[++i
] == 'e' ? 2 : 0));
360 if (strcmp(argv
[i
], "vlans") == 0 && (i
+ 1) < argc
)
363 if (strcmp(argv
[i
], "reset") == 0) {
364 /* reset vlan validity bit */
365 for (j
= 0; j
<= (robo5350
? VLAN_ID_MAX5350
: VLAN_ID_MAX
); j
++)
367 /* write config now */
368 val16
= (j
) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
370 robo_write32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE_5350
, 0);
371 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
373 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE
, 0);
374 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
378 if (strcmp(argv
[i
], "enable") == 0 || strcmp(argv
[i
], "disable") == 0)
380 int disable
= (*argv
[i
] == 'd');
381 /* enable/disable vlans */
382 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL0
, disable
? 0 :
383 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
385 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL1
, disable
? 0 :
386 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
388 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL4
, disable
? 0 :
389 (1 << 6) /* drop invalid VID frames */);
391 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL5
, disable
? 0 :
392 (1 << 3) /* drop miss V table frames */);
397 if (strcmp(argv
[i
], "show") == 0)
401 fprintf(stderr
, "Invalid option %s\n", argv
[i
]);
408 if (argc
== 1) usage();
414 printf("Switch: %sabled\n", robo_read16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
) & 2 ? "en" : "dis");
416 for (i
= 0; i
< 6; i
++) {
417 printf(robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_LINK_STAT_SUMMARY
) & (1 << port
[i
]) ?
418 "Port %d(%c): %s%s " : "Port %d(%c): DOWN ", i
, ports
[i
],
419 robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_SPEED_STAT_SUMMARY
) & (1 << port
[i
]) ? "100" : " 10",
420 robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_DUPLEX_STAT_SUMMARY
) & (1 << port
[i
]) ? "FD" : "HD");
422 val16
= robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[i
]);
424 printf("%s stp: %s vlan: %d ", rxtx
[val16
& 3], stp
[(val16
>> 5) & 7],
425 robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_PORT0_DEF_TAG
+ (i
<< 1)));
427 robo_read(&robo
, ROBO_STAT_PAGE
, ROBO_LSA_PORT0
+ port
[i
] * 6, mac
, 3);
429 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
430 mac
[2] >> 8, mac
[2] & 255, mac
[1] >> 8, mac
[1] & 255, mac
[0] >> 8, mac
[0] & 255);
433 val16
= robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL0
);
435 printf("VLANs: %s %sabled%s%s\n",
436 robo5350
? "BCM5325/535x" : "BCM536x",
437 (val16
& (1 << 7)) ? "en" : "dis",
438 (val16
& (1 << 6)) ? " mac_check" : "",
439 (val16
& (1 << 5)) ? " mac_hash" : "");
442 for (i
= 0; i
<= (robo5350
? VLAN_ID_MAX5350
: VLAN_ID_MAX
); i
++) {
444 val16
= (i
) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
448 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
450 val32
= robo_read32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_READ
);
451 if ((val32
& (1 << 20)) /* valid */) {
452 printf("vlan%d:", i
);
453 for (j
= 0; j
< 6; j
++) {
454 if (val32
& (1 << j
)) {
455 printf(" %d%s", j
, (val32
& (1 << (j
+ 6))) ?
456 (j
== 5 ? "u" : "") : "t");
462 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
464 val16
= robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_READ
);
465 if ((val16
& (1 << 14)) /* valid */) {
466 printf("vlan%d:", i
);
467 for (j
= 0; j
< 6; j
++) {
468 if (val16
& (1 << j
)) {
469 printf(" %d%s", j
, (val16
& (1 << (j
+ 7))) ?
470 (j
== 5 ? "u" : "") : "t");