2 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet core.
4 * This file implements the chip-specific routines
5 * for Broadcom HNBU Sonics SiliconBackplane enet cores.
7 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
16 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * $Id: etc47xx.c 286404 2011-09-27 19:29:08Z $
27 #include <bcmendian.h>
30 #include <proto/ethernet.h>
36 #include <bcmenet47xx.h>
37 #include <et_export.h> /* for et_phyxx() routines */
46 struct bcm4xxx
; /* forward declaration */
47 #define ch_t struct bcm4xxx
50 /* private chip state */
52 void *et
; /* pointer to et private state */
53 etc_info_t
*etc
; /* pointer to etc public state */
55 bcmenetregs_t
*regs
; /* pointer to chip registers */
56 osl_t
*osh
; /* os handle */
58 void *etphy
; /* pointer to et for shared mdc/mdio contortion */
60 uint32 intstatus
; /* saved interrupt condition bits */
61 uint32 intmask
; /* current software interrupt mask */
63 hnddma_t
*di
; /* dma engine software state */
65 bool mibgood
; /* true once mib registers have been cleared */
66 bcmenetmib_t mib
; /* mib counters */
67 si_t
*sih
; /* si utils handle */
69 char *vars
; /* sprom name=value */
72 void *adm
; /* optional admtek private data */
75 /* local prototypes */
76 static bool chipid(uint vendor
, uint device
);
77 static void *chipattach(etc_info_t
*etc
, void *osh
, void *regsva
);
78 static void chipdetach(ch_t
*ch
);
79 static void chipreset(ch_t
*ch
);
80 static void chipinit(ch_t
*ch
, uint options
);
81 static bool chiptx(ch_t
*ch
, void *p
);
82 static void *chiprx(ch_t
*ch
);
83 static void chiprxfill(ch_t
*ch
);
84 static int chipgetintrevents(ch_t
*ch
, bool in_isr
);
85 static bool chiperrors(ch_t
*ch
);
86 static void chipintrson(ch_t
*ch
);
87 static void chipintrsoff(ch_t
*ch
);
88 static void chiptxreclaim(ch_t
*ch
, bool all
);
89 static void chiprxreclaim(ch_t
*ch
);
90 static void chipstatsupd(ch_t
*ch
);
91 static void chipdumpmib(ch_t
*ch
, struct bcmstrbuf
*b
, bool clear
);
92 static void chipenablepme(ch_t
*ch
);
93 static void chipdisablepme(ch_t
*ch
);
94 static void chipphyreset(ch_t
*ch
, uint phyaddr
);
95 static void chipphyinit(ch_t
*ch
, uint phyaddr
);
96 static uint16
chipphyrd(ch_t
*ch
, uint phyaddr
, uint reg
);
97 static void chipdump(ch_t
*ch
, struct bcmstrbuf
*b
);
98 static void chiplongname(ch_t
*ch
, char *buf
, uint bufsize
);
99 static void chipduplexupd(ch_t
*ch
);
100 static void chipwrcam(struct bcm4xxx
*ch
, struct ether_addr
*ea
, uint camindex
);
101 static void chipphywr(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
);
102 static void chipphyor(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
);
103 static void chipphyand(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
);
104 static void chipphyforce(struct bcm4xxx
*ch
, uint phyaddr
);
105 static void chipphyadvertise(struct bcm4xxx
*ch
, uint phyaddr
);
107 static void chipdumpregs(struct bcm4xxx
*ch
, bcmenetregs_t
*regs
, struct bcmstrbuf
*b
);
110 /* chip interrupt bit error summary */
111 #define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
112 #define DEF_INTMASK (I_XI | I_RI | I_ERRORS)
114 struct chops bcm47xx_et_chops
= {
141 static uint devices
[] = {
146 chipid(uint vendor
, uint device
)
150 if (vendor
!= VENDOR_BROADCOM
)
153 for (i
= 0; devices
[i
]; i
++) {
154 if (device
== devices
[i
])
161 chipattach(etc_info_t
*etc
, void *osh
, void *regsva
)
167 uint boardflags
, boardtype
;
169 ET_TRACE(("et%d: chipattach: regsva 0x%lx\n", etc
->unit
, (ulong
)regsva
));
171 if ((ch
= (struct bcm4xxx
*)MALLOC(osh
, sizeof(struct bcm4xxx
))) == NULL
) {
172 ET_ERROR(("et%d: chipattach: out of memory, malloced %d bytes\n", etc
->unit
,
176 bzero((char *)ch
, sizeof(struct bcm4xxx
));
182 /* store the pointer to the sw mib */
183 etc
->mib
= (void *)&ch
->mib
;
186 if ((ch
->sih
= si_attach(etc
->deviceid
, ch
->osh
, regsva
, PCI_BUS
, NULL
, &ch
->vars
,
187 &ch
->vars_size
)) == NULL
) {
188 ET_ERROR(("et%d: chipattach: si_attach error\n", etc
->unit
));
192 /* We used to have an assert here like:
193 * si_coreid(ch->sih) == ENET_CORE_ID
194 * but srom-less systems and simulators don't have a way to
195 * provide a default bar0window so we were relying on nvram
196 * variables. At some point we decided that we could do away
197 * with that since the wireless driver was simply doing a
198 * setcore in attach. So we need to do the same here for
201 if ((regs
= (bcmenetregs_t
*)si_setcore(ch
->sih
, ENET_CORE_ID
, etc
->unit
)) == NULL
) {
202 ET_ERROR(("et%d: chipattach: Could not setcore to the ENET core\n", etc
->unit
));
207 etc
->chip
= ch
->sih
->chip
;
208 etc
->chiprev
= ch
->sih
->chiprev
;
209 etc
->coreid
= si_coreid(ch
->sih
);
210 etc
->corerev
= si_corerev(ch
->sih
);
211 etc
->nicmode
= !(ch
->sih
->bustype
== SI_BUS
);
212 etc
->coreunit
= si_coreunit(ch
->sih
);
213 etc
->boardflags
= getintvar(ch
->vars
, "boardflags");
215 boardflags
= etc
->boardflags
;
216 boardtype
= ch
->sih
->boardtype
;
218 /* get our local ether addr */
219 sprintf(name
, "et%dmacaddr", etc
->coreunit
);
220 var
= getvar(ch
->vars
, name
);
222 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc
->unit
, name
));
225 bcm_ether_atoe(var
, &etc
->perm_etheraddr
);
227 if (ETHER_ISNULLADDR(&etc
->perm_etheraddr
)) {
228 ET_ERROR(("et%d: chipattach: invalid format: %s=%s\n", etc
->unit
, name
, var
));
231 bcopy((char *)&etc
->perm_etheraddr
, (char *)&etc
->cur_etheraddr
, ETHER_ADDR_LEN
);
234 * Too much can go wrong in scanning MDC/MDIO playing "whos my phy?" .
235 * Instead, explicitly require the environment var "et<coreunit>phyaddr=<val>".
238 /* get our phyaddr value */
239 sprintf(name
, "et%dphyaddr", etc
->coreunit
);
240 var
= getvar(ch
->vars
, name
);
242 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc
->unit
, name
));
245 etc
->phyaddr
= bcm_atoi(var
) & EPHY_MASK
;
247 /* nvram says no phy is present */
248 if (etc
->phyaddr
== EPHY_NONE
) {
249 ET_ERROR(("et%d: chipattach: phy not present\n", etc
->unit
));
253 /* get our mdc/mdio port number */
254 sprintf(name
, "et%dmdcport", etc
->coreunit
);
255 var
= getvar(ch
->vars
, name
);
257 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc
->unit
, name
));
260 etc
->mdcport
= bcm_atoi(var
);
262 /* configure pci core */
263 si_pci_setup(ch
->sih
, (1 << si_coreidx(ch
->sih
)));
265 /* reset the enet core */
269 sprintf(name
, "et%d", etc
->coreunit
);
270 if ((ch
->di
= dma_attach(osh
, name
, ch
->sih
,
271 (void *)®s
->dmaregs
.xmt
, (void *)®s
->dmaregs
.rcv
,
272 NTXD
, NRXD
, RXBUFSZ
, -1, NRXBUFPOST
, HWRXOFF
,
273 &et_msg_level
)) == NULL
) {
274 ET_ERROR(("et%d: chipattach: dma_attach failed\n", etc
->unit
));
277 etc
->txavail
[TX_Q0
] = (uint
*)&ch
->di
->txavail
;
279 /* set default sofware intmask */
280 ch
->intmask
= DEF_INTMASK
;
283 * For the 5222 dual phy shared mdio contortion, our phy is
284 * on someone elses mdio pins. This other enet enet
285 * may not yet be attached so we must defer the et_phyfind().
287 /* if local phy: reset it once now */
288 if (etc
->mdcport
== etc
->coreunit
)
289 chipphyreset(ch
, etc
->phyaddr
);
293 * Broadcom Robo ethernet switch.
295 if ((boardflags
& BFL_ENETROBO
) &&
296 (etc
->phyaddr
== EPHY_NOREG
)) {
297 /* Attach to the switch */
298 if (!(etc
->robo
= bcm_robo_attach(ch
->sih
, ch
, ch
->vars
,
299 (miird_f
)bcm47xx_et_chops
.phyrd
,
300 (miiwr_f
)bcm47xx_et_chops
.phywr
))) {
301 ET_ERROR(("et%d: chipattach: robo_attach failed\n", etc
->unit
));
304 /* Enable the switch and set it to a known good state */
305 if (bcm_robo_enable_device(etc
->robo
)) {
306 ET_ERROR(("et%d: chipattach: robo_enable_device failed\n", etc
->unit
));
309 /* Configure the switch to do VLAN */
310 if ((boardflags
& BFL_ENETVLAN
) &&
311 bcm_robo_config_vlan(etc
->robo
, etc
->perm_etheraddr
.octet
)) {
312 ET_ERROR(("et%d: chipattach: robo_config_vlan failed\n", etc
->unit
));
315 /* Enable switching/forwarding */
316 if (bcm_robo_enable_switch(etc
->robo
)) {
317 ET_ERROR(("et%d: chipattach: robo_enable_switch failed\n", etc
->unit
));
325 * ADMtek ethernet switch.
327 if (boardflags
& BFL_ENETADM
) {
328 /* Attach to the device */
329 if (!(ch
->adm
= adm_attach(ch
->sih
, ch
->vars
))) {
330 ET_ERROR(("et%d: chipattach: adm_attach failed\n", etc
->unit
));
333 /* Enable the external switch and set it to a known good state */
334 if (adm_enable_device(ch
->adm
)) {
335 ET_ERROR(("et%d: chipattach: adm_enable_device failed\n", etc
->unit
));
338 /* Configure the switch */
339 if ((boardflags
& BFL_ENETVLAN
) && adm_config_vlan(ch
->adm
)) {
340 ET_ERROR(("et%d: chipattach: adm_config_vlan failed\n", etc
->unit
));
354 chipdetach(struct bcm4xxx
*ch
)
356 ET_TRACE(("et%d: chipdetach\n", ch
->etc
->unit
));
362 /* free robo state */
364 bcm_robo_detach(ch
->etc
->robo
);
368 /* free ADMtek state */
378 /* put the core back into reset */
380 si_core_disable(ch
->sih
, 0);
388 MFREE(ch
->osh
, ch
->vars
, ch
->vars_size
);
390 /* free chip private state */
391 MFREE(ch
->osh
, ch
, sizeof(struct bcm4xxx
));
395 chiplongname(struct bcm4xxx
*ch
, char *buf
, uint bufsize
)
399 switch (ch
->etc
->deviceid
) {
400 case BCM47XX_ENET_ID
:
402 s
= "Broadcom BCM47xx 10/100 Mbps Ethernet Controller";
406 strncpy(buf
, s
, bufsize
);
407 buf
[bufsize
- 1] = '\0';
411 chipdump(struct bcm4xxx
*ch
, struct bcmstrbuf
*b
)
414 bcm_bprintf(b
, "regs 0x%x etphy 0x%x ch->intstatus 0x%x intmask 0x%x\n",
415 (ulong
)ch
->regs
, (ulong
)ch
->etphy
, ch
->intstatus
, ch
->intmask
);
416 bcm_bprintf(b
, "\n");
418 /* dma engine state */
419 dma_dump(ch
->di
, b
, FALSE
);
420 bcm_bprintf(b
, "\n");
423 chipdumpregs(ch
, ch
->regs
, b
);
424 bcm_bprintf(b
, "\n");
426 /* switch registers */
429 robo_dump_regs(ch
->etc
->robo
, b
);
433 adm_dump_regs(ch
->adm
, b
->buf
);
440 #define PRREG(name) bcm_bprintf(b, #name " 0x%x ", R_REG(ch->osh, ®s->name))
441 #define PRMIBREG(name) bcm_bprintf(b, #name " 0x%x ", R_REG(ch->osh, ®s->mib.name))
444 chipdumpregs(struct bcm4xxx
*ch
, bcmenetregs_t
*regs
, struct bcmstrbuf
*b
)
448 phyaddr
= ch
->etc
->phyaddr
;
450 PRREG(devcontrol
); PRREG(biststatus
); PRREG(wakeuplength
);
451 bcm_bprintf(b
, "\n");
452 PRREG(intstatus
); PRREG(intmask
); PRREG(gptimer
);
453 bcm_bprintf(b
, "\n");
454 PRREG(emactxmaxburstlen
); PRREG(emacrxmaxburstlen
);
455 PRREG(emaccontrol
); PRREG(emacflowcontrol
);
456 bcm_bprintf(b
, "\n");
458 bcm_bprintf(b
, "\n");
461 PRREG(rxconfig
); PRREG(rxmaxlength
); PRREG(txmaxlength
);
462 bcm_bprintf(b
, "\n");
463 PRREG(mdiocontrol
); PRREG(camcontrol
); PRREG(enetcontrol
);
464 bcm_bprintf(b
, "\n");
465 PRREG(txcontrol
); PRREG(txwatermark
); PRREG(mibcontrol
);
466 bcm_bprintf(b
, "\n");
469 PRMIBREG(tx_good_octets
); PRMIBREG(tx_good_pkts
); PRMIBREG(tx_octets
); PRMIBREG(tx_pkts
);
470 bcm_bprintf(b
, "\n");
471 PRMIBREG(tx_broadcast_pkts
); PRMIBREG(tx_multicast_pkts
);
472 bcm_bprintf(b
, "\n");
473 PRMIBREG(tx_jabber_pkts
); PRMIBREG(tx_oversize_pkts
); PRMIBREG(tx_fragment_pkts
);
474 bcm_bprintf(b
, "\n");
475 PRMIBREG(tx_underruns
); PRMIBREG(tx_total_cols
); PRMIBREG(tx_single_cols
);
476 bcm_bprintf(b
, "\n");
477 PRMIBREG(tx_multiple_cols
); PRMIBREG(tx_excessive_cols
); PRMIBREG(tx_late_cols
);
478 bcm_bprintf(b
, "\n");
479 PRMIBREG(tx_defered
); PRMIBREG(tx_carrier_lost
); PRMIBREG(tx_pause_pkts
);
480 bcm_bprintf(b
, "\n");
482 PRMIBREG(rx_good_octets
); PRMIBREG(rx_good_pkts
); PRMIBREG(rx_octets
); PRMIBREG(rx_pkts
);
483 bcm_bprintf(b
, "\n");
484 PRMIBREG(rx_broadcast_pkts
); PRMIBREG(rx_multicast_pkts
);
485 bcm_bprintf(b
, "\n");
486 PRMIBREG(rx_jabber_pkts
); PRMIBREG(rx_oversize_pkts
); PRMIBREG(rx_fragment_pkts
);
487 bcm_bprintf(b
, "\n");
488 PRMIBREG(rx_missed_pkts
); PRMIBREG(rx_crc_align_errs
); PRMIBREG(rx_undersize
);
489 bcm_bprintf(b
, "\n");
490 PRMIBREG(rx_crc_errs
); PRMIBREG(rx_align_errs
); PRMIBREG(rx_symbol_errs
);
491 bcm_bprintf(b
, "\n");
492 PRMIBREG(rx_pause_pkts
); PRMIBREG(rx_nonpause_pkts
);
493 bcm_bprintf(b
, "\n");
495 if (phyaddr
!= EPHY_NOREG
) {
496 /* print a few interesting phy registers */
497 bcm_bprintf(b
, "phy0 0x%x phy1 0x%x phy2 0x%x phy3 0x%x\n",
498 chipphyrd(ch
, phyaddr
, 0),
499 chipphyrd(ch
, phyaddr
, 1),
500 chipphyrd(ch
, phyaddr
, 2),
501 chipphyrd(ch
, phyaddr
, 3));
502 bcm_bprintf(b
, "phy4 0x%x phy5 0x%x phy24 0x%x phy25 0x%x\n",
503 chipphyrd(ch
, phyaddr
, 4),
504 chipphyrd(ch
, phyaddr
, 5),
505 chipphyrd(ch
, phyaddr
, 24),
506 chipphyrd(ch
, phyaddr
, 25));
512 #define MDC_RATIO 5000000
515 chipreset(struct bcm4xxx
*ch
)
520 ET_TRACE(("et%d: chipreset\n", ch
->etc
->unit
));
524 if (!si_iscoreup(ch
->sih
)) {
525 if (!ch
->etc
->nicmode
)
526 si_pci_setup(ch
->sih
, (1 << si_coreidx(ch
->sih
)));
527 /* power on reset: reset the enet core */
528 si_core_reset(ch
->sih
, 0, 0);
532 /* read counters before resetting the chip */
536 /* reset the tx dma engine */
540 /* set emac into loopback mode to ensure no rx traffic */
541 W_REG(ch
->osh
, ®s
->rxconfig
, ERC_LE
);
544 /* reset the rx dma engine */
549 si_core_reset(ch
->sih
, 0, 0);
553 /* must clear mib registers by hand */
554 W_REG(ch
->osh
, ®s
->mibcontrol
, EMC_RZ
);
555 (void) R_REG(ch
->osh
, ®s
->mib
.tx_broadcast_pkts
);
556 (void) R_REG(ch
->osh
, ®s
->mib
.tx_multicast_pkts
);
557 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_64
);
558 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_65_to_127
);
559 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_128_to_255
);
560 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_256_to_511
);
561 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_512_to_1023
);
562 (void) R_REG(ch
->osh
, ®s
->mib
.tx_len_1024_to_max
);
563 (void) R_REG(ch
->osh
, ®s
->mib
.tx_jabber_pkts
);
564 (void) R_REG(ch
->osh
, ®s
->mib
.tx_oversize_pkts
);
565 (void) R_REG(ch
->osh
, ®s
->mib
.tx_fragment_pkts
);
566 (void) R_REG(ch
->osh
, ®s
->mib
.tx_underruns
);
567 (void) R_REG(ch
->osh
, ®s
->mib
.tx_total_cols
);
568 (void) R_REG(ch
->osh
, ®s
->mib
.tx_single_cols
);
569 (void) R_REG(ch
->osh
, ®s
->mib
.tx_multiple_cols
);
570 (void) R_REG(ch
->osh
, ®s
->mib
.tx_excessive_cols
);
571 (void) R_REG(ch
->osh
, ®s
->mib
.tx_late_cols
);
572 (void) R_REG(ch
->osh
, ®s
->mib
.tx_defered
);
573 (void) R_REG(ch
->osh
, ®s
->mib
.tx_carrier_lost
);
574 (void) R_REG(ch
->osh
, ®s
->mib
.tx_pause_pkts
);
575 (void) R_REG(ch
->osh
, ®s
->mib
.rx_broadcast_pkts
);
576 (void) R_REG(ch
->osh
, ®s
->mib
.rx_multicast_pkts
);
577 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_64
);
578 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_65_to_127
);
579 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_128_to_255
);
580 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_256_to_511
);
581 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_512_to_1023
);
582 (void) R_REG(ch
->osh
, ®s
->mib
.rx_len_1024_to_max
);
583 (void) R_REG(ch
->osh
, ®s
->mib
.rx_jabber_pkts
);
584 (void) R_REG(ch
->osh
, ®s
->mib
.rx_oversize_pkts
);
585 (void) R_REG(ch
->osh
, ®s
->mib
.rx_fragment_pkts
);
586 (void) R_REG(ch
->osh
, ®s
->mib
.rx_missed_pkts
);
587 (void) R_REG(ch
->osh
, ®s
->mib
.rx_crc_align_errs
);
588 (void) R_REG(ch
->osh
, ®s
->mib
.rx_undersize
);
589 (void) R_REG(ch
->osh
, ®s
->mib
.rx_crc_errs
);
590 (void) R_REG(ch
->osh
, ®s
->mib
.rx_align_errs
);
591 (void) R_REG(ch
->osh
, ®s
->mib
.rx_symbol_errs
);
592 (void) R_REG(ch
->osh
, ®s
->mib
.rx_pause_pkts
);
593 (void) R_REG(ch
->osh
, ®s
->mib
.rx_nonpause_pkts
);
597 * We want the phy registers to be accessible even when
598 * the driver is "downed" so initialize MDC preamble, frequency,
599 * and whether internal or external phy here.
601 /* default: 100Mhz SI clock and external phy */
602 W_REG(ch
->osh
, ®s
->mdiocontrol
, 0x94);
603 if (ch
->etc
->deviceid
== BCM47XX_ENET_ID
) {
604 /* 47xx chips: find out the clock */
605 if ((clk
= si_clock(ch
->sih
)) != 0) {
606 mdc
= 0x80 | ((clk
+ (MDC_RATIO
/ 2)) / MDC_RATIO
);
607 W_REG(ch
->osh
, ®s
->mdiocontrol
, mdc
);
609 ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, "
615 /* some chips have internal phy, some don't */
616 if (!(R_REG(ch
->osh
, ®s
->devcontrol
) & DC_IP
)) {
617 W_REG(ch
->osh
, ®s
->enetcontrol
, EC_EP
);
618 } else if (R_REG(ch
->osh
, ®s
->devcontrol
) & DC_ER
) {
619 AND_REG(ch
->osh
, ®s
->devcontrol
, ~DC_ER
);
621 chipphyinit(ch
, ch
->etc
->phyaddr
);
624 /* clear persistent sw intstatus */
629 * Initialize all the chip registers. If dma mode, init tx and rx dma engines
630 * but leave the devcontrol tx and rx (fifos) disabled.
633 chipinit(struct bcm4xxx
*ch
, uint options
)
644 ET_TRACE(("et%d: chipinit\n", etc
->unit
));
646 /* enable crc32 generation */
647 OR_REG(ch
->osh
, ®s
->emaccontrol
, EMC_CG
);
649 /* enable one rx interrupt per received frame */
650 W_REG(ch
->osh
, ®s
->intrecvlazy
, (1 << IRL_FC_SHIFT
));
652 /* enable 802.3x tx flow control (honor received PAUSE frames) */
653 W_REG(ch
->osh
, ®s
->rxconfig
, ERC_FE
| ERC_UF
);
656 if (etc
->promisc
|| (R_REG(ch
->osh
, ®s
->rxconfig
) & ERC_CA
))
657 OR_REG(ch
->osh
, ®s
->rxconfig
, ERC_PE
);
659 /* our local address */
660 chipwrcam(ch
, &etc
->cur_etheraddr
, idx
++);
662 /* allmulti or a list of discrete multicast addresses */
664 OR_REG(ch
->osh
, ®s
->rxconfig
, ERC_AM
);
665 else if (etc
->nmulticast
) {
666 for (i
= 0; i
< etc
->nmulticast
; i
++)
667 chipwrcam(ch
, &etc
->multicast
[i
], idx
++);
671 OR_REG(ch
->osh
, ®s
->camcontrol
, CC_CE
);
674 /* optionally enable mac-level loopback */
676 OR_REG(ch
->osh
, ®s
->rxconfig
, ERC_LE
);
678 /* set max frame lengths - account for possible vlan tag */
679 W_REG(ch
->osh
, ®s
->rxmaxlength
, ETHER_MAX_LEN
+ 32);
680 W_REG(ch
->osh
, ®s
->txmaxlength
, ETHER_MAX_LEN
+ 32);
682 /* set tx watermark */
683 W_REG(ch
->osh
, ®s
->txwatermark
, 56);
686 * Optionally, disable phy autonegotiation and force our speed/duplex
687 * or constrain our advertised capabilities.
689 if (etc
->forcespeed
!= ET_AUTO
)
690 chipphyforce(ch
, etc
->phyaddr
);
691 else if (etc
->advertise
&& etc
->needautoneg
)
692 chipphyadvertise(ch
, etc
->phyaddr
);
694 if (options
& ET_INIT_FULL
) {
695 /* initialize the tx and rx dma channels */
699 /* post dma receive buffers */
702 /* lastly, enable interrupts */
703 if (options
& ET_INIT_INTRON
)
707 dma_rxenable(ch
->di
);
709 /* turn on the emac */
710 OR_REG(ch
->osh
, ®s
->enetcontrol
, EC_EE
);
714 static bool BCMFASTPATH
715 chiptx(struct bcm4xxx
*ch
, void *p0
)
719 ET_TRACE(("et%d: chiptx\n", ch
->etc
->unit
));
720 ET_LOG("et%d: chiptx", ch
->etc
->unit
, 0);
722 error
= dma_txfast(ch
->di
, p0
, TRUE
);
725 ET_ERROR(("et%d: chiptx: out of txds\n", ch
->etc
->unit
));
732 /* reclaim completed transmit descriptors and packets */
733 static void BCMFASTPATH
734 chiptxreclaim(struct bcm4xxx
*ch
, bool forceall
)
736 ET_TRACE(("et%d: chiptxreclaim\n", ch
->etc
->unit
));
737 dma_txreclaim(ch
->di
, forceall
? HNDDMA_RANGE_ALL
: HNDDMA_RANGE_TRANSMITTED
);
738 ch
->intstatus
&= ~I_XI
;
741 /* dma receive: returns a pointer to the next frame received, or NULL if there are no more */
742 static void * BCMFASTPATH
743 chiprx(struct bcm4xxx
*ch
)
747 ET_TRACE(("et%d: chiprx\n", ch
->etc
->unit
));
748 ET_LOG("et%d: chiprx", ch
->etc
->unit
, 0);
750 if ((p
= dma_rx(ch
->di
)) == NULL
)
751 ch
->intstatus
&= ~I_RI
;
756 /* reclaim completed dma receive descriptors and packets */
758 chiprxreclaim(struct bcm4xxx
*ch
)
760 ET_TRACE(("et%d: chiprxreclaim\n", ch
->etc
->unit
));
761 dma_rxreclaim(ch
->di
);
762 ch
->intstatus
&= ~I_RI
;
765 /* allocate and post dma receive buffers */
766 static void BCMFASTPATH
767 chiprxfill(struct bcm4xxx
*ch
)
769 ET_TRACE(("et%d: chiprxfill\n", ch
->etc
->unit
));
770 ET_LOG("et%d: chiprx", ch
->etc
->unit
, 0);
774 /* get current and pending interrupt events */
775 static int BCMFASTPATH
776 chipgetintrevents(struct bcm4xxx
*ch
, bool in_isr
)
785 /* read the interrupt status register */
786 intstatus
= R_REG(ch
->osh
, ®s
->intstatus
);
788 /* defer unsolicited interrupts */
789 intstatus
&= (in_isr
? ch
->intmask
: DEF_INTMASK
);
791 /* clear non-error interrupt conditions */
792 if (intstatus
!= 0) {
793 W_REG(ch
->osh
, ®s
->intstatus
, intstatus
);
797 /* or new bits into persistent intstatus */
798 intstatus
= (ch
->intstatus
|= intstatus
);
800 /* return if no events */
804 /* convert chip-specific intstatus bits into generic intr event bits */
805 if (intstatus
& I_RI
)
807 if (intstatus
& I_XI
)
809 if (intstatus
& I_ERRORS
)
810 events
|= INTR_ERROR
;
811 if (intstatus
& I_TO
)
817 /* enable chip interrupts */
818 static void BCMFASTPATH
819 chipintrson(struct bcm4xxx
*ch
)
821 ch
->intmask
= DEF_INTMASK
;
822 W_REG(ch
->osh
, &ch
->regs
->intmask
, ch
->intmask
);
825 /* disable chip interrupts */
826 static void BCMFASTPATH
827 chipintrsoff(struct bcm4xxx
*ch
)
829 W_REG(ch
->osh
, &ch
->regs
->intmask
, 0);
830 (void) R_REG(ch
->osh
, &ch
->regs
->intmask
); /* sync readback */
834 /* return true of caller should re-initialize, otherwise false */
835 static bool BCMFASTPATH
836 chiperrors(struct bcm4xxx
*ch
)
843 intstatus
= ch
->intstatus
;
844 ch
->intstatus
&= ~(I_ERRORS
);
846 ET_TRACE(("et%d: chiperrors: intstatus 0x%x\n", etc
->unit
, intstatus
));
848 if (intstatus
& I_PC
) {
849 ET_ERROR(("et%d: descriptor error\n", etc
->unit
));
853 if (intstatus
& I_PD
) {
854 ET_ERROR(("et%d: data error\n", etc
->unit
));
858 if (intstatus
& I_DE
) {
859 ET_ERROR(("et%d: descriptor protocol error\n", etc
->unit
));
862 /* NOTE : this ie NOT an error. It becomes an error only
863 * when the rx fifo overflows
865 if (intstatus
& I_RU
) {
866 ET_ERROR(("et%d: receive descriptor underflow\n", etc
->unit
));
870 if (intstatus
& I_RO
) {
871 ET_ERROR(("et%d: receive fifo overflow\n", etc
->unit
));
875 if (intstatus
& I_XU
) {
876 ET_ERROR(("et%d: transmit fifo underflow\n", etc
->unit
));
879 /* if overflows or decriptors underflow, don't report it
880 * as an error and provoque a reset
882 if (intstatus
& ~(I_RU
) & I_ERRORS
)
888 chipwrcam(struct bcm4xxx
*ch
, struct ether_addr
*ea
, uint camindex
)
892 ASSERT((R_REG(ch
->osh
, &ch
->regs
->camcontrol
) & (CC_CB
| CC_CE
)) == 0);
894 w
= (ea
->octet
[2] << 24) | (ea
->octet
[3] << 16) | (ea
->octet
[4] << 8)
896 W_REG(ch
->osh
, &ch
->regs
->camdatalo
, w
);
897 w
= CD_V
| (ea
->octet
[0] << 8) | ea
->octet
[1];
898 W_REG(ch
->osh
, &ch
->regs
->camdatahi
, w
);
899 W_REG(ch
->osh
, &ch
->regs
->camcontrol
, ((camindex
<< CC_INDEX_SHIFT
) | CC_WR
));
901 /* spin until done */
902 SPINWAIT((R_REG(ch
->osh
, &ch
->regs
->camcontrol
) & CC_CB
), 1000);
905 * This assertion is usually caused by the phy not providing a clock
906 * to the bottom portion of the mac..
908 ASSERT((R_REG(ch
->osh
, &ch
->regs
->camcontrol
) & CC_CB
) == 0);
912 chipstatsupd(struct bcm4xxx
*ch
)
923 * mib counters are clear-on-read.
924 * Don't bother using the pkt and octet counters since they are only
925 * 16bits and wrap too quickly to be useful.
927 m
->tx_broadcast_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_broadcast_pkts
);
928 m
->tx_multicast_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_multicast_pkts
);
929 m
->tx_len_64
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_64
);
930 m
->tx_len_65_to_127
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_65_to_127
);
931 m
->tx_len_128_to_255
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_128_to_255
);
932 m
->tx_len_256_to_511
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_256_to_511
);
933 m
->tx_len_512_to_1023
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_512_to_1023
);
934 m
->tx_len_1024_to_max
+= R_REG(ch
->osh
, ®s
->mib
.tx_len_1024_to_max
);
935 m
->tx_jabber_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_jabber_pkts
);
936 m
->tx_oversize_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_oversize_pkts
);
937 m
->tx_fragment_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_fragment_pkts
);
938 m
->tx_underruns
+= R_REG(ch
->osh
, ®s
->mib
.tx_underruns
);
939 m
->tx_total_cols
+= R_REG(ch
->osh
, ®s
->mib
.tx_total_cols
);
940 m
->tx_single_cols
+= R_REG(ch
->osh
, ®s
->mib
.tx_single_cols
);
941 m
->tx_multiple_cols
+= R_REG(ch
->osh
, ®s
->mib
.tx_multiple_cols
);
942 m
->tx_excessive_cols
+= R_REG(ch
->osh
, ®s
->mib
.tx_excessive_cols
);
943 m
->tx_late_cols
+= R_REG(ch
->osh
, ®s
->mib
.tx_late_cols
);
944 m
->tx_defered
+= R_REG(ch
->osh
, ®s
->mib
.tx_defered
);
945 m
->tx_carrier_lost
+= R_REG(ch
->osh
, ®s
->mib
.tx_carrier_lost
);
946 m
->tx_pause_pkts
+= R_REG(ch
->osh
, ®s
->mib
.tx_pause_pkts
);
947 m
->rx_broadcast_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_broadcast_pkts
);
948 m
->rx_multicast_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_multicast_pkts
);
949 m
->rx_len_64
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_64
);
950 m
->rx_len_65_to_127
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_65_to_127
);
951 m
->rx_len_128_to_255
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_128_to_255
);
952 m
->rx_len_256_to_511
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_256_to_511
);
953 m
->rx_len_512_to_1023
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_512_to_1023
);
954 m
->rx_len_1024_to_max
+= R_REG(ch
->osh
, ®s
->mib
.rx_len_1024_to_max
);
955 m
->rx_jabber_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_jabber_pkts
);
956 m
->rx_oversize_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_oversize_pkts
);
957 m
->rx_fragment_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_fragment_pkts
);
958 m
->rx_missed_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_missed_pkts
);
959 m
->rx_crc_align_errs
+= R_REG(ch
->osh
, ®s
->mib
.rx_crc_align_errs
);
960 m
->rx_undersize
+= R_REG(ch
->osh
, ®s
->mib
.rx_undersize
);
961 m
->rx_crc_errs
+= R_REG(ch
->osh
, ®s
->mib
.rx_crc_errs
);
962 m
->rx_align_errs
+= R_REG(ch
->osh
, ®s
->mib
.rx_align_errs
);
963 m
->rx_symbol_errs
+= R_REG(ch
->osh
, ®s
->mib
.rx_symbol_errs
);
964 m
->rx_pause_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_pause_pkts
);
965 m
->rx_nonpause_pkts
+= R_REG(ch
->osh
, ®s
->mib
.rx_nonpause_pkts
);
968 * Aggregate transmit and receive errors that probably resulted
969 * in the loss of a frame are computed on the fly.
971 * We seem to get lots of tx_carrier_lost errors when flipping
972 * speed modes so don't count these as tx errors.
974 * Arbitrarily lump the non-specific dma errors as tx errors.
976 etc
->txerror
= m
->tx_jabber_pkts
+ m
->tx_oversize_pkts
977 + m
->tx_underruns
+ m
->tx_excessive_cols
978 + m
->tx_late_cols
+ etc
->txnobuf
+ etc
->dmade
979 + etc
->dmada
+ etc
->dmape
+ etc
->txuflo
;
980 etc
->rxerror
= m
->rx_jabber_pkts
+ m
->rx_oversize_pkts
981 + m
->rx_missed_pkts
+ m
->rx_crc_align_errs
982 + m
->rx_undersize
+ m
->rx_crc_errs
983 + m
->rx_align_errs
+ m
->rx_symbol_errs
984 + etc
->rxnobuf
+ etc
->rxdmauflo
+ etc
->rxoflo
+ etc
->rxbadlen
;
988 chipdumpmib(ch_t
*ch
, struct bcmstrbuf
*b
, bool clear
)
995 bzero((char *)m
, sizeof(bcmenetmib_t
));
999 bcm_bprintf(b
, "tx_broadcast_pkts %d tx_multicast_pkts %d tx_jabber_pkts %d "
1000 "tx_oversize_pkts %d\n",
1001 m
->tx_broadcast_pkts
, m
->tx_multicast_pkts
,
1003 m
->tx_oversize_pkts
);
1004 bcm_bprintf(b
, "tx_fragment_pkts %d tx_underruns %d\n",
1005 m
->tx_fragment_pkts
, m
->tx_underruns
);
1006 bcm_bprintf(b
, "tx_total_cols %d tx_single_cols %d tx_multiple_cols %d "
1007 "tx_excessive_cols %d\n",
1008 m
->tx_total_cols
, m
->tx_single_cols
, m
->tx_multiple_cols
,
1009 m
->tx_excessive_cols
);
1010 bcm_bprintf(b
, "tx_late_cols %d tx_defered %d tx_carrier_lost %d tx_pause_pkts %d\n",
1011 m
->tx_late_cols
, m
->tx_defered
, m
->tx_carrier_lost
,
1014 /* receive stat counters */
1015 /* hardware mib pkt and octet counters wrap too quickly to be useful */
1016 bcm_bprintf(b
, "rx_broadcast_pkts %d rx_multicast_pkts %d rx_jabber_pkts %d "
1017 "rx_oversize_pkts %d\n",
1018 m
->rx_broadcast_pkts
, m
->rx_multicast_pkts
,
1019 m
->rx_jabber_pkts
, m
->rx_oversize_pkts
);
1020 bcm_bprintf(b
, "rx_fragment_pkts %d rx_missed_pkts %d rx_crc_align_errs %d "
1021 "rx_undersize %d\n",
1022 m
->rx_fragment_pkts
, m
->rx_missed_pkts
,
1023 m
->rx_crc_align_errs
, m
->rx_undersize
);
1024 bcm_bprintf(b
, "rx_crc_errs %d rx_align_errs %d rx_symbol_errs %d\n",
1025 m
->rx_crc_errs
, m
->rx_align_errs
, m
->rx_symbol_errs
);
1026 bcm_bprintf(b
, "rx_pause_pkts %d rx_nonpause_pkts %d\n",
1027 m
->rx_pause_pkts
, m
->rx_nonpause_pkts
);
1031 chipenablepme(struct bcm4xxx
*ch
)
1033 bcmenetregs_t
*regs
;
1037 /* enable chip wakeup pattern matching */
1038 OR_REG(ch
->osh
, ®s
->devcontrol
, DC_PM
);
1040 /* enable sonics bus PME */
1041 si_core_cflags(ch
->sih
, SICF_PME_EN
, SICF_PME_EN
);
1045 chipdisablepme(struct bcm4xxx
*ch
)
1047 bcmenetregs_t
*regs
;
1051 AND_REG(ch
->osh
, ®s
->devcontrol
, ~DC_PM
);
1052 si_core_cflags(ch
->sih
, SICF_PME_EN
, 0);
1056 chipduplexupd(struct bcm4xxx
*ch
)
1060 txcontrol
= R_REG(ch
->osh
, &ch
->regs
->txcontrol
);
1061 if (ch
->etc
->duplex
&& !(txcontrol
& EXC_FD
))
1062 OR_REG(ch
->osh
, &ch
->regs
->txcontrol
, EXC_FD
);
1063 else if (!ch
->etc
->duplex
&& (txcontrol
& EXC_FD
))
1064 AND_REG(ch
->osh
, &ch
->regs
->txcontrol
, ~EXC_FD
);
1068 chipphyrd(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
)
1070 bcmenetregs_t
*regs
;
1072 ASSERT(phyaddr
< MAXEPHY
);
1075 * BCM5222 dualphy shared mdio contortion.
1076 * remote phy: another emac controls our phy.
1078 if (ch
->etc
->mdcport
!= ch
->etc
->coreunit
) {
1079 if (ch
->etphy
== NULL
) {
1080 ch
->etphy
= et_phyfind(ch
->et
, ch
->etc
->mdcport
);
1082 /* first time reset */
1084 chipphyreset(ch
, ch
->etc
->phyaddr
);
1087 return (et_phyrd(ch
->etphy
, phyaddr
, reg
));
1092 /* local phy: our emac controls our phy */
1097 W_REG(ch
->osh
, ®s
->emacintstatus
, EI_MII
);
1099 /* issue the read */
1100 W_REG(ch
->osh
, ®s
->mdiodata
, (MD_SB_START
| MD_OP_READ
| (phyaddr
<< MD_PMD_SHIFT
)
1101 | (reg
<< MD_RA_SHIFT
) | MD_TA_VALID
));
1103 /* wait for it to complete */
1104 SPINWAIT(((R_REG(ch
->osh
, ®s
->emacintstatus
) & EI_MII
) == 0), 100);
1105 if ((R_REG(ch
->osh
, ®s
->emacintstatus
) & EI_MII
) == 0) {
1106 ET_ERROR(("et%d: chipphyrd: did not complete\n", ch
->etc
->unit
));
1109 return (R_REG(ch
->osh
, ®s
->mdiodata
) & MD_DATA_MASK
);
1113 chipphywr(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
)
1115 bcmenetregs_t
*regs
;
1117 ASSERT(phyaddr
< MAXEPHY
);
1120 * BCM5222 dualphy shared mdio contortion.
1121 * remote phy: another emac controls our phy.
1123 if (ch
->etc
->mdcport
!= ch
->etc
->coreunit
) {
1124 if (ch
->etphy
== NULL
)
1125 ch
->etphy
= et_phyfind(ch
->et
, ch
->etc
->mdcport
);
1127 et_phywr(ch
->etphy
, phyaddr
, reg
, v
);
1131 /* local phy: our emac controls our phy */
1136 W_REG(ch
->osh
, ®s
->emacintstatus
, EI_MII
);
1137 ASSERT((R_REG(ch
->osh
, ®s
->emacintstatus
) & EI_MII
) == 0);
1139 /* issue the write */
1140 W_REG(ch
->osh
, ®s
->mdiodata
, (MD_SB_START
| MD_OP_WRITE
| (phyaddr
<< MD_PMD_SHIFT
)
1141 | (reg
<< MD_RA_SHIFT
) | MD_TA_VALID
| v
));
1143 /* wait for it to complete */
1144 SPINWAIT(((R_REG(ch
->osh
, ®s
->emacintstatus
) & EI_MII
) == 0), 100);
1145 if ((R_REG(ch
->osh
, ®s
->emacintstatus
) & EI_MII
) == 0) {
1146 ET_ERROR(("et%d: chipphywr: did not complete\n", ch
->etc
->unit
));
1151 chipphyor(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
)
1155 tmp
= chipphyrd(ch
, phyaddr
, reg
);
1157 chipphywr(ch
, phyaddr
, reg
, tmp
);
1161 chipphyand(struct bcm4xxx
*ch
, uint phyaddr
, uint reg
, uint16 v
)
1165 tmp
= chipphyrd(ch
, phyaddr
, reg
);
1167 chipphywr(ch
, phyaddr
, reg
, tmp
);
1171 chipphyreset(struct bcm4xxx
*ch
, uint phyaddr
)
1173 ASSERT(phyaddr
< MAXEPHY
);
1175 if (phyaddr
== EPHY_NOREG
)
1178 chipphywr(ch
, phyaddr
, 0, CTL_RESET
);
1180 if (chipphyrd(ch
, phyaddr
, 0) & CTL_RESET
) {
1181 ET_ERROR(("et%d: chipphyreset: reset not complete\n", ch
->etc
->unit
));
1184 chipphyinit(ch
, phyaddr
);
1188 chipphyinit(struct bcm4xxx
*ch
, uint phyaddr
)
1192 /* enable activity led */
1193 chipphyand(ch
, phyaddr
, 26, 0x7fff);
1195 /* enable traffic meter led mode */
1196 chipphyor(ch
, phyaddr
, 27, (1 << 6));
1198 phyid
= chipphyrd(ch
, phyaddr
, 0x2);
1199 phyid
|= chipphyrd(ch
, phyaddr
, 0x3) << 16;
1200 if (phyid
== 0x55210022) {
1201 chipphywr(ch
, phyaddr
, 30, (uint16
) (chipphyrd(ch
, phyaddr
, 30) | 0x3000));
1202 chipphywr(ch
, phyaddr
, 22, (uint16
) (chipphyrd(ch
, phyaddr
, 22) & 0xffdf));
1207 chipphyforce(struct bcm4xxx
*ch
, uint phyaddr
)
1212 ASSERT(phyaddr
< MAXEPHY
);
1214 if (phyaddr
== EPHY_NOREG
)
1219 if (etc
->forcespeed
== ET_AUTO
)
1222 ctl
= chipphyrd(ch
, phyaddr
, 0);
1223 ctl
&= ~(CTL_SPEED
| CTL_ANENAB
| CTL_DUPLEX
);
1225 switch (etc
->forcespeed
) {
1238 ctl
|= (CTL_SPEED
| CTL_DUPLEX
);
1242 chipphywr(ch
, phyaddr
, 0, ctl
);
1245 /* set selected capability bits in autonegotiation advertisement */
1247 chipphyadvertise(struct bcm4xxx
*ch
, uint phyaddr
)
1252 ASSERT(phyaddr
< MAXEPHY
);
1254 if (phyaddr
== EPHY_NOREG
)
1259 if ((etc
->forcespeed
!= ET_AUTO
) || !etc
->needautoneg
)
1262 ASSERT(etc
->advertise
);
1264 /* reset our advertised capabilitity bits */
1265 adv
= chipphyrd(ch
, phyaddr
, 4);
1266 adv
&= ~(ADV_100FULL
| ADV_100HALF
| ADV_10FULL
| ADV_10HALF
);
1267 adv
|= etc
->advertise
;
1268 chipphywr(ch
, phyaddr
, 4, adv
);
1270 /* restart autonegotiation */
1271 chipphyor(ch
, phyaddr
, 0, CTL_RESTART
);
1273 etc
->needautoneg
= FALSE
;