K2.6 patches and update.
[tomato.git] / release / src-rt / et / sys / etc47xx.c
blob61b0ffd77be13076581cf364042379cfe992683b
1 /*
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) 2010, Broadcom Corporation
8 * All Rights Reserved.
9 *
10 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
11 * the contents of this file may not be disclosed to third parties, copied
12 * or duplicated in any form, in whole or in part, without the prior
13 * written permission of Broadcom Corporation.
14 * $Id: etc47xx.c,v 1.172.58.1 2010-07-01 23:25:46 Exp $
17 #include <typedefs.h>
18 #include <osl.h>
19 #include <bcmdefs.h>
20 #include <bcmendian.h>
21 #include <bcmutils.h>
22 #include <bcmdevs.h>
23 #include <proto/ethernet.h>
24 #include <siutils.h>
25 #include <sbhnddma.h>
26 #include <hnddma.h>
27 #include <et_dbg.h>
28 #include <hndsoc.h>
29 #include <bcmenet47xx.h>
30 #include <et_export.h> /* for et_phyxx() routines */
32 #ifdef ETROBO
33 #include <bcmrobo.h>
34 #endif /* ETROBO */
35 #ifdef ETADM
36 #include <etc_adm.h>
37 #endif /* ETADM */
39 struct bcm4xxx; /* forward declaration */
40 #define ch_t struct bcm4xxx
41 #include <etc.h>
43 /* private chip state */
44 struct bcm4xxx {
45 void *et; /* pointer to et private state */
46 etc_info_t *etc; /* pointer to etc public state */
48 bcmenetregs_t *regs; /* pointer to chip registers */
49 osl_t *osh; /* os handle */
51 void *etphy; /* pointer to et for shared mdc/mdio contortion */
53 uint32 intstatus; /* saved interrupt condition bits */
54 uint32 intmask; /* current software interrupt mask */
56 hnddma_t *di; /* dma engine software state */
58 bool mibgood; /* true once mib registers have been cleared */
59 bcmenetmib_t mib; /* mib counters */
60 si_t *sih; /* si utils handle */
62 char *vars; /* sprom name=value */
63 uint vars_size;
65 void *adm; /* optional admtek private data */
68 /* local prototypes */
69 static bool chipid(uint vendor, uint device);
70 static void *chipattach(etc_info_t *etc, void *osh, void *regsva);
71 static void chipdetach(ch_t *ch);
72 static void chipreset(ch_t *ch);
73 static void chipinit(ch_t *ch, uint options);
74 static bool chiptx(ch_t *ch, void *p);
75 static void *chiprx(ch_t *ch);
76 static void chiprxfill(ch_t *ch);
77 static int chipgetintrevents(ch_t *ch, bool in_isr);
78 static bool chiperrors(ch_t *ch);
79 static void chipintrson(ch_t *ch);
80 static void chipintrsoff(ch_t *ch);
81 static void chiptxreclaim(ch_t *ch, bool all);
82 static void chiprxreclaim(ch_t *ch);
83 static void chipstatsupd(ch_t *ch);
84 static void chipdumpmib(ch_t *ch, struct bcmstrbuf *b, bool clear);
85 static void chipenablepme(ch_t *ch);
86 static void chipdisablepme(ch_t *ch);
87 static void chipphyreset(ch_t *ch, uint phyaddr);
88 static void chipphyinit(ch_t *ch, uint phyaddr);
89 static uint16 chipphyrd(ch_t *ch, uint phyaddr, uint reg);
90 static void chipdump(ch_t *ch, struct bcmstrbuf *b);
91 static void chiplongname(ch_t *ch, char *buf, uint bufsize);
92 static void chipduplexupd(ch_t *ch);
93 static void chipwrcam(struct bcm4xxx *ch, struct ether_addr *ea, uint camindex);
94 static void chipphywr(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v);
95 static void chipphyor(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v);
96 static void chipphyand(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v);
97 static void chipphyforce(struct bcm4xxx *ch, uint phyaddr);
98 static void chipphyadvertise(struct bcm4xxx *ch, uint phyaddr);
99 #ifdef BCMDBG
100 static void chipdumpregs(struct bcm4xxx *ch, bcmenetregs_t *regs, struct bcmstrbuf *b);
101 #endif /* BCMDBG */
103 /* chip interrupt bit error summary */
104 #define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
105 #define DEF_INTMASK (I_XI | I_RI | I_ERRORS)
107 struct chops bcm47xx_et_chops = {
108 chipid,
109 chipattach,
110 chipdetach,
111 chipreset,
112 chipinit,
113 chiptx,
114 chiprx,
115 chiprxfill,
116 chipgetintrevents,
117 chiperrors,
118 chipintrson,
119 chipintrsoff,
120 chiptxreclaim,
121 chiprxreclaim,
122 chipstatsupd,
123 chipdumpmib,
124 chipenablepme,
125 chipdisablepme,
126 chipphyreset,
127 chipphyrd,
128 chipphywr,
129 chipdump,
130 chiplongname,
131 chipduplexupd
134 static uint devices[] = {
135 BCM47XX_ENET_ID,
136 0x0000 };
138 static bool
139 chipid(uint vendor, uint device)
141 int i;
143 if (vendor != VENDOR_BROADCOM)
144 return (FALSE);
146 for (i = 0; devices[i]; i++) {
147 if (device == devices[i])
148 return (TRUE);
150 return (FALSE);
153 static void *
154 chipattach(etc_info_t *etc, void *osh, void *regsva)
156 struct bcm4xxx *ch;
157 bcmenetregs_t *regs;
158 char name[16];
159 char *var;
160 uint boardflags, boardtype;
162 ET_TRACE(("et%d: chipattach: regsva 0x%lx\n", etc->unit, (ulong)regsva));
164 if ((ch = (struct bcm4xxx *)MALLOC(osh, sizeof(struct bcm4xxx))) == NULL) {
165 ET_ERROR(("et%d: chipattach: out of memory, malloced %d bytes\n", etc->unit,
166 MALLOCED(osh)));
167 return (NULL);
169 bzero((char *)ch, sizeof(struct bcm4xxx));
171 ch->etc = etc;
172 ch->et = etc->et;
173 ch->osh = osh;
175 /* store the pointer to the sw mib */
176 etc->mib = (void *)&ch->mib;
178 /* get si handle */
179 if ((ch->sih = si_attach(etc->deviceid, ch->osh, regsva, PCI_BUS, NULL, &ch->vars,
180 &ch->vars_size)) == NULL) {
181 ET_ERROR(("et%d: chipattach: si_attach error\n", etc->unit));
182 goto fail;
185 /* We used to have an assert here like:
186 * si_coreid(ch->sih) == ENET_CORE_ID
187 * but srom-less systems and simulators don't have a way to
188 * provide a default bar0window so we were relying on nvram
189 * variables. At some point we decided that we could do away
190 * with that since the wireless driver was simply doing a
191 * setcore in attach. So we need to do the same here for
192 * the ethernet.
194 if ((regs = (bcmenetregs_t *)si_setcore(ch->sih, ENET_CORE_ID, etc->unit)) == NULL) {
195 ET_ERROR(("et%d: chipattach: Could not setcore to the ENET core\n", etc->unit));
196 goto fail;
199 ch->regs = regs;
200 etc->chip = ch->sih->chip;
201 etc->chiprev = ch->sih->chiprev;
202 etc->coreid = si_coreid(ch->sih);
203 etc->corerev = si_corerev(ch->sih);
204 etc->nicmode = !(ch->sih->bustype == SI_BUS);
205 etc->coreunit = si_coreunit(ch->sih);
206 etc->boardflags = getintvar(ch->vars, "boardflags");
208 boardflags = etc->boardflags;
209 boardtype = ch->sih->boardtype;
211 /* get our local ether addr */
212 sprintf(name, "et%dmacaddr", etc->coreunit);
213 var = getvar(ch->vars, name);
214 if (var == NULL) {
215 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name));
216 goto fail;
218 bcm_ether_atoe(var, &etc->perm_etheraddr);
220 if (ETHER_ISNULLADDR(&etc->perm_etheraddr)) {
221 ET_ERROR(("et%d: chipattach: invalid format: %s=%s\n", etc->unit, name, var));
222 goto fail;
224 bcopy((char *)&etc->perm_etheraddr, (char *)&etc->cur_etheraddr, ETHER_ADDR_LEN);
227 * Too much can go wrong in scanning MDC/MDIO playing "whos my phy?" .
228 * Instead, explicitly require the environment var "et<coreunit>phyaddr=<val>".
231 /* get our phyaddr value */
232 sprintf(name, "et%dphyaddr", etc->coreunit);
233 var = getvar(ch->vars, name);
234 if (var == NULL) {
235 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name));
236 goto fail;
238 etc->phyaddr = bcm_atoi(var) & EPHY_MASK;
240 /* nvram says no phy is present */
241 if (etc->phyaddr == EPHY_NONE) {
242 ET_ERROR(("et%d: chipattach: phy not present\n", etc->unit));
243 goto fail;
246 /* get our mdc/mdio port number */
247 sprintf(name, "et%dmdcport", etc->coreunit);
248 var = getvar(ch->vars, name);
249 if (var == NULL) {
250 ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name));
251 goto fail;
253 etc->mdcport = bcm_atoi(var);
255 /* configure pci core */
256 si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih)));
258 /* reset the enet core */
259 chipreset(ch);
261 /* dma attach */
262 sprintf(name, "et%d", etc->coreunit);
263 if ((ch->di = dma_attach(osh, name, ch->sih,
264 (void *)&regs->dmaregs.xmt, (void *)&regs->dmaregs.rcv,
265 NTXD, NRXD, RXBUFSZ, -1, NRXBUFPOST, HWRXOFF,
266 &et_msg_level)) == NULL) {
267 ET_ERROR(("et%d: chipattach: dma_attach failed\n", etc->unit));
268 goto fail;
270 etc->txavail[TX_Q0] = (uint *)&ch->di->txavail;
272 /* set default sofware intmask */
273 ch->intmask = DEF_INTMASK;
276 * For the 5222 dual phy shared mdio contortion, our phy is
277 * on someone elses mdio pins. This other enet enet
278 * may not yet be attached so we must defer the et_phyfind().
280 /* if local phy: reset it once now */
281 if (etc->mdcport == etc->coreunit)
282 chipphyreset(ch, etc->phyaddr);
284 #ifdef ETROBO
286 * Broadcom Robo ethernet switch.
288 if ((boardflags & BFL_ENETROBO) &&
289 (etc->phyaddr == EPHY_NOREG)) {
290 /* Attach to the switch */
291 if (!(etc->robo = bcm_robo_attach(ch->sih, ch, ch->vars,
292 (miird_f)bcm47xx_et_chops.phyrd,
293 (miiwr_f)bcm47xx_et_chops.phywr))) {
294 ET_ERROR(("et%d: chipattach: robo_attach failed\n", etc->unit));
295 goto fail;
297 /* Enable the switch and set it to a known good state */
298 if (bcm_robo_enable_device(etc->robo)) {
299 ET_ERROR(("et%d: chipattach: robo_enable_device failed\n", etc->unit));
300 goto fail;
302 /* Configure the switch to do VLAN */
303 if ((boardflags & BFL_ENETVLAN) &&
304 bcm_robo_config_vlan(etc->robo, etc->perm_etheraddr.octet)) {
305 ET_ERROR(("et%d: chipattach: robo_config_vlan failed\n", etc->unit));
306 goto fail;
308 /* Enable switching/forwarding */
309 if (bcm_robo_enable_switch(etc->robo)) {
310 ET_ERROR(("et%d: chipattach: robo_enable_switch failed\n", etc->unit));
311 goto fail;
314 #endif /* ETROBO */
316 #ifdef ETADM
318 * ADMtek ethernet switch.
320 if (boardflags & BFL_ENETADM) {
321 /* Attach to the device */
322 if (!(ch->adm = adm_attach(ch->sih, ch->vars))) {
323 ET_ERROR(("et%d: chipattach: adm_attach failed\n", etc->unit));
324 goto fail;
326 /* Enable the external switch and set it to a known good state */
327 if (adm_enable_device(ch->adm)) {
328 ET_ERROR(("et%d: chipattach: adm_enable_device failed\n", etc->unit));
329 goto fail;
331 /* Configure the switch */
332 if ((boardflags & BFL_ENETVLAN) && adm_config_vlan(ch->adm)) {
333 ET_ERROR(("et%d: chipattach: adm_config_vlan failed\n", etc->unit));
334 goto fail;
337 #endif /* ETADM */
339 return ((void *)ch);
341 fail:
342 chipdetach(ch);
343 return (NULL);
346 static void
347 chipdetach(struct bcm4xxx *ch)
349 ET_TRACE(("et%d: chipdetach\n", ch->etc->unit));
351 if (ch == NULL)
352 return;
354 #ifdef ETROBO
355 /* free robo state */
356 if (ch->etc->robo)
357 bcm_robo_detach(ch->etc->robo);
358 #endif /* ETROBO */
360 #ifdef ETADM
361 /* free ADMtek state */
362 if (ch->adm)
363 adm_detach(ch->adm);
364 #endif /* ETADM */
366 /* free dma state */
367 if (ch->di)
368 dma_detach(ch->di);
369 ch->di = NULL;
371 /* put the core back into reset */
372 if (ch->sih)
373 si_core_disable(ch->sih, 0);
375 /* free si handle */
376 si_detach(ch->sih);
377 ch->sih = NULL;
379 /* free vars */
380 if (ch->vars)
381 MFREE(ch->osh, ch->vars, ch->vars_size);
383 /* free chip private state */
384 MFREE(ch->osh, ch, sizeof(struct bcm4xxx));
387 static void
388 chiplongname(struct bcm4xxx *ch, char *buf, uint bufsize)
390 char *s;
392 switch (ch->etc->deviceid) {
393 case BCM47XX_ENET_ID:
394 default:
395 s = "Broadcom BCM47xx 10/100 Mbps Ethernet Controller";
396 break;
399 strncpy(buf, s, bufsize);
400 buf[bufsize - 1] = '\0';
403 static void
404 chipdump(struct bcm4xxx *ch, struct bcmstrbuf *b)
406 #ifdef BCMDBG
407 bcm_bprintf(b, "regs 0x%x etphy 0x%x ch->intstatus 0x%x intmask 0x%x\n",
408 (ulong)ch->regs, (ulong)ch->etphy, ch->intstatus, ch->intmask);
409 bcm_bprintf(b, "\n");
411 /* dma engine state */
412 dma_dump(ch->di, b, FALSE);
413 bcm_bprintf(b, "\n");
415 /* registers */
416 chipdumpregs(ch, ch->regs, b);
417 bcm_bprintf(b, "\n");
419 /* switch registers */
420 #ifdef ETROBO
421 if (ch->etc->robo)
422 robo_dump_regs(ch->etc->robo, b);
423 #endif /* ETROBO */
424 #ifdef ETADM
425 if (ch->adm)
426 adm_dump_regs(ch->adm, b->buf);
427 #endif /* ETADM */
428 #endif /* BCMDBG */
431 #ifdef BCMDBG
433 #define PRREG(name) bcm_bprintf(b, #name " 0x%x ", R_REG(ch->osh, &regs->name))
434 #define PRMIBREG(name) bcm_bprintf(b, #name " 0x%x ", R_REG(ch->osh, &regs->mib.name))
436 static void
437 chipdumpregs(struct bcm4xxx *ch, bcmenetregs_t *regs, struct bcmstrbuf *b)
439 uint phyaddr;
441 phyaddr = ch->etc->phyaddr;
443 PRREG(devcontrol); PRREG(biststatus); PRREG(wakeuplength);
444 bcm_bprintf(b, "\n");
445 PRREG(intstatus); PRREG(intmask); PRREG(gptimer);
446 bcm_bprintf(b, "\n");
447 PRREG(emactxmaxburstlen); PRREG(emacrxmaxburstlen);
448 PRREG(emaccontrol); PRREG(emacflowcontrol);
449 bcm_bprintf(b, "\n");
450 PRREG(intrecvlazy);
451 bcm_bprintf(b, "\n");
453 /* emac registers */
454 PRREG(rxconfig); PRREG(rxmaxlength); PRREG(txmaxlength);
455 bcm_bprintf(b, "\n");
456 PRREG(mdiocontrol); PRREG(camcontrol); PRREG(enetcontrol);
457 bcm_bprintf(b, "\n");
458 PRREG(txcontrol); PRREG(txwatermark); PRREG(mibcontrol);
459 bcm_bprintf(b, "\n");
461 /* mib registers */
462 PRMIBREG(tx_good_octets); PRMIBREG(tx_good_pkts); PRMIBREG(tx_octets); PRMIBREG(tx_pkts);
463 bcm_bprintf(b, "\n");
464 PRMIBREG(tx_broadcast_pkts); PRMIBREG(tx_multicast_pkts);
465 bcm_bprintf(b, "\n");
466 PRMIBREG(tx_jabber_pkts); PRMIBREG(tx_oversize_pkts); PRMIBREG(tx_fragment_pkts);
467 bcm_bprintf(b, "\n");
468 PRMIBREG(tx_underruns); PRMIBREG(tx_total_cols); PRMIBREG(tx_single_cols);
469 bcm_bprintf(b, "\n");
470 PRMIBREG(tx_multiple_cols); PRMIBREG(tx_excessive_cols); PRMIBREG(tx_late_cols);
471 bcm_bprintf(b, "\n");
472 PRMIBREG(tx_defered); PRMIBREG(tx_carrier_lost); PRMIBREG(tx_pause_pkts);
473 bcm_bprintf(b, "\n");
475 PRMIBREG(rx_good_octets); PRMIBREG(rx_good_pkts); PRMIBREG(rx_octets); PRMIBREG(rx_pkts);
476 bcm_bprintf(b, "\n");
477 PRMIBREG(rx_broadcast_pkts); PRMIBREG(rx_multicast_pkts);
478 bcm_bprintf(b, "\n");
479 PRMIBREG(rx_jabber_pkts); PRMIBREG(rx_oversize_pkts); PRMIBREG(rx_fragment_pkts);
480 bcm_bprintf(b, "\n");
481 PRMIBREG(rx_missed_pkts); PRMIBREG(rx_crc_align_errs); PRMIBREG(rx_undersize);
482 bcm_bprintf(b, "\n");
483 PRMIBREG(rx_crc_errs); PRMIBREG(rx_align_errs); PRMIBREG(rx_symbol_errs);
484 bcm_bprintf(b, "\n");
485 PRMIBREG(rx_pause_pkts); PRMIBREG(rx_nonpause_pkts);
486 bcm_bprintf(b, "\n");
488 if (phyaddr != EPHY_NOREG) {
489 /* print a few interesting phy registers */
490 bcm_bprintf(b, "phy0 0x%x phy1 0x%x phy2 0x%x phy3 0x%x\n",
491 chipphyrd(ch, phyaddr, 0),
492 chipphyrd(ch, phyaddr, 1),
493 chipphyrd(ch, phyaddr, 2),
494 chipphyrd(ch, phyaddr, 3));
495 bcm_bprintf(b, "phy4 0x%x phy5 0x%x phy24 0x%x phy25 0x%x\n",
496 chipphyrd(ch, phyaddr, 4),
497 chipphyrd(ch, phyaddr, 5),
498 chipphyrd(ch, phyaddr, 24),
499 chipphyrd(ch, phyaddr, 25));
503 #endif /* BCMDBG */
505 #define MDC_RATIO 5000000
507 static void
508 chipreset(struct bcm4xxx *ch)
510 bcmenetregs_t *regs;
511 uint32 clk, mdc;
513 ET_TRACE(("et%d: chipreset\n", ch->etc->unit));
515 regs = ch->regs;
517 if (!si_iscoreup(ch->sih)) {
518 if (!ch->etc->nicmode)
519 si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih)));
520 /* power on reset: reset the enet core */
521 si_core_reset(ch->sih, 0, 0);
522 goto chipinreset;
525 /* read counters before resetting the chip */
526 if (ch->mibgood)
527 chipstatsupd(ch);
529 /* reset the tx dma engine */
530 if (ch->di)
531 dma_txreset(ch->di);
533 /* set emac into loopback mode to ensure no rx traffic */
534 W_REG(ch->osh, &regs->rxconfig, ERC_LE);
535 OSL_DELAY(1);
537 /* reset the rx dma engine */
538 if (ch->di)
539 dma_rxreset(ch->di);
541 /* reset core */
542 si_core_reset(ch->sih, 0, 0);
544 chipinreset:
546 /* must clear mib registers by hand */
547 W_REG(ch->osh, &regs->mibcontrol, EMC_RZ);
548 (void) R_REG(ch->osh, &regs->mib.tx_broadcast_pkts);
549 (void) R_REG(ch->osh, &regs->mib.tx_multicast_pkts);
550 (void) R_REG(ch->osh, &regs->mib.tx_len_64);
551 (void) R_REG(ch->osh, &regs->mib.tx_len_65_to_127);
552 (void) R_REG(ch->osh, &regs->mib.tx_len_128_to_255);
553 (void) R_REG(ch->osh, &regs->mib.tx_len_256_to_511);
554 (void) R_REG(ch->osh, &regs->mib.tx_len_512_to_1023);
555 (void) R_REG(ch->osh, &regs->mib.tx_len_1024_to_max);
556 (void) R_REG(ch->osh, &regs->mib.tx_jabber_pkts);
557 (void) R_REG(ch->osh, &regs->mib.tx_oversize_pkts);
558 (void) R_REG(ch->osh, &regs->mib.tx_fragment_pkts);
559 (void) R_REG(ch->osh, &regs->mib.tx_underruns);
560 (void) R_REG(ch->osh, &regs->mib.tx_total_cols);
561 (void) R_REG(ch->osh, &regs->mib.tx_single_cols);
562 (void) R_REG(ch->osh, &regs->mib.tx_multiple_cols);
563 (void) R_REG(ch->osh, &regs->mib.tx_excessive_cols);
564 (void) R_REG(ch->osh, &regs->mib.tx_late_cols);
565 (void) R_REG(ch->osh, &regs->mib.tx_defered);
566 (void) R_REG(ch->osh, &regs->mib.tx_carrier_lost);
567 (void) R_REG(ch->osh, &regs->mib.tx_pause_pkts);
568 (void) R_REG(ch->osh, &regs->mib.rx_broadcast_pkts);
569 (void) R_REG(ch->osh, &regs->mib.rx_multicast_pkts);
570 (void) R_REG(ch->osh, &regs->mib.rx_len_64);
571 (void) R_REG(ch->osh, &regs->mib.rx_len_65_to_127);
572 (void) R_REG(ch->osh, &regs->mib.rx_len_128_to_255);
573 (void) R_REG(ch->osh, &regs->mib.rx_len_256_to_511);
574 (void) R_REG(ch->osh, &regs->mib.rx_len_512_to_1023);
575 (void) R_REG(ch->osh, &regs->mib.rx_len_1024_to_max);
576 (void) R_REG(ch->osh, &regs->mib.rx_jabber_pkts);
577 (void) R_REG(ch->osh, &regs->mib.rx_oversize_pkts);
578 (void) R_REG(ch->osh, &regs->mib.rx_fragment_pkts);
579 (void) R_REG(ch->osh, &regs->mib.rx_missed_pkts);
580 (void) R_REG(ch->osh, &regs->mib.rx_crc_align_errs);
581 (void) R_REG(ch->osh, &regs->mib.rx_undersize);
582 (void) R_REG(ch->osh, &regs->mib.rx_crc_errs);
583 (void) R_REG(ch->osh, &regs->mib.rx_align_errs);
584 (void) R_REG(ch->osh, &regs->mib.rx_symbol_errs);
585 (void) R_REG(ch->osh, &regs->mib.rx_pause_pkts);
586 (void) R_REG(ch->osh, &regs->mib.rx_nonpause_pkts);
587 ch->mibgood = TRUE;
590 * We want the phy registers to be accessible even when
591 * the driver is "downed" so initialize MDC preamble, frequency,
592 * and whether internal or external phy here.
594 /* default: 100Mhz SI clock and external phy */
595 W_REG(ch->osh, &regs->mdiocontrol, 0x94);
596 if (ch->etc->deviceid == BCM47XX_ENET_ID) {
597 /* 47xx chips: find out the clock */
598 if ((clk = si_clock(ch->sih)) != 0) {
599 mdc = 0x80 | ((clk + (MDC_RATIO / 2)) / MDC_RATIO);
600 W_REG(ch->osh, &regs->mdiocontrol, mdc);
601 } else {
602 ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, "
603 "using 100Mhz\n",
604 ch->etc->unit));
608 /* some chips have internal phy, some don't */
609 if (!(R_REG(ch->osh, &regs->devcontrol) & DC_IP)) {
610 W_REG(ch->osh, &regs->enetcontrol, EC_EP);
611 } else if (R_REG(ch->osh, &regs->devcontrol) & DC_ER) {
612 AND_REG(ch->osh, &regs->devcontrol, ~DC_ER);
613 OSL_DELAY(100);
614 chipphyinit(ch, ch->etc->phyaddr);
617 /* clear persistent sw intstatus */
618 ch->intstatus = 0;
622 * Initialize all the chip registers. If dma mode, init tx and rx dma engines
623 * but leave the devcontrol tx and rx (fifos) disabled.
625 static void
626 chipinit(struct bcm4xxx *ch, uint options)
628 etc_info_t *etc;
629 bcmenetregs_t *regs;
630 uint idx;
631 uint i;
633 regs = ch->regs;
634 etc = ch->etc;
635 idx = 0;
637 ET_TRACE(("et%d: chipinit\n", etc->unit));
639 /* enable crc32 generation */
640 OR_REG(ch->osh, &regs->emaccontrol, EMC_CG);
642 /* enable one rx interrupt per received frame */
643 W_REG(ch->osh, &regs->intrecvlazy, (1 << IRL_FC_SHIFT));
645 /* enable 802.3x tx flow control (honor received PAUSE frames) */
646 W_REG(ch->osh, &regs->rxconfig, ERC_FE | ERC_UF);
648 /* initialize CAM */
649 if (etc->promisc || (R_REG(ch->osh, &regs->rxconfig) & ERC_CA))
650 OR_REG(ch->osh, &regs->rxconfig, ERC_PE);
651 else {
652 /* our local address */
653 chipwrcam(ch, &etc->cur_etheraddr, idx++);
655 /* allmulti or a list of discrete multicast addresses */
656 if (etc->allmulti)
657 OR_REG(ch->osh, &regs->rxconfig, ERC_AM);
658 else if (etc->nmulticast) {
659 for (i = 0; i < etc->nmulticast; i++)
660 chipwrcam(ch, &etc->multicast[i], idx++);
663 /* enable cam */
664 OR_REG(ch->osh, &regs->camcontrol, CC_CE);
667 /* optionally enable mac-level loopback */
668 if (etc->loopbk)
669 OR_REG(ch->osh, &regs->rxconfig, ERC_LE);
671 /* set max frame lengths - account for possible vlan tag */
672 W_REG(ch->osh, &regs->rxmaxlength, ETHER_MAX_LEN + 32);
673 W_REG(ch->osh, &regs->txmaxlength, ETHER_MAX_LEN + 32);
675 /* set tx watermark */
676 W_REG(ch->osh, &regs->txwatermark, 56);
679 * Optionally, disable phy autonegotiation and force our speed/duplex
680 * or constrain our advertised capabilities.
682 if (etc->forcespeed != ET_AUTO)
683 chipphyforce(ch, etc->phyaddr);
684 else if (etc->advertise && etc->needautoneg)
685 chipphyadvertise(ch, etc->phyaddr);
687 if (options & ET_INIT_FULL) {
688 /* initialize the tx and rx dma channels */
689 dma_txinit(ch->di);
690 dma_rxinit(ch->di);
692 /* post dma receive buffers */
693 dma_rxfill(ch->di);
695 /* lastly, enable interrupts */
696 if (options & ET_INIT_INTRON)
697 et_intrson(etc->et);
699 else
700 dma_rxenable(ch->di);
702 /* turn on the emac */
703 OR_REG(ch->osh, &regs->enetcontrol, EC_EE);
706 /* dma transmit */
707 static bool BCMFASTPATH
708 chiptx(struct bcm4xxx *ch, void *p0)
710 int error;
712 ET_TRACE(("et%d: chiptx\n", ch->etc->unit));
713 ET_LOG("et%d: chiptx", ch->etc->unit, 0);
715 error = dma_txfast(ch->di, p0, TRUE);
717 if (error) {
718 ET_ERROR(("et%d: chiptx: out of txds\n", ch->etc->unit));
719 ch->etc->txnobuf++;
720 return FALSE;
722 return TRUE;
725 /* reclaim completed transmit descriptors and packets */
726 static void BCMFASTPATH
727 chiptxreclaim(struct bcm4xxx *ch, bool forceall)
729 ET_TRACE(("et%d: chiptxreclaim\n", ch->etc->unit));
730 dma_txreclaim(ch->di, forceall ? HNDDMA_RANGE_ALL : HNDDMA_RANGE_TRANSMITTED);
731 ch->intstatus &= ~I_XI;
734 /* dma receive: returns a pointer to the next frame received, or NULL if there are no more */
735 static void * BCMFASTPATH
736 chiprx(struct bcm4xxx *ch)
738 void *p;
740 ET_TRACE(("et%d: chiprx\n", ch->etc->unit));
741 ET_LOG("et%d: chiprx", ch->etc->unit, 0);
743 if ((p = dma_rx(ch->di)) == NULL)
744 ch->intstatus &= ~I_RI;
746 return (p);
749 /* reclaim completed dma receive descriptors and packets */
750 static void
751 chiprxreclaim(struct bcm4xxx *ch)
753 ET_TRACE(("et%d: chiprxreclaim\n", ch->etc->unit));
754 dma_rxreclaim(ch->di);
755 ch->intstatus &= ~I_RI;
758 /* allocate and post dma receive buffers */
759 static void BCMFASTPATH
760 chiprxfill(struct bcm4xxx *ch)
762 ET_TRACE(("et%d: chiprxfill\n", ch->etc->unit));
763 ET_LOG("et%d: chiprx", ch->etc->unit, 0);
764 dma_rxfill(ch->di);
767 /* get current and pending interrupt events */
768 static int BCMFASTPATH
769 chipgetintrevents(struct bcm4xxx *ch, bool in_isr)
771 bcmenetregs_t *regs;
772 uint32 intstatus;
773 int events;
775 regs = ch->regs;
776 events = 0;
778 /* read the interrupt status register */
779 intstatus = R_REG(ch->osh, &regs->intstatus);
781 /* defer unsolicited interrupts */
782 intstatus &= (in_isr ? ch->intmask : DEF_INTMASK);
784 /* clear non-error interrupt conditions */
785 if (intstatus != 0) {
786 W_REG(ch->osh, &regs->intstatus, intstatus);
787 events = INTR_NEW;
790 /* or new bits into persistent intstatus */
791 intstatus = (ch->intstatus |= intstatus);
793 /* return if no events */
794 if (intstatus == 0)
795 return (0);
797 /* convert chip-specific intstatus bits into generic intr event bits */
798 if (intstatus & I_RI)
799 events |= INTR_RX;
800 if (intstatus & I_XI)
801 events |= INTR_TX;
802 if (intstatus & I_ERRORS)
803 events |= INTR_ERROR;
804 if (intstatus & I_TO)
805 events |= INTR_TO;
807 return (events);
810 /* enable chip interrupts */
811 static void BCMFASTPATH
812 chipintrson(struct bcm4xxx *ch)
814 ch->intmask = DEF_INTMASK;
815 W_REG(ch->osh, &ch->regs->intmask, ch->intmask);
818 /* disable chip interrupts */
819 static void BCMFASTPATH
820 chipintrsoff(struct bcm4xxx *ch)
822 W_REG(ch->osh, &ch->regs->intmask, 0);
823 (void) R_REG(ch->osh, &ch->regs->intmask); /* sync readback */
824 ch->intmask = 0;
827 /* return true of caller should re-initialize, otherwise false */
828 static bool BCMFASTPATH
829 chiperrors(struct bcm4xxx *ch)
831 uint32 intstatus;
832 etc_info_t *etc;
834 etc = ch->etc;
836 intstatus = ch->intstatus;
837 ch->intstatus &= ~(I_ERRORS);
839 ET_TRACE(("et%d: chiperrors: intstatus 0x%x\n", etc->unit, intstatus));
841 if (intstatus & I_PC) {
842 ET_ERROR(("et%d: descriptor error\n", etc->unit));
843 etc->dmade++;
846 if (intstatus & I_PD) {
847 ET_ERROR(("et%d: data error\n", etc->unit));
848 etc->dmada++;
851 if (intstatus & I_DE) {
852 ET_ERROR(("et%d: descriptor protocol error\n", etc->unit));
853 etc->dmape++;
855 /* NOTE : this ie NOT an error. It becomes an error only
856 * when the rx fifo overflows
858 if (intstatus & I_RU) {
859 ET_ERROR(("et%d: receive descriptor underflow\n", etc->unit));
860 etc->rxdmauflo++;
863 if (intstatus & I_RO) {
864 ET_ERROR(("et%d: receive fifo overflow\n", etc->unit));
865 etc->rxoflo++;
868 if (intstatus & I_XU) {
869 ET_ERROR(("et%d: transmit fifo underflow\n", etc->unit));
870 etc->txuflo++;
872 /* if overflows or decriptors underflow, don't report it
873 * as an error and provoque a reset
875 if (intstatus & ~(I_RU) & I_ERRORS)
876 return (TRUE);
877 return FALSE;
880 static void
881 chipwrcam(struct bcm4xxx *ch, struct ether_addr *ea, uint camindex)
883 uint32 w;
885 ASSERT((R_REG(ch->osh, &ch->regs->camcontrol) & (CC_CB | CC_CE)) == 0);
887 w = (ea->octet[2] << 24) | (ea->octet[3] << 16) | (ea->octet[4] << 8)
888 | ea->octet[5];
889 W_REG(ch->osh, &ch->regs->camdatalo, w);
890 w = CD_V | (ea->octet[0] << 8) | ea->octet[1];
891 W_REG(ch->osh, &ch->regs->camdatahi, w);
892 W_REG(ch->osh, &ch->regs->camcontrol, ((camindex << CC_INDEX_SHIFT) | CC_WR));
894 /* spin until done */
895 SPINWAIT((R_REG(ch->osh, &ch->regs->camcontrol) & CC_CB), 1000);
898 * This assertion is usually caused by the phy not providing a clock
899 * to the bottom portion of the mac..
901 ASSERT((R_REG(ch->osh, &ch->regs->camcontrol) & CC_CB) == 0);
904 static void
905 chipstatsupd(struct bcm4xxx *ch)
907 etc_info_t *etc;
908 bcmenetregs_t *regs;
909 bcmenetmib_t *m;
911 etc = ch->etc;
912 regs = ch->regs;
913 m = &ch->mib;
916 * mib counters are clear-on-read.
917 * Don't bother using the pkt and octet counters since they are only
918 * 16bits and wrap too quickly to be useful.
920 m->tx_broadcast_pkts += R_REG(ch->osh, &regs->mib.tx_broadcast_pkts);
921 m->tx_multicast_pkts += R_REG(ch->osh, &regs->mib.tx_multicast_pkts);
922 m->tx_len_64 += R_REG(ch->osh, &regs->mib.tx_len_64);
923 m->tx_len_65_to_127 += R_REG(ch->osh, &regs->mib.tx_len_65_to_127);
924 m->tx_len_128_to_255 += R_REG(ch->osh, &regs->mib.tx_len_128_to_255);
925 m->tx_len_256_to_511 += R_REG(ch->osh, &regs->mib.tx_len_256_to_511);
926 m->tx_len_512_to_1023 += R_REG(ch->osh, &regs->mib.tx_len_512_to_1023);
927 m->tx_len_1024_to_max += R_REG(ch->osh, &regs->mib.tx_len_1024_to_max);
928 m->tx_jabber_pkts += R_REG(ch->osh, &regs->mib.tx_jabber_pkts);
929 m->tx_oversize_pkts += R_REG(ch->osh, &regs->mib.tx_oversize_pkts);
930 m->tx_fragment_pkts += R_REG(ch->osh, &regs->mib.tx_fragment_pkts);
931 m->tx_underruns += R_REG(ch->osh, &regs->mib.tx_underruns);
932 m->tx_total_cols += R_REG(ch->osh, &regs->mib.tx_total_cols);
933 m->tx_single_cols += R_REG(ch->osh, &regs->mib.tx_single_cols);
934 m->tx_multiple_cols += R_REG(ch->osh, &regs->mib.tx_multiple_cols);
935 m->tx_excessive_cols += R_REG(ch->osh, &regs->mib.tx_excessive_cols);
936 m->tx_late_cols += R_REG(ch->osh, &regs->mib.tx_late_cols);
937 m->tx_defered += R_REG(ch->osh, &regs->mib.tx_defered);
938 m->tx_carrier_lost += R_REG(ch->osh, &regs->mib.tx_carrier_lost);
939 m->tx_pause_pkts += R_REG(ch->osh, &regs->mib.tx_pause_pkts);
940 m->rx_broadcast_pkts += R_REG(ch->osh, &regs->mib.rx_broadcast_pkts);
941 m->rx_multicast_pkts += R_REG(ch->osh, &regs->mib.rx_multicast_pkts);
942 m->rx_len_64 += R_REG(ch->osh, &regs->mib.rx_len_64);
943 m->rx_len_65_to_127 += R_REG(ch->osh, &regs->mib.rx_len_65_to_127);
944 m->rx_len_128_to_255 += R_REG(ch->osh, &regs->mib.rx_len_128_to_255);
945 m->rx_len_256_to_511 += R_REG(ch->osh, &regs->mib.rx_len_256_to_511);
946 m->rx_len_512_to_1023 += R_REG(ch->osh, &regs->mib.rx_len_512_to_1023);
947 m->rx_len_1024_to_max += R_REG(ch->osh, &regs->mib.rx_len_1024_to_max);
948 m->rx_jabber_pkts += R_REG(ch->osh, &regs->mib.rx_jabber_pkts);
949 m->rx_oversize_pkts += R_REG(ch->osh, &regs->mib.rx_oversize_pkts);
950 m->rx_fragment_pkts += R_REG(ch->osh, &regs->mib.rx_fragment_pkts);
951 m->rx_missed_pkts += R_REG(ch->osh, &regs->mib.rx_missed_pkts);
952 m->rx_crc_align_errs += R_REG(ch->osh, &regs->mib.rx_crc_align_errs);
953 m->rx_undersize += R_REG(ch->osh, &regs->mib.rx_undersize);
954 m->rx_crc_errs += R_REG(ch->osh, &regs->mib.rx_crc_errs);
955 m->rx_align_errs += R_REG(ch->osh, &regs->mib.rx_align_errs);
956 m->rx_symbol_errs += R_REG(ch->osh, &regs->mib.rx_symbol_errs);
957 m->rx_pause_pkts += R_REG(ch->osh, &regs->mib.rx_pause_pkts);
958 m->rx_nonpause_pkts += R_REG(ch->osh, &regs->mib.rx_nonpause_pkts);
961 * Aggregate transmit and receive errors that probably resulted
962 * in the loss of a frame are computed on the fly.
964 * We seem to get lots of tx_carrier_lost errors when flipping
965 * speed modes so don't count these as tx errors.
967 * Arbitrarily lump the non-specific dma errors as tx errors.
969 etc->txerror = m->tx_jabber_pkts + m->tx_oversize_pkts
970 + m->tx_underruns + m->tx_excessive_cols
971 + m->tx_late_cols + etc->txnobuf + etc->dmade
972 + etc->dmada + etc->dmape + etc->txuflo;
973 etc->rxerror = m->rx_jabber_pkts + m->rx_oversize_pkts
974 + m->rx_missed_pkts + m->rx_crc_align_errs
975 + m->rx_undersize + m->rx_crc_errs
976 + m->rx_align_errs + m->rx_symbol_errs
977 + etc->rxnobuf + etc->rxdmauflo + etc->rxoflo + etc->rxbadlen;
980 static void
981 chipdumpmib(ch_t *ch, struct bcmstrbuf *b, bool clear)
983 bcmenetmib_t *m;
985 m = &ch->mib;
987 if (clear) {
988 bzero((char *)m, sizeof(bcmenetmib_t));
989 return;
992 bcm_bprintf(b, "tx_broadcast_pkts %d tx_multicast_pkts %d tx_jabber_pkts %d "
993 "tx_oversize_pkts %d\n",
994 m->tx_broadcast_pkts, m->tx_multicast_pkts,
995 m->tx_jabber_pkts,
996 m->tx_oversize_pkts);
997 bcm_bprintf(b, "tx_fragment_pkts %d tx_underruns %d\n",
998 m->tx_fragment_pkts, m->tx_underruns);
999 bcm_bprintf(b, "tx_total_cols %d tx_single_cols %d tx_multiple_cols %d "
1000 "tx_excessive_cols %d\n",
1001 m->tx_total_cols, m->tx_single_cols, m->tx_multiple_cols,
1002 m->tx_excessive_cols);
1003 bcm_bprintf(b, "tx_late_cols %d tx_defered %d tx_carrier_lost %d tx_pause_pkts %d\n",
1004 m->tx_late_cols, m->tx_defered, m->tx_carrier_lost,
1005 m->tx_pause_pkts);
1007 /* receive stat counters */
1008 /* hardware mib pkt and octet counters wrap too quickly to be useful */
1009 bcm_bprintf(b, "rx_broadcast_pkts %d rx_multicast_pkts %d rx_jabber_pkts %d "
1010 "rx_oversize_pkts %d\n",
1011 m->rx_broadcast_pkts, m->rx_multicast_pkts,
1012 m->rx_jabber_pkts, m->rx_oversize_pkts);
1013 bcm_bprintf(b, "rx_fragment_pkts %d rx_missed_pkts %d rx_crc_align_errs %d "
1014 "rx_undersize %d\n",
1015 m->rx_fragment_pkts, m->rx_missed_pkts,
1016 m->rx_crc_align_errs, m->rx_undersize);
1017 bcm_bprintf(b, "rx_crc_errs %d rx_align_errs %d rx_symbol_errs %d\n",
1018 m->rx_crc_errs, m->rx_align_errs, m->rx_symbol_errs);
1019 bcm_bprintf(b, "rx_pause_pkts %d rx_nonpause_pkts %d\n",
1020 m->rx_pause_pkts, m->rx_nonpause_pkts);
1023 static void
1024 chipenablepme(struct bcm4xxx *ch)
1026 bcmenetregs_t *regs;
1028 regs = ch->regs;
1030 /* enable chip wakeup pattern matching */
1031 OR_REG(ch->osh, &regs->devcontrol, DC_PM);
1033 /* enable sonics bus PME */
1034 si_core_cflags(ch->sih, SICF_PME_EN, SICF_PME_EN);
1037 static void
1038 chipdisablepme(struct bcm4xxx *ch)
1040 bcmenetregs_t *regs;
1042 regs = ch->regs;
1044 AND_REG(ch->osh, &regs->devcontrol, ~DC_PM);
1045 si_core_cflags(ch->sih, SICF_PME_EN, 0);
1048 static void
1049 chipduplexupd(struct bcm4xxx *ch)
1051 uint32 txcontrol;
1053 txcontrol = R_REG(ch->osh, &ch->regs->txcontrol);
1054 if (ch->etc->duplex && !(txcontrol & EXC_FD))
1055 OR_REG(ch->osh, &ch->regs->txcontrol, EXC_FD);
1056 else if (!ch->etc->duplex && (txcontrol & EXC_FD))
1057 AND_REG(ch->osh, &ch->regs->txcontrol, ~EXC_FD);
1060 static uint16
1061 chipphyrd(struct bcm4xxx *ch, uint phyaddr, uint reg)
1063 bcmenetregs_t *regs;
1065 ASSERT(phyaddr < MAXEPHY);
1068 * BCM5222 dualphy shared mdio contortion.
1069 * remote phy: another emac controls our phy.
1071 if (ch->etc->mdcport != ch->etc->coreunit) {
1072 if (ch->etphy == NULL) {
1073 ch->etphy = et_phyfind(ch->et, ch->etc->mdcport);
1075 /* first time reset */
1076 if (ch->etphy)
1077 chipphyreset(ch, ch->etc->phyaddr);
1079 if (ch->etphy)
1080 return (et_phyrd(ch->etphy, phyaddr, reg));
1081 else
1082 return (0xffff);
1085 /* local phy: our emac controls our phy */
1087 regs = ch->regs;
1089 /* clear mii_int */
1090 W_REG(ch->osh, &regs->emacintstatus, EI_MII);
1092 /* issue the read */
1093 W_REG(ch->osh, &regs->mdiodata, (MD_SB_START | MD_OP_READ | (phyaddr << MD_PMD_SHIFT)
1094 | (reg << MD_RA_SHIFT) | MD_TA_VALID));
1096 /* wait for it to complete */
1097 SPINWAIT(((R_REG(ch->osh, &regs->emacintstatus) & EI_MII) == 0), 100);
1098 if ((R_REG(ch->osh, &regs->emacintstatus) & EI_MII) == 0) {
1099 ET_ERROR(("et%d: chipphyrd: did not complete\n", ch->etc->unit));
1102 return (R_REG(ch->osh, &regs->mdiodata) & MD_DATA_MASK);
1105 static void
1106 chipphywr(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v)
1108 bcmenetregs_t *regs;
1110 ASSERT(phyaddr < MAXEPHY);
1113 * BCM5222 dualphy shared mdio contortion.
1114 * remote phy: another emac controls our phy.
1116 if (ch->etc->mdcport != ch->etc->coreunit) {
1117 if (ch->etphy == NULL)
1118 ch->etphy = et_phyfind(ch->et, ch->etc->mdcport);
1119 if (ch->etphy)
1120 et_phywr(ch->etphy, phyaddr, reg, v);
1121 return;
1124 /* local phy: our emac controls our phy */
1126 regs = ch->regs;
1128 /* clear mii_int */
1129 W_REG(ch->osh, &regs->emacintstatus, EI_MII);
1130 ASSERT((R_REG(ch->osh, &regs->emacintstatus) & EI_MII) == 0);
1132 /* issue the write */
1133 W_REG(ch->osh, &regs->mdiodata, (MD_SB_START | MD_OP_WRITE | (phyaddr << MD_PMD_SHIFT)
1134 | (reg << MD_RA_SHIFT) | MD_TA_VALID | v));
1136 /* wait for it to complete */
1137 SPINWAIT(((R_REG(ch->osh, &regs->emacintstatus) & EI_MII) == 0), 100);
1138 if ((R_REG(ch->osh, &regs->emacintstatus) & EI_MII) == 0) {
1139 ET_ERROR(("et%d: chipphywr: did not complete\n", ch->etc->unit));
1143 static void
1144 chipphyor(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v)
1146 uint16 tmp;
1148 tmp = chipphyrd(ch, phyaddr, reg);
1149 tmp |= v;
1150 chipphywr(ch, phyaddr, reg, tmp);
1153 static void
1154 chipphyand(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v)
1156 uint16 tmp;
1158 tmp = chipphyrd(ch, phyaddr, reg);
1159 tmp &= v;
1160 chipphywr(ch, phyaddr, reg, tmp);
1163 static void
1164 chipphyreset(struct bcm4xxx *ch, uint phyaddr)
1166 ASSERT(phyaddr < MAXEPHY);
1168 if (phyaddr == EPHY_NOREG)
1169 return;
1171 chipphywr(ch, phyaddr, 0, CTL_RESET);
1172 OSL_DELAY(100);
1173 if (chipphyrd(ch, phyaddr, 0) & CTL_RESET) {
1174 ET_ERROR(("et%d: chipphyreset: reset not complete\n", ch->etc->unit));
1177 chipphyinit(ch, phyaddr);
1180 static void
1181 chipphyinit(struct bcm4xxx *ch, uint phyaddr)
1183 uint phyid = 0;
1185 /* enable activity led */
1186 chipphyand(ch, phyaddr, 26, 0x7fff);
1188 /* enable traffic meter led mode */
1189 chipphyor(ch, phyaddr, 27, (1 << 6));
1191 phyid = chipphyrd(ch, phyaddr, 0x2);
1192 phyid |= chipphyrd(ch, phyaddr, 0x3) << 16;
1193 if (phyid == 0x55210022) {
1194 chipphywr(ch, phyaddr, 30, (uint16) (chipphyrd(ch, phyaddr, 30) | 0x3000));
1195 chipphywr(ch, phyaddr, 22, (uint16) (chipphyrd(ch, phyaddr, 22) & 0xffdf));
1199 static void
1200 chipphyforce(struct bcm4xxx *ch, uint phyaddr)
1202 etc_info_t *etc;
1203 uint16 ctl;
1205 ASSERT(phyaddr < MAXEPHY);
1207 if (phyaddr == EPHY_NOREG)
1208 return;
1210 etc = ch->etc;
1212 if (etc->forcespeed == ET_AUTO)
1213 return;
1215 ctl = chipphyrd(ch, phyaddr, 0);
1216 ctl &= ~(CTL_SPEED | CTL_ANENAB | CTL_DUPLEX);
1218 switch (etc->forcespeed) {
1219 case ET_10HALF:
1220 break;
1222 case ET_10FULL:
1223 ctl |= CTL_DUPLEX;
1224 break;
1226 case ET_100HALF:
1227 ctl |= CTL_SPEED;
1228 break;
1230 case ET_100FULL:
1231 ctl |= (CTL_SPEED | CTL_DUPLEX);
1232 break;
1235 chipphywr(ch, phyaddr, 0, ctl);
1238 /* set selected capability bits in autonegotiation advertisement */
1239 static void
1240 chipphyadvertise(struct bcm4xxx *ch, uint phyaddr)
1242 etc_info_t *etc;
1243 uint16 adv;
1245 ASSERT(phyaddr < MAXEPHY);
1247 if (phyaddr == EPHY_NOREG)
1248 return;
1250 etc = ch->etc;
1252 if ((etc->forcespeed != ET_AUTO) || !etc->needautoneg)
1253 return;
1255 ASSERT(etc->advertise);
1257 /* reset our advertised capabilitity bits */
1258 adv = chipphyrd(ch, phyaddr, 4);
1259 adv &= ~(ADV_100FULL | ADV_100HALF | ADV_10FULL | ADV_10HALF);
1260 adv |= etc->advertise;
1261 chipphywr(ch, phyaddr, 4, adv);
1263 /* restart autonegotiation */
1264 chipphyor(ch, phyaddr, 0, CTL_RESTART);
1266 etc->needautoneg = FALSE;