1/* 2 * Common [OS-independent] portion of 3 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet 4 * Device Driver. 5 * 6 * Copyright 2007, Broadcom Corporation 7 * All Rights Reserved. 8 * 9 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; 10 * the contents of this file may not be disclosed to third parties, copied 11 * or duplicated in any form, in whole or in part, without the prior 12 * written permission of Broadcom Corporation. 13 * $Id: etc.c,v 1.1.1.1 2008/10/15 03:25:54 james26_jang Exp $ 14 */ 15 16#include <typedefs.h> 17#include <osl.h> 18#include <bcmendian.h> 19#include <proto/ethernet.h> 20#include <proto/vlan.h> 21#include <proto/bcmip.h> 22#include <bcmenetmib.h> 23#include <bcmenetrxh.h> 24#include <bcmenetphy.h> 25#include <et_dbg.h> 26#include <etc.h> 27#include <et_export.h> 28#include <bcmutils.h> 29 30#ifdef ETROBO 31#ifndef _sbutils_h_ 32typedef const struct sb_pub sb_t; 33#endif 34#include <bcmrobo.h> 35#endif /* ETROBO */ 36 37uint32 et_msg_level = 38 0; 39 40/* local prototypes */ 41static void etc_loopback(etc_info_t *etc, int on); 42 43/* find the chip opsvec for this chip */ 44struct chops* 45etc_chipmatch(uint vendor, uint device) 46{ 47 { 48 extern struct chops bcm47xx_et_chops; 49 if (bcm47xx_et_chops.id(vendor, device)) 50 return (&bcm47xx_et_chops); 51 } 52 return (NULL); 53} 54 55void* 56etc_attach(void *et, uint vendor, uint device, uint unit, void *osh, void *regsva) 57{ 58 etc_info_t *etc; 59 60 ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit, vendor, device)); 61 62 /* some code depends on packed structures */ 63 ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN); 64 ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN); 65 66 /* allocate etc_info_t state structure */ 67 if ((etc = (etc_info_t*) MALLOC(osh, sizeof(etc_info_t))) == NULL) { 68 ET_ERROR(("et%d: etc_attach: out of memory, malloced %d bytes\n", unit, 69 MALLOCED(osh))); 70 return (NULL); 71 } 72 bzero((char*)etc, sizeof(etc_info_t)); 73 74 etc->et = et; 75 etc->unit = unit; 76 etc->osh = osh; 77 etc->vendorid = (uint16) vendor; 78 etc->deviceid = (uint16) device; 79 etc->forcespeed = ET_AUTO; 80 etc->linkstate = FALSE; 81 82 /* set chip opsvec */ 83 etc->chops = etc_chipmatch(vendor, device); 84 ASSERT(etc->chops); 85 86 /* chip attach */ 87 if ((etc->ch = (*etc->chops->attach)(etc, osh, regsva)) == NULL) { 88 ET_ERROR(("et%d: chipattach error\n", unit)); 89 goto fail; 90 } 91 92 return ((void*)etc); 93 94fail: 95 etc_detach(etc); 96 return (NULL); 97} 98 99void 100etc_detach(etc_info_t *etc) 101{ 102 if (etc == NULL) 103 return; 104 105 /* free chip private state */ 106 if (etc->ch) { 107 (*etc->chops->detach)(etc->ch); 108 etc->chops = etc->ch = NULL; 109 } 110 111 MFREE(etc->osh, etc, sizeof(etc_info_t)); 112} 113 114void 115etc_reset(etc_info_t *etc) 116{ 117 ET_TRACE(("et%d: etc_reset\n", etc->unit)); 118 119 etc->reset++; 120 121 /* reset the chip */ 122 (*etc->chops->reset)(etc->ch); 123 124 /* free any posted tx packets */ 125 (*etc->chops->txreclaim)(etc->ch, TRUE); 126 127#ifdef DMA 128 /* free any posted rx packets */ 129 (*etc->chops->rxreclaim)(etc->ch); 130#endif /* DMA */ 131} 132 133void 134etc_init(etc_info_t *etc) 135{ 136 ET_TRACE(("et%d: etc_init\n", etc->unit)); 137 138 ASSERT(etc->pioactive == NULL); 139 ASSERT(!ETHER_ISNULLADDR(&etc->cur_etheraddr)); 140 ASSERT(!ETHER_ISMULTI(&etc->cur_etheraddr)); 141 142 /* init the chip */ 143 (*etc->chops->init)(etc->ch, TRUE); 144} 145 146/* mark interface up */ 147void 148etc_up(etc_info_t *etc) 149{ 150 etc->up = TRUE; 151 152 et_init(etc->et); 153} 154 155/* mark interface down */ 156uint 157etc_down(etc_info_t *etc, int reset) 158{ 159 uint callback; 160 161 callback = 0; 162 163 etc->up = FALSE; 164 if (reset) 165 et_reset(etc->et); 166 167 /* suppress link state changes during power management mode changes */ 168 if (etc->linkstate) { 169 etc->linkstate = FALSE; 170 if (!etc->pm_modechange) 171 et_link_down(etc->et); 172 } 173 174 return (callback); 175} 176 177unsigned int etc_arl_dump(etc_info_t *etc, char *buff, int maxno) 178{ 179 uint8 val; 180 uint8 res_reg[8]; 181 uint8 res_ext_reg; 182 int size=0; 183 int offset=0; 184 int count=0; 185 int port_id = -1; 186 187 robo_info_t *robo = (robo_info_t *)etc->robo; 188 189 //printk(KERN_ERR "etc_arl_dump\n"); 190 191 if (etc->robo) 192 { 193 robo->ops->read_reg(etc->robo, 0x04, 0x0, &val, 1); 194 // ARL Search Control Register page=5 addr=0x20 195 // start 196 val = 0x80; 197 robo->ops->write_reg(etc->robo, 0x05, 0x20, &val, 1); 198 while(1) 199 { 200 robo->ops->read_reg(etc->robo, 0x05, 0x20, &val, 1); 201 if(val&0x80) 202 { 203 if(val&0x01) 204 { 205 robo->ops->read_reg(etc->robo, 0x05, 0x2c, &res_ext_reg, 1); 206 robo->ops->read_reg(etc->robo, 0x05, 0x24, res_reg, 8); 207 port_id = -1; 208 port_id = (int)res_reg[6]; 209 if(port_id < 0 || port_id > 3) 210 continue; 211 size = sprintf(buff+offset, "%02x:%02x:%02x:%02x:%02x:%02x %02x %02x %02x\n", res_reg[5], res_reg[4], res_reg[3], res_reg[2], res_reg[1], res_reg[0], res_reg[6], res_reg[7], res_ext_reg); 212 //printk("rreg: %s\n", buff+offset); 213 offset+=size; 214 count++; 215 if(count>=maxno) break; 216 } 217 } 218 else break; 219 } 220 } 221 //printk("%x %x %x %x\n", offset, count, maxno, *len); 222 return offset; 223} 224 225/* common ioctl handler. return: 0=ok, -1=error */ 226int 227etc_ioctl(etc_info_t *etc, int cmd, void *arg) 228{ 229 int error; 230 int val; 231 int *vec = (int*)arg; 232 233 error = 0; 234 235 val = arg ? *(int*)arg : 0; 236 237 ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd)); 238 239 switch (cmd) { 240 case ETCUP: 241 et_up(etc->et); 242 break; 243 244 case ETCDOWN: 245 et_down(etc->et, TRUE); 246 break; 247 248 case ETCLOOP: 249 etc_loopback(etc, val); 250 break; 251 252 case ETCDUMP: 253 if (et_msg_level & 0x10000) 254 bcmdumplog((char *)arg, 4096); 255 break; 256 257 case ETCSETMSGLEVEL: 258 et_msg_level = val; 259 break; 260 261 case ETCPROMISC: 262 etc_promisc(etc, val); 263 break; 264 265 case ETCQOS: 266 etc_qos(etc, val); 267 break; 268 269 case ETCSPEED: 270 if ((val != ET_AUTO) && (val != ET_10HALF) && (val != ET_10FULL) && 271 (val != ET_100HALF) && (val != ET_100FULL)) 272 goto err; 273 etc->forcespeed = val; 274 275 /* explicitly reset the phy */ 276 (*etc->chops->phyreset)(etc->ch, etc->phyaddr); 277 278 /* request restart autonegotiation if we're reverting to adv mode */ 279 if ((etc->forcespeed == ET_AUTO) & etc->advertise) 280 etc->needautoneg = TRUE; 281 282 et_init(etc->et); 283 break; 284 285 case ETCPHYRD: 286 if (vec) { 287 vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]); 288 ET_TRACE(("etc_ioctl: ETCPHYRD of reg 0x%x => 0x%x\n", vec[0], vec[1])); 289 } 290 break; 291 292 case ETCPHYRD2: 293 if (vec) { 294 uint phyaddr, reg; 295 phyaddr = vec[0] >> 16; 296 if (phyaddr < MAXEPHY) { 297 reg = vec[0] & 0xffff; 298 vec[1] = (*etc->chops->phyrd)(etc->ch, phyaddr, reg); 299 ET_TRACE(("etc_ioctl: ETCPHYRD2 of phy 0x%x, reg 0x%x => 0x%x\n", 300 phyaddr, reg, vec[1])); 301 } 302 } 303 break; 304 305 case ETCPHYWR: 306 if (vec) { 307 ET_TRACE(("etc_ioctl: ETCPHYWR to reg 0x%x <= 0x%x\n", vec[0], vec[1])); 308 (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16)vec[1]); 309 } 310 break; 311 312 case ETCPHYWR2: 313 if (vec) { 314 uint phyaddr, reg; 315 phyaddr = vec[0] >> 16; 316 if (phyaddr < MAXEPHY) { 317 reg = vec[0] & 0xffff; 318 (*etc->chops->phywr)(etc->ch, phyaddr, reg, (uint16)vec[1]); 319 ET_TRACE(("etc_ioctl: ETCPHYWR2 to phy 0x%x, reg 0x%x <= 0x%x\n", 320 phyaddr, reg, vec[1])); 321 } 322 } 323 break; 324 325#ifdef ETROBO 326 case ETCROBORD: 327 if (etc->robo && vec) { 328 uint page, reg; 329 uint16 val; 330 robo_info_t *robo = (robo_info_t *)etc->robo; 331 332 page = vec[0] >> 16; 333 reg = vec[0] & 0xffff; 334 val = -1; 335 robo->ops->read_reg(etc->robo, page, reg, &val, 2); 336 vec[1] = val; 337 ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n", 338 page, reg, val)); 339 } 340 break; 341 342 case ETCROBOWR: 343 if (etc->robo && vec) { 344 uint page, reg; 345 uint16 val; 346 robo_info_t *robo = (robo_info_t *)etc->robo; 347 348 page = vec[0] >> 16; 349 reg = vec[0] & 0xffff; 350 val = vec[1]; 351 robo->ops->write_reg(etc->robo, page, vec[0], &val, 2); 352 ET_TRACE(("etc_ioctl: ETCROBOWR to page 0x%x, reg 0x%x <= 0x%x\n", 353 page, reg, val)); 354 } 355 break; 356#endif /* ETROBO */ 357 358 359 default: 360 err: 361 error = -1; 362 } 363 364 return (error); 365} 366 367/* called once per second */ 368void 369etc_watchdog(etc_info_t *etc) 370{ 371 uint16 status; 372 uint16 adv; 373 uint16 lpa; 374 375 etc->now++; 376 377 /* no local phy registers */ 378 if (etc->phyaddr == EPHY_NOREG) { 379 etc->linkstate = TRUE; 380 etc->speed = 100; 381 etc->duplex = 1; 382 return; 383 } 384 385 status = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 1); 386 adv = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 4); 387 lpa = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 5); 388 389 /* check for bad mdio read */ 390 if (status == 0xffff) { 391 ET_ERROR(("et%d: etc_watchdog: bad mdio read: phyaddr %d mdcport %d\n", 392 etc->unit, etc->phyaddr, etc->mdcport)); 393 return; 394 } 395 396 /* monitor link state */ 397 if (!etc->linkstate && (status & STAT_LINK)) { 398 etc->linkstate = TRUE; 399 400 if (etc->pm_modechange) 401 etc->pm_modechange = FALSE; 402 else 403 et_link_up(etc->et); 404 } 405 else if (etc->linkstate && !(status & STAT_LINK)) { 406 etc->linkstate = FALSE; 407 if (!etc->pm_modechange) 408 et_link_down(etc->et); 409 } 410 411 /* update current speed and duplex */ 412 if ((adv & ADV_100FULL) && (lpa & LPA_100FULL)) { 413 etc->speed = 100; 414 etc->duplex = 1; 415 } else if ((adv & ADV_100HALF) && (lpa & LPA_100HALF)) { 416 etc->speed = 100; 417 etc->duplex = 0; 418 } else if ((adv & ADV_10FULL) && (lpa & LPA_10FULL)) { 419 etc->speed = 10; 420 etc->duplex = 1; 421 } else { 422 etc->speed = 10; 423 etc->duplex = 0; 424 } 425 426 /* keep emac txcontrol duplex bit consistent with current phy duplex */ 427 (*etc->chops->duplexupd)(etc->ch); 428 429 /* check for remote fault error */ 430 if (status & STAT_REMFAULT) { 431 ET_ERROR(("et%d: remote fault\n", etc->unit)); 432 } 433 434 /* check for jabber error */ 435 if (status & STAT_JAB) { 436 ET_ERROR(("et%d: jabber\n", etc->unit)); 437 } 438 439 /* 440 * Read chip mib counters occationally before the 16bit ones can wrap. 441 * We don't use the high-rate mib counters. 442 */ 443 if ((etc->now % 30) == 0) 444 (*etc->chops->statsupd)(etc->ch); 445} 446 447static void 448etc_loopback(etc_info_t *etc, int on) 449{ 450 ET_TRACE(("et%d: etc_loopback: %d\n", etc->unit, on)); 451 452 etc->loopbk = (bool) on; 453 et_init(etc->et); 454} 455 456void 457etc_promisc(etc_info_t *etc, uint on) 458{ 459 ET_TRACE(("et%d: etc_promisc: %d\n", etc->unit, on)); 460 461 etc->promisc = (bool) on; 462 et_init(etc->et); 463} 464 465void 466etc_qos(etc_info_t *etc, uint on) 467{ 468 ET_TRACE(("et%d: etc_qos: %d\n", etc->unit, on)); 469 470 etc->qos = (bool) on; 471 et_init(etc->et); 472} 473 474 475uint 476etc_totlen(etc_info_t *etc, void *p) 477{ 478 uint total; 479 480 total = 0; 481 for (; p; p = PKTNEXT(etc->osh, p)) 482 total += PKTLEN(etc->osh, p); 483 return (total); 484} 485 486