static int BCMFASTPATH chiprxquota(ch_t *ch, int quota, void **rxpkts) { int rxcnt; void * pkt; uint8 * addr; ET_TRACE(("et%d: chiprxquota\n", ch->etc->unit)); ET_LOG("et%d: chiprxquota", ch->etc->unit, 0); rxcnt = 0; while ((quota > 0) && ((pkt = dma_rx(ch->di)) != NULL)) { addr = PKTDATA(ch->osh, pkt); #if !defined(_CFE_) bcm_prefetch_32B(addr + 32, 1); #endif /* _CFE_ */ rxpkts[rxcnt] = pkt; rxcnt++; quota--; } if (rxcnt < quota) { /* ring is "possibly" empty, enable et interrupts */ ch->intstatus &= ~I_RI; } return rxcnt; /* rxpkts[] has rxcnt number of pkts to be processed */ }
/* reclaim completed transmit descriptors and packets */ static void BCMFASTPATH chiptxreclaim(struct bcm4xxx *ch, bool forceall) { ET_TRACE(("et%d: chiptxreclaim\n", ch->etc->unit)); dma_txreclaim(ch->di, forceall ? HNDDMA_RANGE_ALL : HNDDMA_RANGE_TRANSMITTED); ch->intstatus &= ~I_XI; }
/* allocate and post dma receive buffers */ static void BCMFASTPATH chiprxfill(struct bcm4xxx *ch) { ET_TRACE(("et%d: chiprxfill\n", ch->etc->unit)); ET_LOG("et%d: chiprx", ch->etc->unit, 0); dma_rxfill(ch->di); }
/* reclaim completed dma receive descriptors and packets */ static void chiprxreclaim(struct bcm4xxx *ch) { ET_TRACE(("et%d: chiprxreclaim\n", ch->etc->unit)); dma_rxreclaim(ch->di); ch->intstatus &= ~I_RI; }
static void etc_loopback(etc_info_t *etc, int on) { ET_TRACE(("et%d: etc_loopback: %d\n", etc->unit, on)); etc->loopbk = (bool) on; et_init(etc->et); }
void etc_qos(etc_info_t *etc, uint on) { ET_TRACE(("et%d: etc_qos: %d\n", etc->unit, on)); etc->qos = (bool) on; et_init(etc->et); }
void etc_promisc(etc_info_t *etc, uint on) { ET_TRACE(("et%d: etc_promisc: %d\n", etc->unit, on)); etc->promisc = (bool) on; et_init(etc->et); }
void etc_init(etc_info_t *etc, uint options) { ET_TRACE(("et%d: etc_init\n", etc->unit)); ASSERT(etc->pioactive == NULL); ASSERT(!ETHER_ISNULLADDR(&etc->cur_etheraddr)); ASSERT(!ETHER_ISMULTI(&etc->cur_etheraddr)); /* init the chip */ (*etc->chops->init)(etc->ch, options); }
/* dma receive: returns a pointer to the next frame received, or NULL if there are no more */ static void * BCMFASTPATH chiprx(struct bcm4xxx *ch) { void *p; ET_TRACE(("et%d: chiprx\n", ch->etc->unit)); ET_LOG("et%d: chiprx", ch->etc->unit, 0); if ((p = dma_rx(ch->di)) == NULL) ch->intstatus &= ~I_RI; return (p); }
/* return true of caller should re-initialize, otherwise false */ static bool BCMFASTPATH chiperrors(struct bcm4xxx *ch) { uint32 intstatus; etc_info_t *etc; etc = ch->etc; intstatus = ch->intstatus; ch->intstatus &= ~(I_ERRORS); ET_TRACE(("et%d: chiperrors: intstatus 0x%x\n", etc->unit, intstatus)); if (intstatus & I_PC) { ET_ERROR(("et%d: descriptor error\n", etc->unit)); etc->dmade++; } if (intstatus & I_PD) { ET_ERROR(("et%d: data error\n", etc->unit)); etc->dmada++; } if (intstatus & I_DE) { ET_ERROR(("et%d: descriptor protocol error\n", etc->unit)); etc->dmape++; } /* NOTE : this ie NOT an error. It becomes an error only * when the rx fifo overflows */ if (intstatus & I_RU) { ET_ERROR(("et%d: receive descriptor underflow\n", etc->unit)); etc->rxdmauflo++; } if (intstatus & I_RO) { ET_ERROR(("et%d: receive fifo overflow\n", etc->unit)); etc->rxoflo++; } if (intstatus & I_XU) { ET_ERROR(("et%d: transmit fifo underflow\n", etc->unit)); etc->txuflo++; } /* if overflows or decriptors underflow, don't report it * as an error and provoque a reset */ if (intstatus & ~(I_RU) & I_ERRORS) return (TRUE); return FALSE; }
/* dma transmit */ static bool BCMFASTPATH chiptx(struct bcm4xxx *ch, void *p0) { int error; ET_TRACE(("et%d: chiptx\n", ch->etc->unit)); ET_LOG("et%d: chiptx", ch->etc->unit, 0); error = dma_txfast(ch->di, p0, TRUE); if (error) { ET_ERROR(("et%d: chiptx: out of txds\n", ch->etc->unit)); ch->etc->txnobuf++; return FALSE; } return TRUE; }
void etc_reset(etc_info_t *etc) { ET_TRACE(("et%d: etc_reset\n", etc->unit)); etc->reset++; /* reset the chip */ (*etc->chops->reset)(etc->ch); /* free any posted tx packets */ (*etc->chops->txreclaim)(etc->ch, TRUE); #ifdef DMA /* free any posted rx packets */ (*etc->chops->rxreclaim)(etc->ch); #endif /* DMA */ }
void* etc_attach(void *et, uint vendor, uint device, uint unit, void *osh, void *regsva) { etc_info_t *etc; ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit, vendor, device)); /* some code depends on packed structures */ ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN); ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN); /* allocate etc_info_t state structure */ if ((etc = (etc_info_t*) MALLOC(osh, sizeof(etc_info_t))) == NULL) { ET_ERROR(("et%d: etc_attach: out of memory, malloced %d bytes\n", unit, MALLOCED(osh))); return (NULL); } bzero((char*)etc, sizeof(etc_info_t)); etc->et = et; etc->unit = unit; etc->osh = osh; etc->vendorid = (uint16) vendor; etc->deviceid = (uint16) device; etc->forcespeed = ET_AUTO; etc->linkstate = FALSE; /* set chip opsvec */ etc->chops = etc_chipmatch(vendor, device); ASSERT(etc->chops); /* chip attach */ if ((etc->ch = (*etc->chops->attach)(etc, osh, regsva)) == NULL) { ET_ERROR(("et%d: chipattach error\n", unit)); goto fail; } return ((void*)etc); fail: etc_detach(etc); return (NULL); }
/* common iovar handler. return 0=ok, -1=error */ int etc_iovar(etc_info_t *etc, uint cmd, uint set, void *arg) { int error; #ifdef ETROBO int i; uint *vecarg; robo_info_t *robo = etc->robo; #endif error = 0; ET_TRACE(("et%d: etc_iovar: cmd 0x%x\n", etc->unit, cmd)); switch (cmd) { #ifdef ETROBO case IOV_ET_POWER_SAVE_MODE: vecarg = (uint *)arg; if (set) error = robo_power_save_mode_set(robo, vecarg[1], vecarg[0]); else { /* get power save mode of all the phys */ if (vecarg[0] == MAX_NO_PHYS) { for (i = 0; i < MAX_NO_PHYS; i++) vecarg[i] = robo_power_save_mode_get(robo, i); break; } /* get power save mode of the phy */ error = robo_power_save_mode_get(robo, vecarg[0]); if (error != -1) { vecarg[1] = error; error = 0; } } break; #endif /* ETROBO */ default: error = -1; } return (error); }
static void chipdetach(struct bcm4xxx *ch) { ET_TRACE(("et%d: chipdetach\n", ch->etc->unit)); if (ch == NULL) return; #ifdef ETROBO /* free robo state */ if (ch->etc->robo) bcm_robo_detach(ch->etc->robo); #endif /* ETROBO */ #ifdef ETADM /* free ADMtek state */ if (ch->adm) adm_detach(ch->adm); #endif /* ETADM */ /* free dma state */ if (ch->di) dma_detach(ch->di); ch->di = NULL; /* put the core back into reset */ if (ch->sih) si_core_disable(ch->sih, 0); /* free si handle */ si_detach(ch->sih); ch->sih = NULL; /* free vars */ if (ch->vars) MFREE(ch->osh, ch->vars, ch->vars_size); /* free chip private state */ MFREE(ch->osh, ch, sizeof(struct bcm4xxx)); }
/* common ioctl handler. return: 0=ok, -1=error */ int etc_ioctl(etc_info_t *etc, int cmd, void *arg) { int error; int val; int *vec = (int*)arg; error = 0; val = arg? *(int*)arg: 0; ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd)); switch (cmd) { case ETCUP: et_up(etc->et); break; case ETCDOWN: et_down(etc->et, TRUE); break; case ETCLOOP: etc_loopback(etc, val); break; case ETCDUMP: if (et_msg_level & 0x10000) bcmdumplog((uchar*)arg, 4096); break; case ETCSETMSGLEVEL: et_msg_level = val; break; case ETCPROMISC: etc_promisc(etc, val); break; case ETCQOS: etc_qos(etc, val); break; case ETCSPEED: if ((val != ET_AUTO) && (val != ET_10HALF) && (val != ET_10FULL) && (val != ET_100HALF) && (val != ET_100FULL)) goto err; etc->forcespeed = val; /* explicitly reset the phy */ (*etc->chops->phyreset)(etc->ch, etc->phyaddr); /* request restart autonegotiation if we're reverting to adv mode */ if ((etc->forcespeed == ET_AUTO) & etc->advertise) etc->needautoneg = TRUE; et_init(etc->et); break; case ETCPHYRD: if (vec) vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]); break; case ETCPHYWR: if (vec) (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16) vec[1]); break; default: err: error = -1; } return (error); }
/* common ioctl handler. return: 0=ok, -1=error */ int etc_ioctl(etc_info_t *etc, int cmd, void *arg) { int error; int val; int *vec = (int*)arg; error = 0; val = arg ? *(int*)arg : 0; ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd)); switch (cmd) { case ETCUP: et_up(etc->et); break; case ETCDOWN: et_down(etc->et, TRUE); break; case ETCLOOP: etc_loopback(etc, val); break; case ETCDUMP: if (et_msg_level & 0x10000) bcmdumplog((char *)arg, 4096); break; case ETCSETMSGLEVEL: et_msg_level = val; break; case ETCPROMISC: etc_promisc(etc, val); break; case ETCQOS: etc_qos(etc, val); break; case ETCSPEED: if (val == ET_1000FULL) { etc->speed = 1000; etc->duplex = 1; } else if (val == ET_1000HALF) { etc->speed = 1000; etc->duplex = 0; } else if (val == ET_100FULL) { etc->speed = 100; etc->duplex = 1; } else if (val == ET_100HALF) { etc->speed = 100; etc->duplex = 0; } else if (val == ET_10FULL) { etc->speed = 10; etc->duplex = 1; } else if (val == ET_10HALF) { etc->speed = 10; etc->duplex = 0; } else if (val == ET_AUTO) ; else goto err; etc->forcespeed = val; /* explicitly reset the phy */ (*etc->chops->phyreset)(etc->ch, etc->phyaddr); /* request restart autonegotiation if we're reverting to adv mode */ if (etc->forcespeed == ET_AUTO) { etc->advertise = (ADV_100FULL | ADV_100HALF | ADV_10FULL | ADV_10HALF); etc->advertise2 = ADV_1000FULL; etc->needautoneg = TRUE; } else { etc->advertise = etc->advertise2 = 0; etc->needautoneg = FALSE; } et_init(etc->et, ET_INIT_DEF_OPTIONS); break; case ETCPHYRD: if (vec) { vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]); ET_TRACE(("etc_ioctl: ETCPHYRD of reg 0x%x => 0x%x\n", vec[0], vec[1])); } break; case ETCPHYRD2: if (vec) { uint phyaddr, reg; phyaddr = vec[0] >> 16; if (phyaddr < MAXEPHY) { reg = vec[0] & 0xffff; vec[1] = (*etc->chops->phyrd)(etc->ch, phyaddr, reg); ET_TRACE(("etc_ioctl: ETCPHYRD2 of phy 0x%x, reg 0x%x => 0x%x\n", phyaddr, reg, vec[1])); } } break; case ETCPHYWR: if (vec) { ET_TRACE(("etc_ioctl: ETCPHYWR to reg 0x%x <= 0x%x\n", vec[0], vec[1])); (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16)vec[1]); } break; case ETCPHYWR2: if (vec) { uint phyaddr, reg; phyaddr = vec[0] >> 16; if (phyaddr < MAXEPHY) { reg = vec[0] & 0xffff; (*etc->chops->phywr)(etc->ch, phyaddr, reg, (uint16)vec[1]); ET_TRACE(("etc_ioctl: ETCPHYWR2 to phy 0x%x, reg 0x%x <= 0x%x\n", phyaddr, reg, vec[1])); } } break; #ifdef ETROBO case ETCROBORD: if (etc->robo && vec) { uint page, reg; uint16 val; robo_info_t *robo = (robo_info_t *)etc->robo; page = vec[0] >> 16; reg = vec[0] & 0xffff; val = -1; robo->ops->read_reg(etc->robo, page, reg, &val, 2); vec[1] = val; ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n", page, reg, val)); } break; case ETCROBOWR: if (etc->robo && vec) { uint page, reg; uint16 val; robo_info_t *robo = (robo_info_t *)etc->robo; page = vec[0] >> 16; reg = vec[0] & 0xffff; val = vec[1]; robo->ops->write_reg(etc->robo, page, vec[0], &val, 2); ET_TRACE(("etc_ioctl: ETCROBOWR to page 0x%x, reg 0x%x <= 0x%x\n", page, reg, val)); }
static void * chipattach(etc_info_t *etc, void *osh, void *regsva) { struct bcm4xxx *ch; bcmenetregs_t *regs; char name[16]; char *var; uint boardflags, boardtype; ET_TRACE(("et%d: chipattach: regsva 0x%lx\n", etc->unit, (ulong)regsva)); if ((ch = (struct bcm4xxx *)MALLOC(osh, sizeof(struct bcm4xxx))) == NULL) { ET_ERROR(("et%d: chipattach: out of memory, malloced %d bytes\n", etc->unit, MALLOCED(osh))); return (NULL); } bzero((char *)ch, sizeof(struct bcm4xxx)); ch->etc = etc; ch->et = etc->et; ch->osh = osh; /* store the pointer to the sw mib */ etc->mib = (void *)&ch->mib; /* get si handle */ if ((ch->sih = si_attach(etc->deviceid, ch->osh, regsva, PCI_BUS, NULL, &ch->vars, &ch->vars_size)) == NULL) { ET_ERROR(("et%d: chipattach: si_attach error\n", etc->unit)); goto fail; } /* We used to have an assert here like: * si_coreid(ch->sih) == ENET_CORE_ID * but srom-less systems and simulators don't have a way to * provide a default bar0window so we were relying on nvram * variables. At some point we decided that we could do away * with that since the wireless driver was simply doing a * setcore in attach. So we need to do the same here for * the ethernet. */ if ((regs = (bcmenetregs_t *)si_setcore(ch->sih, ENET_CORE_ID, etc->unit)) == NULL) { ET_ERROR(("et%d: chipattach: Could not setcore to the ENET core\n", etc->unit)); goto fail; } ch->regs = regs; etc->chip = ch->sih->chip; etc->chiprev = ch->sih->chiprev; etc->coreid = si_coreid(ch->sih); etc->corerev = si_corerev(ch->sih); etc->nicmode = !(ch->sih->bustype == SI_BUS); etc->coreunit = si_coreunit(ch->sih); etc->boardflags = getintvar(ch->vars, "boardflags"); etc->hwrxoff = HWRXOFF; boardflags = etc->boardflags; boardtype = ch->sih->boardtype; /* Backplane clock ticks per microsecs: used by gptimer, intrecvlazy */ etc->bp_ticks_usec = si_clock(ch->sih) / 1000000; /* get our local ether addr */ sprintf(name, "et%dmacaddr", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } bcm_ether_atoe(var, &etc->perm_etheraddr); if (ETHER_ISNULLADDR(&etc->perm_etheraddr)) { ET_ERROR(("et%d: chipattach: invalid format: %s=%s\n", etc->unit, name, var)); goto fail; } bcopy((char *)&etc->perm_etheraddr, (char *)&etc->cur_etheraddr, ETHER_ADDR_LEN); /* * Too much can go wrong in scanning MDC/MDIO playing "whos my phy?" . * Instead, explicitly require the environment var "et<coreunit>phyaddr=<val>". */ /* get our phyaddr value */ sprintf(name, "et%dphyaddr", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } etc->phyaddr = bcm_atoi(var) & EPHY_MASK; /* nvram says no phy is present */ if (etc->phyaddr == EPHY_NONE) { ET_ERROR(("et%d: chipattach: phy not present\n", etc->unit)); goto fail; } /* get our mdc/mdio port number */ sprintf(name, "et%dmdcport", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } etc->mdcport = bcm_atoi(var); /* configure pci core */ si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih))); /* reset the enet core */ chipreset(ch); /* dma attach */ sprintf(name, "et%d", etc->coreunit); if ((ch->di = dma_attach(osh, name, ch->sih, (void *)®s->dmaregs.xmt, (void *)®s->dmaregs.rcv, NTXD, NRXD, RXBUFSZ, -1, NRXBUFPOST, HWRXOFF, &et_msg_level)) == NULL) { ET_ERROR(("et%d: chipattach: dma_attach failed\n", etc->unit)); goto fail; } etc->txavail[TX_Q0] = (uint *)&ch->di->txavail; /* set default sofware intmask */ ch->intmask = DEF_INTMASK; /* * For the 5222 dual phy shared mdio contortion, our phy is * on someone elses mdio pins. This other enet enet * may not yet be attached so we must defer the et_phyfind(). */ /* if local phy: reset it once now */ if (etc->mdcport == etc->coreunit) chipphyreset(ch, etc->phyaddr); #ifdef ETROBO /* * Broadcom Robo ethernet switch. */ if ((boardflags & BFL_ENETROBO) && (etc->phyaddr == EPHY_NOREG)) { /* Attach to the switch */ if (!(etc->robo = bcm_robo_attach(ch->sih, ch, ch->vars, (miird_f)bcm47xx_et_chops.phyrd, (miiwr_f)bcm47xx_et_chops.phywr))) { ET_ERROR(("et%d: chipattach: robo_attach failed\n", etc->unit)); goto fail; } /* Enable the switch and set it to a known good state */ if (bcm_robo_enable_device(etc->robo)) { ET_ERROR(("et%d: chipattach: robo_enable_device failed\n", etc->unit)); goto fail; } /* Configure the switch to do VLAN */ if ((boardflags & BFL_ENETVLAN) && bcm_robo_config_vlan(etc->robo, etc->perm_etheraddr.octet)) { ET_ERROR(("et%d: chipattach: robo_config_vlan failed\n", etc->unit)); goto fail; } /* Enable switching/forwarding */ if (bcm_robo_enable_switch(etc->robo)) { ET_ERROR(("et%d: chipattach: robo_enable_switch failed\n", etc->unit)); goto fail; } } #endif /* ETROBO */ #ifdef ETADM /* * ADMtek ethernet switch. */ if (boardflags & BFL_ENETADM) { /* Attach to the device */ if (!(ch->adm = adm_attach(ch->sih, ch->vars))) { ET_ERROR(("et%d: chipattach: adm_attach failed\n", etc->unit)); goto fail; } /* Enable the external switch and set it to a known good state */ if (adm_enable_device(ch->adm)) { ET_ERROR(("et%d: chipattach: adm_enable_device failed\n", etc->unit)); goto fail; } /* Configure the switch */ if ((boardflags & BFL_ENETVLAN) && adm_config_vlan(ch->adm)) { ET_ERROR(("et%d: chipattach: adm_config_vlan failed\n", etc->unit)); goto fail; } } #endif /* ETADM */ return ((void *)ch); fail: chipdetach(ch); return (NULL); }
static void chipreset(struct bcm4xxx *ch) { bcmenetregs_t *regs; uint32 clk, mdc; ET_TRACE(("et%d: chipreset\n", ch->etc->unit)); regs = ch->regs; if (!si_iscoreup(ch->sih)) { if (!ch->etc->nicmode) si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih))); /* power on reset: reset the enet core */ si_core_reset(ch->sih, 0, 0); goto chipinreset; } /* read counters before resetting the chip */ if (ch->mibgood) chipstatsupd(ch); /* reset the tx dma engine */ if (ch->di) dma_txreset(ch->di); /* set emac into loopback mode to ensure no rx traffic */ W_REG(ch->osh, ®s->rxconfig, ERC_LE); OSL_DELAY(1); /* reset the rx dma engine */ if (ch->di) dma_rxreset(ch->di); /* reset core */ si_core_reset(ch->sih, 0, 0); chipinreset: /* must clear mib registers by hand */ W_REG(ch->osh, ®s->mibcontrol, EMC_RZ); (void) R_REG(ch->osh, ®s->mib.tx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_len_64); (void) R_REG(ch->osh, ®s->mib.tx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.tx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.tx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.tx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.tx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.tx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.tx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.tx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.tx_underruns); (void) R_REG(ch->osh, ®s->mib.tx_total_cols); (void) R_REG(ch->osh, ®s->mib.tx_single_cols); (void) R_REG(ch->osh, ®s->mib.tx_multiple_cols); (void) R_REG(ch->osh, ®s->mib.tx_excessive_cols); (void) R_REG(ch->osh, ®s->mib.tx_late_cols); (void) R_REG(ch->osh, ®s->mib.tx_defered); (void) R_REG(ch->osh, ®s->mib.tx_carrier_lost); (void) R_REG(ch->osh, ®s->mib.tx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_len_64); (void) R_REG(ch->osh, ®s->mib.rx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.rx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.rx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.rx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.rx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.rx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.rx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.rx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.rx_missed_pkts); (void) R_REG(ch->osh, ®s->mib.rx_crc_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_undersize); (void) R_REG(ch->osh, ®s->mib.rx_crc_errs); (void) R_REG(ch->osh, ®s->mib.rx_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_symbol_errs); (void) R_REG(ch->osh, ®s->mib.rx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_nonpause_pkts); ch->mibgood = TRUE; /* * We want the phy registers to be accessible even when * the driver is "downed" so initialize MDC preamble, frequency, * and whether internal or external phy here. */ /* default: 100Mhz SI clock and external phy */ W_REG(ch->osh, ®s->mdiocontrol, 0x94); if (ch->etc->deviceid == BCM47XX_ENET_ID) { /* 47xx chips: find out the clock */ if ((clk = si_clock(ch->sih)) != 0) { mdc = 0x80 | ((clk + (MDC_RATIO / 2)) / MDC_RATIO); W_REG(ch->osh, ®s->mdiocontrol, mdc); } else { ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, " "using 100Mhz\n", ch->etc->unit)); } } /* some chips have internal phy, some don't */ if (!(R_REG(ch->osh, ®s->devcontrol) & DC_IP)) { W_REG(ch->osh, ®s->enetcontrol, EC_EP); } else if (R_REG(ch->osh, ®s->devcontrol) & DC_ER) { AND_REG(ch->osh, ®s->devcontrol, ~DC_ER); OSL_DELAY(100); chipphyinit(ch, ch->etc->phyaddr); } /* clear persistent sw intstatus */ ch->intstatus = 0; }
/* * Initialize all the chip registers. If dma mode, init tx and rx dma engines * but leave the devcontrol tx and rx (fifos) disabled. */ static void chipinit(struct bcm4xxx *ch, uint options) { etc_info_t *etc; bcmenetregs_t *regs; uint idx; uint i; regs = ch->regs; etc = ch->etc; idx = 0; ET_TRACE(("et%d: chipinit\n", etc->unit)); /* enable crc32 generation */ OR_REG(ch->osh, ®s->emaccontrol, EMC_CG); /* enable one rx interrupt per received frame */ W_REG(ch->osh, ®s->intrecvlazy, (1 << IRL_FC_SHIFT)); /* enable 802.3x tx flow control (honor received PAUSE frames) */ W_REG(ch->osh, ®s->rxconfig, ERC_FE | ERC_UF); /* initialize CAM */ if (etc->promisc || (R_REG(ch->osh, ®s->rxconfig) & ERC_CA)) OR_REG(ch->osh, ®s->rxconfig, ERC_PE); else { /* our local address */ chipwrcam(ch, &etc->cur_etheraddr, idx++); /* allmulti or a list of discrete multicast addresses */ if (etc->allmulti) OR_REG(ch->osh, ®s->rxconfig, ERC_AM); else if (etc->nmulticast) { for (i = 0; i < etc->nmulticast; i++) chipwrcam(ch, &etc->multicast[i], idx++); } /* enable cam */ OR_REG(ch->osh, ®s->camcontrol, CC_CE); } /* optionally enable mac-level loopback */ if (etc->loopbk) OR_REG(ch->osh, ®s->rxconfig, ERC_LE); /* set max frame lengths - account for possible vlan tag */ W_REG(ch->osh, ®s->rxmaxlength, ETHER_MAX_LEN + 32); W_REG(ch->osh, ®s->txmaxlength, ETHER_MAX_LEN + 32); /* set tx watermark */ W_REG(ch->osh, ®s->txwatermark, 56); /* * Optionally, disable phy autonegotiation and force our speed/duplex * or constrain our advertised capabilities. */ if (etc->forcespeed != ET_AUTO) chipphyforce(ch, etc->phyaddr); else if (etc->advertise && etc->needautoneg) chipphyadvertise(ch, etc->phyaddr); if (options & ET_INIT_FULL) { /* initialize the tx and rx dma channels */ dma_txinit(ch->di); dma_rxinit(ch->di); /* post dma receive buffers */ dma_rxfill(ch->di); /* lastly, enable interrupts */ if (options & ET_INIT_INTRON) et_intrson(etc->et); } else dma_rxenable(ch->di); /* turn on the emac */ OR_REG(ch->osh, ®s->enetcontrol, EC_EE); }