2 * Common [OS-independent] portion of
3 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet
6 * Copyright (C) 2009, Broadcom Corporation
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 $
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>
28 #include <et_export.h>
33 typedef const struct si_pub si_t
;
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 */
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
);
78 extern struct chops bcmgmac_et_chops
;
80 if (bcmgmac_et_chops
.id(vendor
, device
))
81 return (&bcmgmac_et_chops
);
88 etc_attach(void *et
, uint vendor
, uint device
, uint unit
, void *osh
, void *regsva
)
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
,
104 bzero((char*)etc
, sizeof(etc_info_t
));
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
);
119 if ((etc
->ch
= (*etc
->chops
->attach
)(etc
, osh
, regsva
)) == NULL
) {
120 ET_ERROR(("et%d: chipattach error\n", unit
));
132 etc_detach(etc_info_t
*etc
)
137 /* free chip private state */
139 (*etc
->chops
->detach
)(etc
->ch
);
140 etc
->chops
= etc
->ch
= NULL
;
143 MFREE(etc
->osh
, etc
, sizeof(etc_info_t
));
147 etc_reset(etc_info_t
*etc
)
149 ET_TRACE(("et%d: etc_reset\n", etc
->unit
));
154 (*etc
->chops
->reset
)(etc
->ch
);
156 /* free any posted tx packets */
157 (*etc
->chops
->txreclaim
)(etc
->ch
, TRUE
);
160 /* free any posted rx packets */
161 (*etc
->chops
->rxreclaim
)(etc
->ch
);
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
));
175 (*etc
->chops
->init
)(etc
->ch
, options
);
178 /* mark interface up */
180 etc_up(etc_info_t
*etc
)
184 et_init(etc
->et
, ET_INIT_DEF_OPTIONS
);
187 /* mark interface down */
189 etc_down(etc_info_t
*etc
, int reset
)
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
);
210 /* common iovar handler. return 0=ok, -1=error */
212 etc_iovar(etc_info_t
*etc
, uint cmd
, uint set
, void *arg
)
218 robo_info_t
*robo
= etc
->robo
;
222 ET_TRACE(("et%d: etc_iovar: cmd 0x%x\n", etc
->unit
, cmd
));
226 case IOV_ET_POWER_SAVE_MODE
:
227 vecarg
= (uint
*)arg
;
229 error
= robo_power_save_mode_set(robo
, vecarg
[1], vecarg
[0]);
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
);
238 /* get power save mode of the phy */
239 error
= robo_power_save_mode_get(robo
, vecarg
[0]);
255 /* common ioctl handler. return: 0=ok, -1=error */
257 etc_ioctl(etc_info_t
*etc
, int cmd
, void *arg
)
261 int *vec
= (int*)arg
;
265 val
= arg
? *(int*)arg
: 0;
267 ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc
->unit
, cmd
));
275 et_down(etc
->et
, TRUE
);
279 etc_loopback(etc
, val
);
283 if (et_msg_level
& 0x10000)
284 bcmdumplog((char *)arg
, 4096);
292 etc_promisc(etc
, val
);
300 if (val
== ET_1000FULL
) {
303 } else if (val
== ET_1000HALF
) {
306 } else if (val
== ET_100FULL
) {
309 } else if (val
== ET_100HALF
) {
312 } else if (val
== ET_10FULL
) {
315 } else if (val
== ET_10HALF
) {
318 } else if (val
== ET_AUTO
)
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
;
335 etc
->advertise
= etc
->advertise2
= 0;
336 etc
->needautoneg
= FALSE
;
339 et_init(etc
->et
, ET_INIT_DEF_OPTIONS
);
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]));
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]));
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]);
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]));
384 if (etc
->robo
&& vec
) {
387 robo_info_t
*robo
= (robo_info_t
*)etc
->robo
;
390 reg
= vec
[0] & 0xffff;
392 robo
->ops
->read_reg(etc
->robo
, page
, reg
, &val
, 2);
394 ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n",
400 if (etc
->robo
&& vec
) {
403 robo_info_t
*robo
= (robo_info_t
*)etc
->robo
;
406 reg
= vec
[0] & 0xffff;
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",
424 /* called once per second */
426 etc_watchdog(etc_info_t
*etc
)
431 robo_info_t
*robo
= (robo_info_t
*)etc
->robo
;
432 static uint32 sleep_timer
= PWRSAVE_SLEEP_TIME
, wake_timer
;
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
);
462 /* no local phy registers */
463 if (etc
->phyaddr
== EPHY_NOREG
) {
464 etc
->linkstate
= TRUE
;
466 /* keep emac txcontrol duplex bit consistent with current phy duplex */
467 (*etc
->chops
->duplexupd
)(etc
->ch
);
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
));
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
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
)) {
501 } else if ((adv2
& ADV_1000HALF
) && (status2
& LPA_1000HALF
)) {
504 } else if ((adv
& ADV_100FULL
) && (lpa
& LPA_100FULL
)) {
507 } else if ((adv
& ADV_100HALF
) && (lpa
& LPA_100HALF
)) {
510 } else if ((adv
& ADV_10FULL
) && (lpa
& LPA_10FULL
)) {
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
;
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
);
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
);
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
);
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
);
582 etc_totlen(etc_info_t
*etc
, void *p
)
587 for (; p
; p
= PKTNEXT(etc
->osh
, p
))
588 total
+= PKTLEN(etc
->osh
, p
);