/* * Initialization of interface; reinitialize UNIBUS usage. */ int dmcinit(struct ifnet *ifp) { struct dmc_softc *sc = ifp->if_softc; struct ifrw *ifrw; struct ifxmt *ifxp; struct dmcbufs *rp; struct dmc_command *qp; struct ifaddr *ifa; cfdata_t ui = device_cfdata(sc->sc_dev); int base; int s; /* * Check to see that an address has been set * (both local and destination for an address family). */ IFADDR_FOREACH(ifa, ifp) if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family) break; if (ifa == (struct ifaddr *) 0) return 0; if ((DMC_RBYTE(DMC_BSEL1) & DMC_RUN) == 0) { printf("dmcinit: DMC not running\n"); ifp->if_flags &= ~IFF_UP; return 0; } /* map base table */ if ((sc->sc_flag & DMC_BMAPPED) == 0) { sc->sc_ui.ui_size = sizeof(struct dmc_base); sc->sc_ui.ui_vaddr = (void *)&sc->dmc_base; uballoc(device_private(device_parent(sc->sc_dev)), &sc->sc_ui, 0); sc->sc_flag |= DMC_BMAPPED; } /* initialize UNIBUS resources */ sc->sc_iused = sc->sc_oused = 0; if ((ifp->if_flags & IFF_RUNNING) == 0) { if (if_ubaminit(&sc->sc_ifuba, device_private(device_parent(sc->sc_dev)), sizeof(struct dmc_header) + DMCMTU, sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { aprint_error_dev(sc->sc_dev, "can't allocate uba resources\n"); ifp->if_flags &= ~IFF_UP; return 0; } ifp->if_flags |= IFF_RUNNING; } sc->sc_flag &= ~DMC_ONLINE; sc->sc_flag |= DMC_RUNNING; /* * Limit packets enqueued until we see if we're on the air. */ ifp->if_snd.ifq_maxlen = 3; /* initialize buffer pool */ /* receives */ ifrw = &sc->sc_ifr[0]; for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { rp->ubinfo = ifrw->ifrw_info; rp->cc = DMCMTU + sizeof (struct dmc_header); rp->flags = DBUF_OURS|DBUF_RCV; ifrw++; } /* transmits */ ifxp = &sc->sc_ifw[0]; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { rp->ubinfo = ifxp->ifw_info; rp->cc = 0; rp->flags = DBUF_OURS|DBUF_XMIT; ifxp++; } /* set up command queues */ sc->sc_qfreeh = sc->sc_qfreet = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = (struct dmc_command *)0; /* set up free command buffer list */ for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); } /* base in */ base = sc->sc_ui.ui_baddr; dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM); /* specify half duplex operation, flags tell if primary */ /* or secondary station */ if (ui->cf_flags == 0) /* use DDCMP mode in full duplex */ dmcload(sc, DMC_CNTLI, 0, 0); else if (ui->cf_flags == 1) /* use MAINTENENCE mode */ dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); else if (ui->cf_flags == 2) /* use DDCMP half duplex as primary station */ dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); else if (ui->cf_flags == 3) /* use DDCMP half duplex as secondary station */ dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); /* enable operation done interrupts */ while ((DMC_RBYTE(DMC_BSEL2) & DMC_IEO) == 0) DMC_WBYTE(DMC_BSEL2, DMC_RBYTE(DMC_BSEL2) | DMC_IEO); s = splnet(); /* queue first NRCV buffers for DMC to fill */ for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { rp->flags |= DBUF_DMCS; dmcload(sc, DMC_READ, rp->ubinfo, (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); sc->sc_iused++; } splx(s); return 0; }
/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */ int deinit(struct ifnet *ifp) { struct de_softc *sc = ifp->if_softc; struct de_cdata *dc, *pdc; struct ifrw *ifrw; struct ifxmt *ifxp; struct de_ring *rp; int s, error; if (ifp->if_flags & IFF_RUNNING) return 0; if ((sc->sc_flags & DSF_MAPPED) == 0) { if (if_ubaminit(&sc->sc_ifuba, (void *)sc->sc_dev.dv_parent, MCLBYTES, sc->sc_ifr, NRCV, sc->sc_ifw, NXMT)) { printf("%s: can't initialize\n", sc->sc_dev.dv_xname); ifp->if_flags &= ~IFF_UP; return 0; } sc->sc_ui.ui_size = sizeof(struct de_cdata); if ((error = ubmemalloc((void *)sc->sc_dev.dv_parent, &sc->sc_ui, 0))) { printf(": unable to ubmemalloc(), error = %d\n", error); return 0; } sc->sc_pdedata = (struct de_cdata *)sc->sc_ui.ui_baddr; sc->sc_dedata = (struct de_cdata *)sc->sc_ui.ui_vaddr; sc->sc_flags |= DSF_MAPPED; } /* * Tell the DEUNA about our PCB */ DE_WCSR(DE_PCSR2, LOWORD(sc->sc_pdedata)); DE_WCSR(DE_PCSR3, HIWORD(sc->sc_pdedata)); DE_WLOW(0); /* reset INTE */ DELAY(500); DE_WLOW(CMD_GETPCBB); dewait(sc, "pcbb"); dc = sc->sc_dedata; pdc = sc->sc_pdedata; /* set the transmit and receive ring header addresses */ dc->dc_pcbb.pcbb0 = FC_WTRING; dc->dc_pcbb.pcbb2 = LOWORD(&pdc->dc_udbbuf); dc->dc_pcbb.pcbb4 = HIWORD(&pdc->dc_udbbuf); dc->dc_udbbuf.b_tdrbl = LOWORD(&pdc->dc_xrent[0]); dc->dc_udbbuf.b_tdrbh = HIWORD(&pdc->dc_xrent[0]); dc->dc_udbbuf.b_telen = sizeof (struct de_ring) / sizeof(u_int16_t); dc->dc_udbbuf.b_trlen = NXMT; dc->dc_udbbuf.b_rdrbl = LOWORD(&pdc->dc_rrent[0]); dc->dc_udbbuf.b_rdrbh = HIWORD(&pdc->dc_rrent[0]); dc->dc_udbbuf.b_relen = sizeof (struct de_ring) / sizeof(u_int16_t); dc->dc_udbbuf.b_rrlen = NRCV; DE_WLOW(CMD_GETCMD); dewait(sc, "wtring"); sc->sc_dedata->dc_pcbb.pcbb0 = FC_WTMODE; sc->sc_dedata->dc_pcbb.pcbb2 = MOD_TPAD|MOD_HDX|MOD_DRDC|MOD_ENAL; DE_WLOW(CMD_GETCMD); dewait(sc, "wtmode"); /* set up the receive and transmit ring entries */ ifxp = &sc->sc_ifw[0]; for (rp = &dc->dc_xrent[0]; rp < &dc->dc_xrent[NXMT]; rp++) { rp->r_segbl = LOWORD(ifxp->ifw_info); rp->r_segbh = HIWORD(ifxp->ifw_info); rp->r_flags = 0; ifxp++; } ifrw = &sc->sc_ifr[0]; for (rp = &dc->dc_rrent[0]; rp < &dc->dc_rrent[NRCV]; rp++) { rp->r_slen = MCLBYTES - 2; rp->r_segbl = LOWORD(ifrw->ifrw_info); rp->r_segbh = HIWORD(ifrw->ifrw_info); rp->r_flags = RFLG_OWN; ifrw++; } /* start up the board (rah rah) */ s = splnet(); sc->sc_rindex = sc->sc_xindex = sc->sc_xfree = sc->sc_nxmit = 0; sc->sc_if.if_flags |= IFF_RUNNING; DE_WLOW(PCSR0_INTE); /* avoid interlock */ destart(&sc->sc_if); /* queue output packets */ DE_WLOW(CMD_START|PCSR0_INTE); splx(s); return 0; }