/* * Create setup packet and put in queue for sending. */ void ni_setup(struct ni_softc *sc) { struct ifnet *ifp = &sc->sc_if; struct ni_msg *msg; struct ni_ptdb *ptdb; struct ether_multi *enm; struct ether_multistep step; int i, res; msg = REMQHI(&fqb->nf_mforw); if ((int)msg == Q_EMPTY) return; /* What to do? */ ptdb = (struct ni_ptdb *)&msg->nm_text[0]; memset(ptdb, 0, sizeof(struct ni_ptdb)); msg->nm_opcode = BVP_MSG; msg->nm_len = 18; ptdb->np_index = 2; /* definition type index */ ptdb->np_fque = 2; /* Free queue */ if (ifp->if_flags & IFF_RUNNING) { msg->nm_opcode2 = NI_STPTDB; ptdb->np_type = ETHERTYPE_IP; ptdb->np_flags = PTDB_UNKN|PTDB_BDC; if (ifp->if_flags & IFF_PROMISC) ptdb->np_flags |= PTDB_PROMISC; memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); /* Broadcast */ ptdb->np_adrlen = 1; msg->nm_len += 8; ifp->if_flags &= ~IFF_ALLMULTI; if ((ifp->if_flags & IFF_PROMISC) == 0) { ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); i = 1; while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) { ifp->if_flags |= IFF_ALLMULTI; ptdb->np_flags |= PTDB_AMC; break; } msg->nm_len += 8; ptdb->np_adrlen++; memcpy(ptdb->np_mcast[i++], enm->enm_addrlo, ETHER_ADDR_LEN); ETHER_NEXT_MULTI(step, enm); } } } else msg->nm_opcode2 = NI_CLPTDB; res = INSQTI(msg, &gvp->nc_forw0); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); } }
void niintr(void *arg) { struct ni_softc *sc = arg; struct ni_dg *data; struct ni_msg *msg; struct ifnet *ifp = &sc->sc_if; struct ni_bbd *bd; struct mbuf *m; int idx, res; if ((NI_RREG(NI_PSR) & PSR_STATE) != PSR_ENABLED) return; if ((NI_RREG(NI_PSR) & PSR_ERR)) printf("%s: PSR %x\n", device_xname(sc->sc_dev), NI_RREG(NI_PSR)); KERNEL_LOCK(1, NULL); /* Got any response packets? */ while ((NI_RREG(NI_PSR) & PSR_RSQ) && (data = REMQHI(&gvp->nc_forwr))) { switch (data->nd_opcode) { case BVP_DGRAMRX: /* Receive datagram */ idx = data->bufs[0]._index; bd = &bbd[idx]; m = (void *)data->nd_cmdref; m->m_pkthdr.len = m->m_len = data->bufs[0]._len - ETHER_CRC_LEN; m->m_pkthdr.rcvif = ifp; if (ni_add_rxbuf(sc, data, idx)) { bd->nb_len = (m->m_ext.ext_size - 2); bd->nb_pte = (long)kvtopte(m->m_ext.ext_buf); bd->nb_status = 2 | NIBD_VALID; bd->nb_key = 1; } data->nd_len = RXADD; data->nd_status = 0; res = INSQTI(data, &fqb->nf_rforw); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN); } if (m == (void *)data->nd_cmdref) break; /* Out of mbufs */ bpf_mtap(ifp, m); (*ifp->if_input)(ifp, m); break; case BVP_DGRAM: m = (struct mbuf *)data->nd_cmdref; ifp->if_flags &= ~IFF_OACTIVE; m_freem(m); res = INSQTI(data, &fqb->nf_dforw); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN); } break; case BVP_MSGRX: msg = (struct ni_msg *)data; switch (msg->nm_opcode2) { case NI_WPARAM: memcpy(sc->sc_enaddr, ((struct ni_param *)&msg->nm_text[0])->np_dpa, ETHER_ADDR_LEN); endwait = 1; break; case NI_RCCNTR: case NI_CLPTDB: case NI_STPTDB: break; default: printf("Unkn resp %d\n", msg->nm_opcode2); break; } res = INSQTI(data, &fqb->nf_mforw); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); } break; default: printf("Unknown opcode %d\n", data->nd_opcode); res = INSQTI(data, &fqb->nf_mforw); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); } } } /* Try to kick on the start routine again */ nistart(ifp); NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ)); KERNEL_UNLOCK_ONE(NULL); }
/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */ static void niattach(device_t parent, device_t self, void *aux) { struct bi_attach_args *ba = aux; struct ni_softc *sc = device_private(self); struct ifnet *ifp = (struct ifnet *)&sc->sc_if; struct ni_msg *msg; struct ni_ptdb *ptdb; void *va; int i, j, s, res; u_short type; sc->sc_dev = self; type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE); printf(": DEBN%c\n", type == BIDT_DEBNA ? 'A' : type == BIDT_DEBNT ? 'T' : 'K'); sc->sc_iot = ba->ba_iot; sc->sc_ioh = ba->ba_ioh; sc->sc_dmat = ba->ba_dmat; bi_intr_establish(ba->ba_icookie, ba->ba_ivec, niintr, sc, &sc->sc_intrcnt); evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, device_xname(self), "intr"); ni_getpgs(sc, sizeof(struct ni_gvppqb), (void **)&sc->sc_gvppqb, (paddr_t *)&sc->sc_pgvppqb); ni_getpgs(sc, sizeof(struct ni_fqb), (void **)&sc->sc_fqb, 0); ni_getpgs(sc, NBDESCS * sizeof(struct ni_bbd), (void **)&sc->sc_bbd, 0); /* * Zero the newly allocated memory. */ nipqb->np_veclvl = (ba->ba_ivec << 2) + 2; nipqb->np_node = ba->ba_intcpu; nipqb->np_vpqb = (u_int32_t)gvp; #ifdef __vax__ nipqb->np_spt = nipqb->np_gpt = mfpr(PR_SBR); nipqb->np_sptlen = nipqb->np_gptlen = mfpr(PR_SLR); #else #error Must fix support for non-vax. #endif nipqb->np_bvplvl = 1; nipqb->np_vfqb = (u_int32_t)fqb; nipqb->np_vbdt = (u_int32_t)bbd; nipqb->np_nbdr = NBDESCS; /* Free queue block */ nipqb->np_freeq = NQUEUES; fqb->nf_mlen = PKTHDR+MSGADD; fqb->nf_dlen = PKTHDR+TXADD; fqb->nf_rlen = PKTHDR+RXADD; strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_start = nistart; ifp->if_ioctl = niioctl; ifp->if_watchdog = nitimeout; IFQ_SET_READY(&ifp->if_snd); /* * Start init sequence. */ /* Reset the node */ NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST); DELAY(500000); i = 20; while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i) DELAY(500000); if (i == 0) { printf("%s: BROKE bit set after reset\n", device_xname(self)); return; } /* Check state */ if (failtest(sc, NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state")) return; /* Clear owner bits */ NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN); /* kick off init */ NI_WREG(NI_PCR, (u_int32_t)sc->sc_pgvppqb | PCR_INIT | PCR_OWN); while (NI_RREG(NI_PCR) & PCR_OWN) DELAY(100000); /* Check state */ if (failtest(sc, NI_PSR, PSR_INITED, PSR_INITED, "failed initialize")) return; NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE); WAITREG(NI_PCR, PCR_OWN); WAITREG(NI_PSR, PSR_OWN); /* Check state */ if (failtest(sc, NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable")) return; NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); /* * The message queue packets must be located on the beginning * of a page. A VAX page is 512 bytes, but it clusters 8 pages. * This knowledge is used here when allocating pages. * !!! How should this be done on MIPS and Alpha??? !!! */ #if NBPG < 4096 #error pagesize too small #endif s = splvm(); /* Set up message free queue */ ni_getpgs(sc, NMSGBUF * 512, &va, 0); for (i = 0; i < NMSGBUF; i++) { msg = (void *)((char *)va + i * 512); res = INSQTI(msg, &fqb->nf_mforw); } WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); /* Set up xmit queue */ ni_getpgs(sc, NTXBUF * 512, &va, 0); for (i = 0; i < NTXBUF; i++) { struct ni_dg *data; data = (void *)((char *)va + i * 512); data->nd_status = 0; data->nd_len = TXADD; data->nd_ptdbidx = 1; data->nd_opcode = BVP_DGRAM; for (j = 0; j < NTXFRAGS; j++) { data->bufs[j]._offset = 0; data->bufs[j]._key = 1; bbd[i * NTXFRAGS + j].nb_key = 1; bbd[i * NTXFRAGS + j].nb_status = 0; data->bufs[j]._index = i * NTXFRAGS + j; } res = INSQTI(data, &fqb->nf_dforw); } WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); /* recv buffers */ ni_getpgs(sc, NRXBUF * 512, &va, 0); for (i = 0; i < NRXBUF; i++) { struct ni_dg *data; int idx; data = (void *)((char *)va + i * 512); data->nd_len = RXADD; data->nd_opcode = BVP_DGRAMRX; data->nd_ptdbidx = 2; data->bufs[0]._key = 1; idx = NTXBUF * NTXFRAGS + i; if (ni_add_rxbuf(sc, data, idx)) panic("niattach: ni_add_rxbuf: out of mbufs"); res = INSQTI(data, &fqb->nf_rforw); } WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); splx(s); /* Set initial parameters */ msg = REMQHI(&fqb->nf_mforw); msg->nm_opcode = BVP_MSG; msg->nm_status = 0; msg->nm_len = sizeof(struct ni_param) + 6; msg->nm_opcode2 = NI_WPARAM; ((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD; endwait = retry = 0; res = INSQTI(msg, &gvp->nc_forw0); retry: WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); i = 1000; while (endwait == 0 && --i) DELAY(10000); if (endwait == 0) { if (++retry < 3) goto retry; printf("%s: no response to set params\n", device_xname(self)); return; } /* Clear counters */ msg = REMQHI(&fqb->nf_mforw); msg->nm_opcode = BVP_MSG; msg->nm_status = 0; msg->nm_len = sizeof(struct ni_param) + 6; msg->nm_opcode2 = NI_RCCNTR; res = INSQTI(msg, &gvp->nc_forw0); WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); /* Enable transmit logic */ msg = REMQHI(&fqb->nf_mforw); msg->nm_opcode = BVP_MSG; msg->nm_status = 0; msg->nm_len = 18; msg->nm_opcode2 = NI_STPTDB; ptdb = (struct ni_ptdb *)&msg->nm_text[0]; memset(ptdb, 0, sizeof(struct ni_ptdb)); ptdb->np_index = 1; ptdb->np_fque = 1; res = INSQTI(msg, &gvp->nc_forw0); WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); WAITREG(NI_PCR, PCR_OWN); /* Wait for everything to finish */ WAITREG(NI_PSR, PSR_OWN); printf("%s: hardware address %s\n", device_xname(self), ether_sprintf(sc->sc_enaddr)); /* * Attach the interface. */ if_attach(ifp); ether_ifattach(ifp, sc->sc_enaddr); if (shutdownhook_establish(ni_shutdown, sc) == 0) aprint_error_dev(self, "WARNING: unable to establish shutdown hook\n"); }
/* * Start output on interface. */ void nistart(struct ifnet *ifp) { struct ni_softc *sc = ifp->if_softc; struct ni_dg *data; struct ni_bbd *bdp; struct mbuf *m, *m0; int i, cnt, res, mlen; if (ifp->if_flags & IFF_OACTIVE) return; #ifdef DEBUG if (ifp->if_flags & IFF_DEBUG) printf("%s: nistart\n", device_xname(sc->sc_dev)); #endif while (fqb->nf_dforw) { IFQ_POLL(&ifp->if_snd, m); if (m == 0) break; data = REMQHI(&fqb->nf_dforw); if ((int)data == Q_EMPTY) { ifp->if_flags |= IFF_OACTIVE; break; } IFQ_DEQUEUE(&ifp->if_snd, m); /* * Count number of mbufs in chain. * Always do DMA directly from mbufs, therefore the transmit * ring is really big. */ for (m0 = m, cnt = 0; m0; m0 = m0->m_next) if (m0->m_len) cnt++; if (cnt > NTXFRAGS) panic("nistart"); /* XXX */ bpf_mtap(ifp, m); bdp = &bbd[(data->bufs[0]._index & 0x7fff)]; for (m0 = m, i = 0, mlen = 0; m0; m0 = m0->m_next) { if (m0->m_len == 0) continue; bdp->nb_status = (mtod(m0, u_int32_t) & NIBD_OFFSET) | NIBD_VALID; bdp->nb_pte = (u_int32_t)kvtopte(mtod(m0, void *)); bdp->nb_len = m0->m_len; data->bufs[i]._offset = 0; data->bufs[i]._len = bdp->nb_len; data->bufs[i]._index |= NIDG_CHAIN; mlen += bdp->nb_len; bdp++; i++; } data->nd_opcode = BVP_DGRAM; data->nd_pad3 = 1; data->nd_ptdbidx = 1; data->nd_len = 10 + i * 8; data->bufs[i - 1]._index &= ~NIDG_CHAIN; data->nd_cmdref = (u_int32_t)m; #ifdef DEBUG if (ifp->if_flags & IFF_DEBUG) printf("%s: sending %d bytes (%d segments)\n", device_xname(sc->sc_dev), mlen, i); #endif res = INSQTI(data, &gvp->nc_forw0); if (res == Q_EMPTY) { WAITREG(NI_PCR, PCR_OWN); NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); } } }
#include "relqueopi.h" #include "cmidef.h" #include "hashtab_mname.h" /* needed for cmmdef.h */ #include "cmmdef.h" #include "gtcm_action_pending.h" GBLREF relque action_que; GBLREF gd_region *action_que_dummy_reg; GBLREF node_local_ptr_t locknl; /* gtcm_action_pending - insert action into action queue and set flag so the same action cannot be inserted more than once. * N.B. gtcm_action_pending should only be invoked from an AST (or with ASTs disabled). */ long gtcm_action_pending(connection_struct *c) { long status = 0; /* assert (lib$ast_in_prog()); */ if (!c->waiting_in_queue) { UNIX_ONLY(DEBUG_ONLY(locknl = FILE_INFO(action_que_dummy_reg)->s_addrs.nl;)) /* for DEBUG_ONLY LOCK_HIST macro */ status = INSQTI(c, &action_que); UNIX_ONLY(DEBUG_ONLY(locknl = NULL;)) /* restore "locknl" to default value */ if (INTERLOCK_FAIL == status) return status; c->waiting_in_queue = TRUE; } return status; }