/* $NetBSD: if_qe.c,v 1.1 1998/03/11 22:13:55 ragge Exp $ */ /* * Copyright (c) 1998 Roar Thronęs. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Roar Thronęs. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Standalone routine for the DEQNA. */ #include #include #include #include #include #include int qe_probe(), qe_match(), qe_get(), qe_put(); void qe_init(); struct netif_stats qe_stats; struct netif_dif qe_ifs[] = { /* dif_unit dif_nsel dif_stats dif_private */ { 0, 1, &qe_stats, }, }; struct netif_stats qe_stats; struct netif_driver qe_driver = { "qe", qe_match, qe_probe, qe_init, qe_get, qe_put, 0, qe_ifs, 1, }; #define NRCV 1 /* Receive descriptors */ #define NXMT 1 /* Transmit descriptors */ #define NTOT (NXMT + NRCV) struct qe_softc { struct qe_ring *rringaddr; /* mapping info for rings */ struct qe_ring *tringaddr; /* "" */ struct qe_ring rring[NRCV+1]; /* Receive ring descriptors */ struct qe_ring tring[NXMT+1]; /* Xmit ring descriptors */ u_char setup_pkt[16][8]; /* Setup packet */ }; static char *qein,*qeout; static volatile struct qe_softc *sc; static volatile struct qedevice *addr; int qe_match(nif, machdep_hint) struct netif *nif; void *machdep_hint; { return strcmp(machdep_hint, "qe") == 0; } int qe_probe(nif, machdep_hint) struct netif *nif; void *machdep_hint; { return 0; } void qe_init(desc, machdep_hint) struct iodesc *desc; void *machdep_hint; { int i,j; struct qe_ring *rp, *prp; qein=(void*)0x1000; qeout=(void*)0x1800; sc=(void*)0x2000; bzero(qein,2048); bzero(qeout,2048); bzero(sc,sizeof(struct qe_softc)); /* XXX hardcoded addr */ addr = (struct qedevice *)(0x20000000 + (0774440 & 017777)); addr->qe_csr = QE_RESET; addr->qe_csr &= ~QE_RESET; sc->rringaddr = (void *)sc->rring; sc->tringaddr = (void *)sc->tring; prp = (struct qe_ring *)sc->rringaddr; bzero((caddr_t)sc->tring, sizeof(struct qe_ring)); sc->tring->qe_buf_len = -64; sc->tring->qe_addr_lo = (int)sc->setup_pkt; sc->tring->qe_addr_hi = 0; bzero((caddr_t)sc->rring, sizeof(struct qe_ring)); sc->rring->qe_buf_len = -64; sc->rring->qe_addr_lo = (int)sc->setup_pkt; sc->rring->qe_addr_hi = 0; rp = (struct qe_ring *)sc->tring; rp->qe_setup = 1; rp->qe_eomsg = 1; rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_valid = 1; rp = (struct qe_ring *)&sc->tring[1]; rp->qe_flag = rp->qe_status1 = 0; rp->qe_valid = 0; rp->qe_addr_lo = 0; rp->qe_addr_hi = 0; rp = (struct qe_ring *)sc->rring; rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_valid = 1; rp = (struct qe_ring *)&sc->rring[1]; rp->qe_flag = rp->qe_status1 = 0; rp->qe_valid = 0; rp->qe_addr_lo = 0; rp->qe_addr_hi = 0; for (i = 0; i < 6; i++) { sc->setup_pkt[i][1] = addr->qe_sta_addr[i]; sc->setup_pkt[i+8][1] = addr->qe_sta_addr[i]; sc->setup_pkt[i][2] = 0xff; sc->setup_pkt[i+8][2] = addr->qe_sta_addr[i]; for (j=3; j < 8; j++) { sc->setup_pkt[i][j] = addr->qe_sta_addr[i]; sc->setup_pkt[i+8][j] = addr->qe_sta_addr[i]; } desc->myea[i] = addr->qe_sta_addr[i]; } addr->qe_csr = QE_XMIT_INT | QE_RCV_INT; addr->qe_rcvlist_lo = (short)((int)prp); addr->qe_rcvlist_hi = (short)((int)prp >> 16); prp += NRCV+1; addr->qe_xmtlist_lo = (short)((int)prp); addr->qe_xmtlist_hi = (short)((int)prp >> 16); while ((addr->qe_csr & 0x8080) != 0x8080) ; addr->qe_csr |= 0x8080; addr->qe_csr &= ~(QE_INT_ENABLE|QE_ELOOP); addr->qe_csr |= QE_ILOOP; sc->rring[0].qe_addr_lo = (short)((int)qein); sc->rring[0].qe_addr_hi = (short)((int)qein >> 16); sc->rring[0].qe_setup=0; sc->rring[0].qe_buf_len=-750; sc->rring[0].qe_valid=1; sc->rring[0].qe_flag=sc->rring[0].qe_status1=QE_NOTYET; sc->rring[0].qe_status2=1; sc->rring[1].qe_valid=0; sc->rring[1].qe_addr_lo = 0; sc->rring[1].qe_addr_hi = 0; sc->rring[1].qe_flag=sc->rring[1].qe_status1=QE_NOTYET; sc->rring[1].qe_status2=1; sc->tring[0].qe_addr_lo = (short)((int)qeout); sc->tring[0].qe_addr_hi = (short)((int)qeout >> 16); sc->tring[0].qe_setup=0; sc->tring[0].qe_buf_len=0; sc->tring[0].qe_eomsg=1; sc->tring[0].qe_flag=sc->tring[0].qe_status1=QE_NOTYET; sc->tring[0].qe_valid=1; sc->tring[1].qe_flag=sc->tring[1].qe_status1=QE_NOTYET; sc->tring[1].qe_valid=0; sc->tring[1].qe_addr_lo = 0; sc->tring[1].qe_addr_hi = 0; addr->qe_csr|=QE_RCV_ENABLE; addr->qe_rcvlist_lo = (short)((int)sc->rring); addr->qe_rcvlist_hi = (short)((int)sc->rring >> 16); return; } int qe_get(desc, pkt, maxlen, timeout) struct iodesc *desc; void *pkt; int maxlen; time_t timeout; { int len, j; retry: for(j = 0x10000;j && (addr->qe_csr & QE_RCV_INT) == 0; j--) ; if ((addr->qe_csr & QE_RCV_INT) == 0) goto fail; addr->qe_csr &= ~(QE_RCV_ENABLE|QE_XMIT_INT); len= ((sc->rring[0].qe_status1 & QE_RBL_HI) | (sc->rring[0].qe_status2 & QE_RBL_LO)) + 60; if (sc->rring[0].qe_status1 & 0xc000) goto fail; if (len == 0) goto retry; bcopy((void*)qein,pkt,len); end: sc->rring[0].qe_flag = sc->rring[1].qe_flag = 0; sc->rring[0].qe_status2 = sc->rring[1].qe_status2 = 1; sc->rring[0].qe_flag=sc->rring[0].qe_status1=QE_NOTYET; sc->rring[1].qe_flag=sc->rring[1].qe_status1=QE_NOTYET; addr->qe_csr |= QE_RCV_ENABLE; addr->qe_rcvlist_lo = (short)((int)sc->rring); addr->qe_rcvlist_hi = (short)((int)sc->rring >> 16); return len; fail: len = -1; goto end; } int qe_put(desc, pkt, len) struct iodesc *desc; void *pkt; int len; { int j; bcopy(pkt,qeout,len); sc->tring[0].qe_buf_len=-len/2; sc->tring[0].qe_flag=0; sc->tring[0].qe_flag=sc->tring[0].qe_status1=QE_NOTYET; sc->tring[1].qe_flag=sc->tring[1].qe_status1=QE_NOTYET; addr->qe_xmtlist_lo = (short)((int)sc->tring); addr->qe_xmtlist_hi = (short)((int)sc->tring >> 16); for(j = 0; (j < 0x10000) && ((addr->qe_csr & QE_XMIT_INT) == 0); j++) ; if ((addr->qe_csr & QE_XMIT_INT) == 0) { qe_init(desc,0); return -1; } addr->qe_csr &= ~QE_RCV_INT; if (sc->tring[0].qe_status1 & 0xc000) { qe_init(desc,0); return -1; } return len; }