Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / et / sys / etc.c
blob2792baeddb8012b9f74b43bd2ec840b40785af29
1 /*
2 * Common [OS-independent] portion of
3 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet
4 * Device Driver.
6 * Copyright (C) 2009, 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.105.2.5 2009/07/17 23:40:42 Exp $
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 <proto/802.1d.h>
23 #include <bcmenetmib.h>
24 #include <bcmenetrxh.h>
25 #include <bcmenetphy.h>
26 #include <et_dbg.h>
27 #include <etc.h>
28 #include <et_export.h>
29 #include <bcmutils.h>
31 #ifdef ETROBO
32 #ifndef _siutils_h_
33 typedef const struct si_pub si_t;
34 #endif
35 #include <bcmrobo.h>
36 #endif /* ETROBO */
38 uint32 et_msg_level =
41 /* local prototypes */
42 static void etc_loopback(etc_info_t *etc, int on);
44 /* 802.1d priority to traffic class mapping. queues correspond one-to-one
45 * with traffic classes.
47 uint32 up2tc[NUMPRIO] = {
48 TC_BE, /* 0 BE TC_BE Best Effort */
49 TC_BK, /* 1 BK TC_BK Background */
50 TC_BK, /* 2 -- TC_BK Background */
51 TC_BE, /* 3 EE TC_BE Best Effort */
52 TC_CL, /* 4 CL TC_CL Controlled Load */
53 TC_CL, /* 5 VI TC_CL Controlled Load */
54 TC_VO, /* 6 VO TC_VO Voice */
55 TC_VO /* 7 NC TC_VO Voice */
58 uint32 priq_selector[] = {
59 [0x0] = TC_NONE, [0x1] = TC_BK, [0x2] = TC_BE, [0x3] = TC_BE,
60 [0x4] = TC_CL, [0x5] = TC_CL, [0x6] = TC_CL, [0x7] = TC_CL,
61 [0x8] = TC_VO, [0x9] = TC_VO, [0xa] = TC_VO, [0xb] = TC_VO,
62 [0xc] = TC_VO, [0xd] = TC_VO, [0xe] = TC_VO, [0xf] = TC_VO
65 /* find the chip opsvec for this chip */
66 struct chops*
67 etc_chipmatch(uint vendor, uint device)
70 extern struct chops bcm47xx_et_chops;
72 if (bcm47xx_et_chops.id(vendor, device))
73 return (&bcm47xx_et_chops);
76 #ifdef CFG_GMAC
78 extern struct chops bcmgmac_et_chops;
80 if (bcmgmac_et_chops.id(vendor, device))
81 return (&bcmgmac_et_chops);
83 #endif /* CFG_GMAC */
84 return (NULL);
87 void*
88 etc_attach(void *et, uint vendor, uint device, uint unit, void *osh, void *regsva)
90 etc_info_t *etc;
92 ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit, vendor, device));
94 /* some code depends on packed structures */
95 ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN);
96 ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN);
98 /* allocate etc_info_t state structure */
99 if ((etc = (etc_info_t*) MALLOC(osh, sizeof(etc_info_t))) == NULL) {
100 ET_ERROR(("et%d: etc_attach: out of memory, malloced %d bytes\n", unit,
101 MALLOCED(osh)));
102 return (NULL);
104 bzero((char*)etc, sizeof(etc_info_t));
106 etc->et = et;
107 etc->unit = unit;
108 etc->osh = osh;
109 etc->vendorid = (uint16) vendor;
110 etc->deviceid = (uint16) device;
111 etc->forcespeed = ET_AUTO;
112 etc->linkstate = FALSE;
114 /* set chip opsvec */
115 etc->chops = etc_chipmatch(vendor, device);
116 ASSERT(etc->chops);
118 /* chip attach */
119 if ((etc->ch = (*etc->chops->attach)(etc, osh, regsva)) == NULL) {
120 ET_ERROR(("et%d: chipattach error\n", unit));
121 goto fail;
124 return ((void*)etc);
126 fail:
127 etc_detach(etc);
128 return (NULL);
131 void
132 etc_detach(etc_info_t *etc)
134 if (etc == NULL)
135 return;
137 /* free chip private state */
138 if (etc->ch) {
139 (*etc->chops->detach)(etc->ch);
140 etc->chops = etc->ch = NULL;
143 MFREE(etc->osh, etc, sizeof(etc_info_t));
146 void
147 etc_reset(etc_info_t *etc)
149 ET_TRACE(("et%d: etc_reset\n", etc->unit));
151 etc->reset++;
153 /* reset the chip */
154 (*etc->chops->reset)(etc->ch);
156 /* free any posted tx packets */
157 (*etc->chops->txreclaim)(etc->ch, TRUE);
159 #ifdef DMA
160 /* free any posted rx packets */
161 (*etc->chops->rxreclaim)(etc->ch);
162 #endif /* DMA */
165 void
166 etc_init(etc_info_t *etc, uint options)
168 ET_TRACE(("et%d: etc_init\n", etc->unit));
170 ASSERT(etc->pioactive == NULL);
171 ASSERT(!ETHER_ISNULLADDR(&etc->cur_etheraddr));
172 ASSERT(!ETHER_ISMULTI(&etc->cur_etheraddr));
174 /* init the chip */
175 (*etc->chops->init)(etc->ch, options);
178 /* mark interface up */
179 void
180 etc_up(etc_info_t *etc)
182 etc->up = TRUE;
184 et_init(etc->et, ET_INIT_DEF_OPTIONS);
187 /* mark interface down */
188 uint
189 etc_down(etc_info_t *etc, int reset)
191 uint callback;
193 callback = 0;
195 ET_FLAG_DOWN(etc);
197 if (reset)
198 et_reset(etc->et);
200 /* suppress link state changes during power management mode changes */
201 if (etc->linkstate) {
202 etc->linkstate = FALSE;
203 if (!etc->pm_modechange)
204 et_link_down(etc->et);
207 return (callback);
210 /* common iovar handler. return 0=ok, -1=error */
212 etc_iovar(etc_info_t *etc, uint cmd, uint set, void *arg)
214 int error;
215 #ifdef ETROBO
216 int i;
217 uint *vecarg;
218 robo_info_t *robo = etc->robo;
219 #endif
221 error = 0;
222 ET_TRACE(("et%d: etc_iovar: cmd 0x%x\n", etc->unit, cmd));
224 switch (cmd) {
225 #ifdef ETROBO
226 case IOV_ET_POWER_SAVE_MODE:
227 vecarg = (uint *)arg;
228 if (set)
229 error = robo_power_save_mode_set(robo, vecarg[1], vecarg[0]);
230 else {
231 /* get power save mode of all the phys */
232 if (vecarg[0] == MAX_NO_PHYS) {
233 for (i = 0; i < MAX_NO_PHYS; i++)
234 vecarg[i] = robo_power_save_mode_get(robo, i);
235 break;
238 /* get power save mode of the phy */
239 error = robo_power_save_mode_get(robo, vecarg[0]);
240 if (error != -1) {
241 vecarg[1] = error;
242 error = 0;
245 break;
246 #endif /* ETROBO */
248 default:
249 error = -1;
252 return (error);
255 /* common ioctl handler. return: 0=ok, -1=error */
257 etc_ioctl(etc_info_t *etc, int cmd, void *arg)
259 int error;
260 int val;
261 int *vec = (int*)arg;
263 error = 0;
265 val = arg ? *(int*)arg : 0;
267 ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd));
269 switch (cmd) {
270 case ETCUP:
271 et_up(etc->et);
272 break;
274 case ETCDOWN:
275 et_down(etc->et, TRUE);
276 break;
278 case ETCLOOP:
279 etc_loopback(etc, val);
280 break;
282 case ETCDUMP:
283 if (et_msg_level & 0x10000)
284 bcmdumplog((char *)arg, 4096);
285 break;
287 case ETCSETMSGLEVEL:
288 et_msg_level = val;
289 break;
291 case ETCPROMISC:
292 etc_promisc(etc, val);
293 break;
295 case ETCQOS:
296 etc_qos(etc, val);
297 break;
299 case ETCSPEED:
300 if (val == ET_1000FULL) {
301 etc->speed = 1000;
302 etc->duplex = 1;
303 } else if (val == ET_1000HALF) {
304 etc->speed = 1000;
305 etc->duplex = 0;
306 } else if (val == ET_100FULL) {
307 etc->speed = 100;
308 etc->duplex = 1;
309 } else if (val == ET_100HALF) {
310 etc->speed = 100;
311 etc->duplex = 0;
312 } else if (val == ET_10FULL) {
313 etc->speed = 10;
314 etc->duplex = 1;
315 } else if (val == ET_10HALF) {
316 etc->speed = 10;
317 etc->duplex = 0;
318 } else if (val == ET_AUTO)
320 else
321 goto err;
323 etc->forcespeed = val;
325 /* explicitly reset the phy */
326 (*etc->chops->phyreset)(etc->ch, etc->phyaddr);
328 /* request restart autonegotiation if we're reverting to adv mode */
329 if (etc->forcespeed == ET_AUTO) {
330 etc->advertise = (ADV_100FULL | ADV_100HALF |
331 ADV_10FULL | ADV_10HALF);
332 etc->advertise2 = ADV_1000FULL;
333 etc->needautoneg = TRUE;
334 } else {
335 etc->advertise = etc->advertise2 = 0;
336 etc->needautoneg = FALSE;
339 et_init(etc->et, ET_INIT_DEF_OPTIONS);
340 break;
342 case ETCPHYRD:
343 if (vec) {
344 vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]);
345 ET_TRACE(("etc_ioctl: ETCPHYRD of reg 0x%x => 0x%x\n", vec[0], vec[1]));
347 break;
349 case ETCPHYRD2:
350 if (vec) {
351 uint phyaddr, reg;
352 phyaddr = vec[0] >> 16;
353 if (phyaddr < MAXEPHY) {
354 reg = vec[0] & 0xffff;
355 vec[1] = (*etc->chops->phyrd)(etc->ch, phyaddr, reg);
356 ET_TRACE(("etc_ioctl: ETCPHYRD2 of phy 0x%x, reg 0x%x => 0x%x\n",
357 phyaddr, reg, vec[1]));
360 break;
362 case ETCPHYWR:
363 if (vec) {
364 ET_TRACE(("etc_ioctl: ETCPHYWR to reg 0x%x <= 0x%x\n", vec[0], vec[1]));
365 (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16)vec[1]);
367 break;
369 case ETCPHYWR2:
370 if (vec) {
371 uint phyaddr, reg;
372 phyaddr = vec[0] >> 16;
373 if (phyaddr < MAXEPHY) {
374 reg = vec[0] & 0xffff;
375 (*etc->chops->phywr)(etc->ch, phyaddr, reg, (uint16)vec[1]);
376 ET_TRACE(("etc_ioctl: ETCPHYWR2 to phy 0x%x, reg 0x%x <= 0x%x\n",
377 phyaddr, reg, vec[1]));
380 break;
382 #ifdef ETROBO
383 case ETCROBORD:
384 if (etc->robo && vec) {
385 uint page, reg;
386 uint16 val;
387 robo_info_t *robo = (robo_info_t *)etc->robo;
389 page = vec[0] >> 16;
390 reg = vec[0] & 0xffff;
391 val = -1;
392 robo->ops->read_reg(etc->robo, page, reg, &val, 2);
393 vec[1] = val;
394 ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n",
395 page, reg, val));
397 break;
399 case ETCROBOWR:
400 if (etc->robo && vec) {
401 uint page, reg;
402 uint16 val;
403 robo_info_t *robo = (robo_info_t *)etc->robo;
405 page = vec[0] >> 16;
406 reg = vec[0] & 0xffff;
407 val = vec[1];
408 robo->ops->write_reg(etc->robo, page, vec[0], &val, 2);
409 ET_TRACE(("etc_ioctl: ETCROBOWR to page 0x%x, reg 0x%x <= 0x%x\n",
410 page, reg, val));
412 break;
413 #endif /* ETROBO */
416 default:
417 err:
418 error = -1;
421 return (error);
424 /* called once per second */
425 void
426 etc_watchdog(etc_info_t *etc)
428 uint16 status;
429 uint16 lpa;
430 #ifdef ETROBO
431 robo_info_t *robo = (robo_info_t *)etc->robo;
432 static uint32 sleep_timer = PWRSAVE_SLEEP_TIME, wake_timer;
433 #endif
435 etc->now++;
437 #ifdef ETROBO
438 /* Every PWRSAVE_WAKE_TIME sec the phys are put into the normal
439 * mode and link status is checked after PWRSAVE_SLEEP_TIME sec
440 * to see if any of the links is up. If any of the links is up
441 * then that port is taken out of the manual power save mode
443 if (robo && (robo->pwrsave_mode_manual | robo->pwrsave_mode_auto)) {
444 if (etc->now == sleep_timer) {
445 robo_power_save_toggle(robo, 0);
446 wake_timer = sleep_timer + PWRSAVE_WAKE_TIME;
447 } else if (etc->now == wake_timer) {
448 robo_power_save_mode_update(robo, FALSE);
449 robo_power_save_toggle(robo, 1);
450 sleep_timer = wake_timer + PWRSAVE_SLEEP_TIME;
453 /* Check the link status. if the link goes down put the
454 * corresponding phy in power save mode (auto, manual or
455 * both). if link comes up put the phy in normal mode.
457 if (etc->now == PWRSAVE_WAKE_TIME)
458 robo_power_save_mode_update(robo, TRUE);
460 #endif /* ETROBO */
462 /* no local phy registers */
463 if (etc->phyaddr == EPHY_NOREG) {
464 etc->linkstate = TRUE;
465 etc->duplex = 1;
466 /* keep emac txcontrol duplex bit consistent with current phy duplex */
467 (*etc->chops->duplexupd)(etc->ch);
468 return;
471 status = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 1);
472 /* check for bad mdio read */
473 if (status == 0xffff) {
474 ET_ERROR(("et%d: etc_watchdog: bad mdio read: phyaddr %d mdcport %d\n",
475 etc->unit, etc->phyaddr, etc->mdcport));
476 return;
479 if (etc->forcespeed == ET_AUTO) {
480 uint16 adv, adv2 = 0, status2 = 0, estatus;
482 adv = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 4);
483 lpa = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 5);
485 /* read extended status register. if we are 1000BASE-T
486 * capable then get our advertised capabilities and the
487 * link partner capabilities from 1000BASE-T control and
488 * status registers.
490 estatus = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 15);
491 if ((estatus != 0xffff) && (estatus & EST_1000TFULL)) {
492 /* read 1000BASE-T control and status registers */
493 adv2 = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 9);
494 status2 = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 10);
497 /* update current speed and duplex */
498 if ((adv2 & ADV_1000FULL) && (status2 & LPA_1000FULL)) {
499 etc->speed = 1000;
500 etc->duplex = 1;
501 } else if ((adv2 & ADV_1000HALF) && (status2 & LPA_1000HALF)) {
502 etc->speed = 1000;
503 etc->duplex = 0;
504 } else if ((adv & ADV_100FULL) && (lpa & LPA_100FULL)) {
505 etc->speed = 100;
506 etc->duplex = 1;
507 } else if ((adv & ADV_100HALF) && (lpa & LPA_100HALF)) {
508 etc->speed = 100;
509 etc->duplex = 0;
510 } else if ((adv & ADV_10FULL) && (lpa & LPA_10FULL)) {
511 etc->speed = 10;
512 etc->duplex = 1;
513 } else {
514 etc->speed = 10;
515 etc->duplex = 0;
519 /* monitor link state */
520 if (!etc->linkstate && (status & STAT_LINK)) {
521 etc->linkstate = TRUE;
522 if (etc->pm_modechange)
523 etc->pm_modechange = FALSE;
524 else
525 et_link_up(etc->et);
526 } else if (etc->linkstate && !(status & STAT_LINK)) {
527 etc->linkstate = FALSE;
528 if (!etc->pm_modechange)
529 et_link_down(etc->et);
532 /* keep emac txcontrol duplex bit consistent with current phy duplex */
533 (*etc->chops->duplexupd)(etc->ch);
535 /* check for remote fault error */
536 if (status & STAT_REMFAULT) {
537 ET_ERROR(("et%d: remote fault\n", etc->unit));
540 /* check for jabber error */
541 if (status & STAT_JAB) {
542 ET_ERROR(("et%d: jabber\n", etc->unit));
546 * Read chip mib counters occationally before the 16bit ones can wrap.
547 * We don't use the high-rate mib counters.
549 if ((etc->now % 30) == 0)
550 (*etc->chops->statsupd)(etc->ch);
553 static void
554 etc_loopback(etc_info_t *etc, int on)
556 ET_TRACE(("et%d: etc_loopback: %d\n", etc->unit, on));
558 etc->loopbk = (bool) on;
559 et_init(etc->et, ET_INIT_DEF_OPTIONS);
562 void
563 etc_promisc(etc_info_t *etc, uint on)
565 ET_TRACE(("et%d: etc_promisc: %d\n", etc->unit, on));
567 etc->promisc = (bool) on;
568 et_init(etc->et, ET_INIT_DEF_OPTIONS);
571 void
572 etc_qos(etc_info_t *etc, uint on)
574 ET_TRACE(("et%d: etc_qos: %d\n", etc->unit, on));
576 etc->qos = (bool) on;
577 et_init(etc->et, ET_INIT_DEF_OPTIONS);
581 uint
582 etc_totlen(etc_info_t *etc, void *p)
584 uint total;
586 total = 0;
587 for (; p; p = PKTNEXT(etc->osh, p))
588 total += PKTLEN(etc->osh, p);
589 return (total);