/* * Initialization of interface. */ void qeinit(struct qe_softc *sc) { struct ifnet *ifp = (struct ifnet *)&sc->sc_if; struct qe_cdata *qc = sc->sc_qedata; int i; /* * Reset the interface. */ QE_WCSR(QE_CSR_CSR, QE_RESET); DELAY(1000); QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET); QE_WCSR(QE_CSR_VECTOR, sc->sc_intvec); sc->sc_nexttx = sc->sc_inq = sc->sc_lastack = 0; /* * Release and init transmit descriptors. */ for (i = 0; i < TXDESCS; i++) { if (sc->sc_txmbuf[i]) { bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[i]); m_freem(sc->sc_txmbuf[i]); sc->sc_txmbuf[i] = 0; } qc->qc_xmit[i].qe_addr_hi = 0; /* Clear valid bit */ qc->qc_xmit[i].qe_status1 = qc->qc_xmit[i].qe_flag = QE_NOTYET; } /* * Init receive descriptors. */ for (i = 0; i < RXDESCS; i++) qc->qc_recv[i].qe_status1 = qc->qc_recv[i].qe_flag = QE_NOTYET; sc->sc_nextrx = 0; /* * Write the descriptor addresses to the device. * Receiving packets will be enabled in the interrupt routine. */ QE_WCSR(QE_CSR_CSR, QE_INT_ENABLE|QE_XMIT_INT|QE_RCV_INT); QE_WCSR(QE_CSR_RCLL, LOWORD(sc->sc_pqedata->qc_recv)); QE_WCSR(QE_CSR_RCLH, HIWORD(sc->sc_pqedata->qc_recv)); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* * Send a setup frame. * This will start the transmit machinery as well. */ qe_setup(sc); }
/* * Start output on interface. */ void qestart(struct ifnet *ifp) { struct qe_softc *sc = ifp->if_softc; struct qe_cdata *qc = sc->sc_qedata; paddr_t buffer; struct mbuf *m, *m0; int idx, len, s, i, totlen, buflen; short orword, csr; if ((QE_RCSR(QE_CSR_CSR) & QE_RCV_ENABLE) == 0) return; s = splnet(); while (sc->sc_inq < (TXDESCS - 1)) { if (sc->sc_setup) { qe_setup(sc); continue; } idx = sc->sc_nexttx; IFQ_POLL(&ifp->if_snd, m); if (m == 0) goto out; /* * Count number of mbufs in chain. * Always do DMA directly from mbufs, therefore the transmit * ring is really big. */ for (m0 = m, i = 0; m0; m0 = m0->m_next) if (m0->m_len) i++; if (m->m_pkthdr.len < ETHER_PAD_LEN) { buflen = ETHER_PAD_LEN; i++; } else buflen = m->m_pkthdr.len; if (i >= TXDESCS) panic("qestart"); if ((i + sc->sc_inq) >= (TXDESCS - 1)) { ifp->if_flags |= IFF_OACTIVE; goto out; } IFQ_DEQUEUE(&ifp->if_snd, m); bpf_mtap(ifp, m); /* * m now points to a mbuf chain that can be loaded. * Loop around and set it. */ totlen = 0; for (m0 = m; ; m0 = m0->m_next) { if (m0) { if (m0->m_len == 0) continue; bus_dmamap_load(sc->sc_dmat, sc->sc_xmtmap[idx], mtod(m0, void *), m0->m_len, 0, 0); buffer = sc->sc_xmtmap[idx]->dm_segs[0].ds_addr; len = m0->m_len; } else if (totlen < ETHER_PAD_LEN) { buffer = sc->sc_nulldmamap->dm_segs[0].ds_addr; len = ETHER_PAD_LEN - totlen; } else { break; } totlen += len; /* Word alignment calc */ orword = 0; if (totlen == buflen) { orword |= QE_EOMSG; sc->sc_txmbuf[idx] = m; } if ((buffer & 1) || (len & 1)) len += 2; if (buffer & 1) orword |= QE_ODDBEGIN; if ((buffer + len) & 1) orword |= QE_ODDEND; qc->qc_xmit[idx].qe_buf_len = -(len/2); qc->qc_xmit[idx].qe_addr_lo = LOWORD(buffer); qc->qc_xmit[idx].qe_addr_hi = HIWORD(buffer); qc->qc_xmit[idx].qe_flag = qc->qc_xmit[idx].qe_status1 = QE_NOTYET; qc->qc_xmit[idx].qe_addr_hi |= (QE_VALID | orword); if (++idx == TXDESCS) idx = 0; sc->sc_inq++; if (m0 == NULL) break; } #ifdef DIAGNOSTIC if (totlen != buflen) panic("qestart: len fault"); #endif /* * Kick off the transmit logic, if it is stopped. */ csr = QE_RCSR(QE_CSR_CSR); if (csr & QE_XL_INVALID) { QE_WCSR(QE_CSR_XMTL, LOWORD(&sc->sc_pqedata->qc_xmit[sc->sc_nexttx])); QE_WCSR(QE_CSR_XMTH, HIWORD(&sc->sc_pqedata->qc_xmit[sc->sc_nexttx])); } sc->sc_nexttx = idx; }
/* * Process an ioctl request. */ int qeioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct qe_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; int s, error = 0; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch(ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: qeinit(sc); arp_ifinit(&sc->sc_ac, ifa); break; #endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && (ifp->if_flags & IFF_RUNNING) != 0) { /* * If interface is marked down and it is running, * stop it. (by disabling receive mechanism). */ QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RCV_ENABLE); ifp->if_flags &= ~IFF_RUNNING; } else if ((ifp->if_flags & IFF_UP) != 0 && (ifp->if_flags & IFF_RUNNING) == 0) { /* * If interface it marked up and it is stopped, then * start it. */ qeinit(sc); } else if ((ifp->if_flags & IFF_UP) != 0) { /* * Send a new setup packet to match any new changes. * (Like IFF_PROMISC etc) */ qe_setup(sc); } break; default: error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); } if (error == ENETRESET) { if (ifp->if_flags & IFF_RUNNING) qe_setup(sc); error = 0; } splx(s); return (error); }