/*
 * 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);
		}
	}
}
Exemple #5
0
#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;
}