2 * Common [OS-independent] portion of
3 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet
6 * Copyright 2006, 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.1.1.1 2007/03/20 12:22:00 roly Exp $
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>
27 #include <et_export.h>
32 typedef const struct sb_pub sb_t
;
40 /* local prototypes */
41 static void etc_loopback(etc_info_t
*etc
, int on
);
43 /* find the chip opsvec for this chip */
45 etc_chipmatch(uint vendor
, uint device
)
48 extern struct chops bcm47xx_et_chops
;
49 if (bcm47xx_et_chops
.id(vendor
, device
))
50 return (&bcm47xx_et_chops
);
56 etc_attach(void *et
, uint vendor
, uint device
, uint unit
, void *osh
, void *regsva
)
60 ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit
, vendor
, device
));
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
);
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
,
72 bzero((char*)etc
, sizeof(etc_info_t
));
77 etc
->vendorid
= (uint16
) vendor
;
78 etc
->deviceid
= (uint16
) device
;
79 etc
->forcespeed
= ET_AUTO
;
80 etc
->linkstate
= FALSE
;
83 etc
->chops
= etc_chipmatch(vendor
, device
);
87 if ((etc
->ch
= (*etc
->chops
->attach
)(etc
, osh
, regsva
)) == NULL
) {
88 ET_ERROR(("et%d: chipattach error\n", unit
));
100 etc_detach(etc_info_t
*etc
)
105 /* free chip private state */
107 (*etc
->chops
->detach
)(etc
->ch
);
108 etc
->chops
= etc
->ch
= NULL
;
111 MFREE(etc
->osh
, etc
, sizeof(etc_info_t
));
115 etc_reset(etc_info_t
*etc
)
117 ET_TRACE(("et%d: etc_reset\n", etc
->unit
));
122 (*etc
->chops
->reset
)(etc
->ch
);
124 /* free any posted tx packets */
125 (*etc
->chops
->txreclaim
)(etc
->ch
, TRUE
);
128 /* free any posted rx packets */
129 (*etc
->chops
->rxreclaim
)(etc
->ch
);
134 etc_init(etc_info_t
*etc
)
136 ET_TRACE(("et%d: etc_init\n", etc
->unit
));
138 ASSERT(etc
->pioactive
== NULL
);
139 ASSERT(!ETHER_ISNULLADDR(&etc
->cur_etheraddr
));
140 ASSERT(!ETHER_ISMULTI(&etc
->cur_etheraddr
));
143 (*etc
->chops
->init
)(etc
->ch
, TRUE
);
146 /* mark interface up */
148 etc_up(etc_info_t
*etc
)
155 /* mark interface down */
157 etc_down(etc_info_t
*etc
, int reset
)
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
);
177 /* common ioctl handler. return: 0=ok, -1=error */
179 etc_ioctl(etc_info_t
*etc
, int cmd
, void *arg
)
183 int *vec
= (int*)arg
;
187 val
= arg
? *(int*)arg
: 0;
189 ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc
->unit
, cmd
));
197 et_down(etc
->et
, TRUE
);
201 etc_loopback(etc
, val
);
205 if (et_msg_level
& 0x10000)
206 bcmdumplog((char *)arg
, 4096);
214 etc_promisc(etc
, val
);
222 if ((val
!= ET_AUTO
) && (val
!= ET_10HALF
) && (val
!= ET_10FULL
) &&
223 (val
!= ET_100HALF
) && (val
!= ET_100FULL
))
225 etc
->forcespeed
= val
;
227 /* explicitly reset the phy */
228 (*etc
->chops
->phyreset
)(etc
->ch
, etc
->phyaddr
);
230 /* request restart autonegotiation if we're reverting to adv mode */
231 if ((etc
->forcespeed
== ET_AUTO
) & etc
->advertise
)
232 etc
->needautoneg
= TRUE
;
239 vec
[1] = (*etc
->chops
->phyrd
)(etc
->ch
, etc
->phyaddr
, vec
[0]);
240 ET_TRACE(("etc_ioctl: ETCPHYRD of reg 0x%x => 0x%x\n", vec
[0], vec
[1]));
247 phyaddr
= vec
[0] >> 16;
248 if (phyaddr
< MAXEPHY
) {
249 reg
= vec
[0] & 0xffff;
250 vec
[1] = (*etc
->chops
->phyrd
)(etc
->ch
, phyaddr
, reg
);
251 ET_TRACE(("etc_ioctl: ETCPHYRD2 of phy 0x%x, reg 0x%x => 0x%x\n",
252 phyaddr
, reg
, vec
[1]));
259 ET_TRACE(("etc_ioctl: ETCPHYWR to reg 0x%x <= 0x%x\n", vec
[0], vec
[1]));
260 (*etc
->chops
->phywr
)(etc
->ch
, etc
->phyaddr
, vec
[0], (uint16
)vec
[1]);
267 phyaddr
= vec
[0] >> 16;
268 if (phyaddr
< MAXEPHY
) {
269 reg
= vec
[0] & 0xffff;
270 (*etc
->chops
->phywr
)(etc
->ch
, phyaddr
, reg
, (uint16
)vec
[1]);
271 ET_TRACE(("etc_ioctl: ETCPHYWR2 to phy 0x%x, reg 0x%x <= 0x%x\n",
272 phyaddr
, reg
, vec
[1]));
279 if (etc
->robo
&& vec
) {
282 robo_info_t
*robo
= (robo_info_t
*)etc
->robo
;
285 reg
= vec
[0] & 0xffff;
287 robo
->ops
->read_reg(etc
->robo
, page
, reg
, &val
, 2);
289 ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n",
295 if (etc
->robo
&& vec
) {
298 robo_info_t
*robo
= (robo_info_t
*)etc
->robo
;
301 reg
= vec
[0] & 0xffff;
303 robo
->ops
->write_reg(etc
->robo
, page
, vec
[0], &val
, 2);
304 ET_TRACE(("etc_ioctl: ETCROBOWR to page 0x%x, reg 0x%x <= 0x%x\n",
319 /* called once per second */
321 etc_watchdog(etc_info_t
*etc
)
330 /* no local phy registers */
331 if (etc
->phyaddr
== EPHY_NOREG
) {
332 control
= CTL_SPEED
| CTL_DUPLEX
;
335 control
= (*etc
->chops
->phyrd
)(etc
->ch
, etc
->phyaddr
, 0);
336 status
= (*etc
->chops
->phyrd
)(etc
->ch
, etc
->phyaddr
, 1);
339 /* check for bad mdio read */
340 if (control
== 0xffff || status
== 0xffff) {
341 ET_ERROR(("et%d: etc_watchdog: bad mdio read: phyaddr %d mdcport %d\n",
342 etc
->unit
, etc
->phyaddr
, etc
->mdcport
));
346 /* update current speed and duplex */
347 if (control
& CTL_ANENAB
) {
348 adv
= (*etc
->chops
->phyrd
)(etc
->ch
, etc
->phyaddr
, 4);
349 lpa
= (*etc
->chops
->phyrd
)(etc
->ch
, etc
->phyaddr
, 5);
351 if ((adv
& ADV_100FULL
) && (lpa
& LPA_100FULL
)) {
354 } else if ((adv
& ADV_100HALF
) && (lpa
& LPA_100HALF
)) {
357 } else if ((adv
& ADV_10FULL
) && (lpa
& LPA_10FULL
)) {
365 etc
->speed
= (control
& CTL_SPEED
) ? 100 : 10;
366 etc
->duplex
= (control
& CTL_DUPLEX
) ? 1 : 0;
369 /* monitor link state */
370 if (!etc
->linkstate
&& (status
& STAT_LINK
)) {
371 etc
->linkstate
= TRUE
;
373 if (etc
->pm_modechange
)
374 etc
->pm_modechange
= FALSE
;
380 else if (etc
->linkstate
&& !(status
& STAT_LINK
)) {
381 etc
->linkstate
= FALSE
;
382 if (!etc
->pm_modechange
)
384 et_link_down(etc
->et
);
388 /* keep emac txcontrol duplex bit consistent with current phy duplex */
389 (*etc
->chops
->duplexupd
)(etc
->ch
);
391 /* check for remote fault error */
392 if (status
& STAT_REMFAULT
) {
393 ET_ERROR(("et%d: remote fault\n", etc
->unit
));
396 /* check for jabber error */
397 if (status
& STAT_JAB
) {
398 ET_ERROR(("et%d: jabber\n", etc
->unit
));
402 * Read chip mib counters occationally before the 16bit ones can wrap.
403 * We don't use the high-rate mib counters.
405 if ((etc
->now
% 30) == 0)
406 (*etc
->chops
->statsupd
)(etc
->ch
);
410 etc_loopback(etc_info_t
*etc
, int on
)
412 ET_TRACE(("et%d: etc_loopback: %d\n", etc
->unit
, on
));
414 etc
->loopbk
= (bool) on
;
419 etc_promisc(etc_info_t
*etc
, uint on
)
421 ET_TRACE(("et%d: etc_promisc: %d\n", etc
->unit
, on
));
423 etc
->promisc
= (bool) on
;
428 etc_qos(etc_info_t
*etc
, uint on
)
430 ET_TRACE(("et%d: etc_qos: %d\n", etc
->unit
, on
));
432 etc
->qos
= (bool) on
;
438 etc_totlen(etc_info_t
*etc
, void *p
)
443 for (; p
; p
= PKTNEXT(etc
->osh
, p
))
444 total
+= PKTLEN(etc
->osh
, p
);