/* Set up data to get the interface up and running. */ int sq_init(struct ifnet *ifp) { int i; u_int32_t reg; struct sq_softc *sc = ifp->if_softc; /* Cancel any in-progress I/O */ sq_stop(ifp, 0); sc->sc_nextrx = 0; sc->sc_nfreetx = SQ_NTXDESC; sc->sc_nexttx = sc->sc_prevtx = 0; SQ_TRACE(SQ_RESET, 0, 0, sc->sc_nfreetx); /* Set into 8003 mode, bank 0 to program ethernet address */ bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCMD, TXCMD_BANK0); /* Now write the address */ for (i = 0; i < ETHER_ADDR_LEN; i++) bus_space_write_1(sc->sc_regt, sc->sc_regh, i, sc->sc_enaddr[i]); sc->sc_rxcmd = RXCMD_IE_CRC | RXCMD_IE_DRIB | RXCMD_IE_SHORT | RXCMD_IE_END | RXCMD_IE_GOOD; /* * Set the receive filter -- this will add some bits to the * prototype RXCMD register. Do this before setting the * transmit config register, since we might need to switch * banks. */ sq_set_filter(sc); /* Set up Seeq transmit command register */ bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCMD, TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD); /* Now write the receive command register. */ bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_RXCMD, sc->sc_rxcmd); /* Set up HPC ethernet DMA config */ reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG); bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG, reg | ENETR_DMACFG_FIX_RXDC | ENETR_DMACFG_FIX_INTR | ENETR_DMACFG_FIX_EOP); /* Pass the start of the receive ring to the HPC */ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_NDBP, SQ_CDRXADDR(sc, 0)); /* And turn on the HPC ethernet receive channel */ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, ENETR_CTL_ACTIVE); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; return 0; }
static int sq_rxintr(struct sq_softc *sc) { int count = 0; struct mbuf* m; int i, framelen; u_int8_t pktstat; u_int32_t status; int new_end, orig_end; struct ifnet *ifp = &sc->sc_ethercom.ec_if; for(i = sc->sc_nextrx;; i = SQ_NEXTRX(i)) { SQ_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* If this is a CPU-owned buffer, we're at the end of the list */ if (sc->sc_rxdesc[i].hdd_ctl & HDD_CTL_OWN) { #if 0 u_int32_t reg; reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL); printf("%s: rxintr: done at %d (ctl %08x)\n", sc->sc_dev.dv_xname, i, reg); #endif break; } count++; m = sc->sc_rxmbuf[i]; framelen = m->m_ext.ext_size - HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hdd_ctl) - 3; /* Now sync the actual packet data */ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_POSTREAD); pktstat = *((u_int8_t*)m->m_data + framelen + 2); if ((pktstat & RXSTAT_GOOD) == 0) { ifp->if_ierrors++; if (pktstat & RXSTAT_OFLOW) printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname); bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD); SQ_INIT_RXDESC(sc, i); continue; } if (sq_add_rxbuf(sc, i) != 0) { ifp->if_ierrors++; bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD); SQ_INIT_RXDESC(sc, i); continue; } m->m_data += 2; m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = framelen; ifp->if_ipackets++; #if 0 printf("%s: sq_rxintr: buf %d len %d\n", sc->sc_dev.dv_xname, i, framelen); #endif #if NBPFILTER > 0 if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m); #endif (*ifp->if_input)(ifp, m); } /* If anything happened, move ring start/end pointers to new spot */ if (i != sc->sc_nextrx) { new_end = SQ_PREVRX(i); sc->sc_rxdesc[new_end].hdd_ctl |= HDD_CTL_EOCHAIN; SQ_CDRXSYNC(sc, new_end, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); orig_end = SQ_PREVRX(sc->sc_nextrx); sc->sc_rxdesc[orig_end].hdd_ctl &= ~HDD_CTL_EOCHAIN; SQ_CDRXSYNC(sc, orig_end, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); sc->sc_nextrx = i; } status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL); /* If receive channel is stopped, restart it... */ if ((status & ENETR_CTL_ACTIVE) == 0) { /* Pass the start of the receive ring to the HPC */ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_NDBP, SQ_CDRXADDR(sc, sc->sc_nextrx)); /* And turn on the HPC ethernet receive channel */ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, ENETR_CTL_ACTIVE); } return count; }
/* Set up data to get the interface up and running. */ int sq_init(struct ifnet *ifp) { int i; struct sq_softc *sc = ifp->if_softc; /* Cancel any in-progress I/O */ sq_stop(ifp, 0); sc->sc_nextrx = 0; sc->sc_nfreetx = SQ_NTXDESC; sc->sc_nexttx = sc->sc_prevtx = 0; SQ_TRACE(SQ_RESET, sc, 0, 0); /* Set into 8003 mode, bank 0 to program ethernet address */ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0); /* Now write the address */ for (i = 0; i < ETHER_ADDR_LEN; i++) sq_seeq_write(sc, i, sc->sc_enaddr[i]); sc->sc_rxcmd = RXCMD_IE_CRC | RXCMD_IE_DRIB | RXCMD_IE_SHORT | RXCMD_IE_END | RXCMD_IE_GOOD; /* * Set the receive filter -- this will add some bits to the * prototype RXCMD register. Do this before setting the * transmit config register, since we might need to switch * banks. */ sq_set_filter(sc); /* Set up Seeq transmit command register */ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD); /* Now write the receive command register. */ sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd); /* * Set up HPC ethernet PIO and DMA configurations. * * The PROM appears to do most of this for the onboard HPC3, but * not for the Challenge S's IOPLUS chip. We copy how the onboard * chip is configured and assume that it's correct for both. */ if (sc->hpc_regs->revision == 3) { uint32_t dmareg, pioreg; pioreg = HPC3_ENETR_PIOCFG_P1(1) | HPC3_ENETR_PIOCFG_P2(6) | HPC3_ENETR_PIOCFG_P3(1); dmareg = HPC3_ENETR_DMACFG_D1(6) | HPC3_ENETR_DMACFG_D2(2) | HPC3_ENETR_DMACFG_D3(0) | HPC3_ENETR_DMACFG_FIX_RXDC | HPC3_ENETR_DMACFG_FIX_INTR | HPC3_ENETR_DMACFG_FIX_EOP | HPC3_ENETR_DMACFG_TIMEOUT; sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg); sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg); } /* Pass the start of the receive ring to the HPC */ sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, 0)); /* And turn on the HPC ethernet receive channel */ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, sc->hpc_regs->enetr_ctl_active); /* * Turn off delayed receive interrupts on HPC1. * (see Hollywood HPC Specification 2.1.4.3) */ if (sc->hpc_regs->revision != 3) sq_hpc_write(sc, HPC1_ENET_INTDELAY, HPC1_ENET_INTDELAY_OFF); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; return 0; }