Annotation of sys/arch/vax/bi/if_ni.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ni.c,v 1.10 2007/05/11 10:06:55 pedro Exp $ */
! 2: /* $NetBSD: if_ni.c,v 1.15 2002/05/22 16:03:14 wiz Exp $ */
! 3: /*
! 4: * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. All advertising materials mentioning features or use of this software
! 15: * must display the following acknowledgement:
! 16: * This product includes software developed at Ludd, University of
! 17: * Lule}, Sweden and its contributors.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Driver for DEBNA/DEBNT/DEBNK ethernet cards.
! 35: * Things that is still to do:
! 36: * Collect statistics.
! 37: */
! 38:
! 39: #include "bpfilter.h"
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/mbuf.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/device.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/sockio.h>
! 47: #include <sys/sched.h>
! 48:
! 49: #include <net/if.h>
! 50: #include <net/if_ether.h>
! 51: #include <net/if_dl.h>
! 52:
! 53: #include <netinet/in.h>
! 54: #include <netinet/if_inarp.h>
! 55:
! 56: #if NBPFILTER > 0
! 57: #include <net/bpf.h>
! 58: #include <net/bpfdesc.h>
! 59: #endif
! 60:
! 61: #include <machine/bus.h>
! 62: #ifdef __vax__
! 63: #include <machine/mtpr.h>
! 64: #include <machine/pte.h>
! 65: #endif
! 66:
! 67: #include <dev/bi/bireg.h>
! 68: #include <dev/bi/bivar.h>
! 69:
! 70: /*
! 71: * Tunable buffer parameters. Good idea to have them as power of 8; then
! 72: * they will fit into a logical VAX page.
! 73: */
! 74: #define NMSGBUF 8 /* Message queue entries */
! 75: #define NTXBUF 16 /* Transmit queue entries */
! 76: #define NTXFRAGS 8 /* Number of transmit buffer fragments */
! 77: #define NRXBUF 24 /* Receive queue entries */
! 78: #define NBDESCS (NTXBUF * NTXFRAGS + NRXBUF)
! 79: #define NQUEUES 3 /* RX + TX + MSG */
! 80: #define PKTHDR 18 /* Length of (control) packet header */
! 81: #define RXADD 18 /* Additional length of receive datagram */
! 82: #define TXADD (10+NTXFRAGS*8) /* "" transmit "" */
! 83: #define MSGADD 134 /* "" message "" */
! 84:
! 85: #include <dev/bi/if_nireg.h> /* XXX include earlier */
! 86:
! 87: /*
! 88: * Macros for (most cases of) insqti/remqhi.
! 89: * Retry NRETRIES times to do the operation, if it still fails assume
! 90: * a lost lock and panic.
! 91: */
! 92: #define NRETRIES 100
! 93: #define INSQTI(e, h) ({ \
! 94: int ret, i; \
! 95: for (i = 0; i < NRETRIES; i++) { \
! 96: if ((ret = insqti(e, h)) != ILCK_FAILED) \
! 97: break; \
! 98: } \
! 99: if (i == NRETRIES) \
! 100: panic("ni: insqti failed at %d", __LINE__); \
! 101: ret; \
! 102: })
! 103: #define REMQHI(h) ({ \
! 104: int i;void *ret; \
! 105: for (i = 0; i < NRETRIES; i++) { \
! 106: if ((ret = remqhi(h)) != (void *)ILCK_FAILED) \
! 107: break; \
! 108: } \
! 109: if (i == NRETRIES) \
! 110: panic("ni: remqhi failed at %d", __LINE__); \
! 111: ret; \
! 112: })
! 113:
! 114:
! 115: #define nipqb (&sc->sc_gvppqb->nc_pqb)
! 116: #define gvp sc->sc_gvppqb
! 117: #define fqb sc->sc_fqb
! 118: #define bbd sc->sc_bbd
! 119:
! 120: struct ni_softc {
! 121: struct device sc_dev; /* Configuration common part */
! 122: struct ethercom sc_ec; /* Ethernet common part */
! 123: #define sc_if sc_ec.ec_if /* network-visible interface */
! 124: bus_space_tag_t sc_iot;
! 125: bus_addr_t sc_ioh;
! 126: bus_dma_tag_t sc_dmat;
! 127: struct ni_gvppqb *sc_gvppqb; /* Port queue block */
! 128: struct ni_gvppqb *sc_pgvppqb; /* Phys address of PQB */
! 129: struct ni_fqb *sc_fqb; /* Free Queue block */
! 130: struct ni_bbd *sc_bbd; /* Buffer descriptors */
! 131: u_int8_t sc_enaddr[ETHER_ADDR_LEN];
! 132: };
! 133:
! 134: static int nimatch(struct device *, struct cfdata *, void *);
! 135: static void niattach(struct device *, struct device *, void *);
! 136: static void niinit(struct ni_softc *);
! 137: static void nistart(struct ifnet *);
! 138: static void niintr(void *);
! 139: static int niioctl(struct ifnet *, u_long, caddr_t);
! 140: static int ni_add_rxbuf(struct ni_softc *, struct ni_dg *, int);
! 141: static void ni_setup(struct ni_softc *);
! 142: static void nitimeout(struct ifnet *);
! 143: static void ni_shutdown(void *);
! 144: static void ni_getpgs(struct ni_softc *sc, int size, caddr_t *v, paddr_t *p);
! 145: static int failtest(struct ni_softc *, int, int, int, char *);
! 146:
! 147: volatile int endwait, retry; /* Used during autoconfig */
! 148:
! 149: struct cfattach ni_ca = {
! 150: sizeof(struct ni_softc), nimatch, niattach
! 151: };
! 152:
! 153: #define NI_WREG(csr, val) \
! 154: bus_space_write_4(sc->sc_iot, sc->sc_ioh, csr, val)
! 155: #define NI_RREG(csr) \
! 156: bus_space_read_4(sc->sc_iot, sc->sc_ioh, csr)
! 157:
! 158: #define WAITREG(csr,val) while (NI_RREG(csr) & val);
! 159: /*
! 160: * Check for present device.
! 161: */
! 162: int
! 163: nimatch(parent, cf, aux)
! 164: struct device *parent;
! 165: struct cfdata *cf;
! 166: void *aux;
! 167: {
! 168: struct bi_attach_args *ba = aux;
! 169: u_short type;
! 170:
! 171: type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE);
! 172: if (type != BIDT_DEBNA && type != BIDT_DEBNT && type != BIDT_DEBNK)
! 173: return 0;
! 174:
! 175: if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
! 176: cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
! 177: return 0;
! 178:
! 179: return 1;
! 180: }
! 181:
! 182: /*
! 183: * Allocate a bunch of descriptor-safe memory.
! 184: * We need to get the structures from the beginning of its own pages.
! 185: */
! 186: static void
! 187: ni_getpgs(struct ni_softc *sc, int size, caddr_t *v, paddr_t *p)
! 188: {
! 189: bus_dma_segment_t seg;
! 190: int nsegs, error;
! 191:
! 192: if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1,
! 193: &nsegs, BUS_DMA_NOWAIT)) != 0)
! 194: panic(" unable to allocate memory: error %d", error);
! 195:
! 196: if ((error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, v,
! 197: BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0)
! 198: panic(" unable to map memory: error %d", error);
! 199:
! 200: if (p)
! 201: *p = seg.ds_addr;
! 202: memset(*v, 0, size);
! 203: }
! 204:
! 205: static int
! 206: failtest(struct ni_softc *sc, int reg, int mask, int test, char *str)
! 207: {
! 208: int i = 100;
! 209:
! 210: do {
! 211: DELAY(100000);
! 212: } while (((NI_RREG(reg) & mask) != test) && --i);
! 213:
! 214: if (i == 0) {
! 215: printf("%s: %s\n", sc->sc_dev.dv_xname, str);
! 216: return 1;
! 217: }
! 218: return 0;
! 219: }
! 220:
! 221:
! 222: /*
! 223: * Interface exists: make available by filling in network interface
! 224: * record. System will initialize the interface when it is ready
! 225: * to accept packets.
! 226: */
! 227: void
! 228: niattach(parent, self, aux)
! 229: struct device *parent, *self;
! 230: void *aux;
! 231: {
! 232: struct bi_attach_args *ba = aux;
! 233: struct ni_softc *sc = (struct ni_softc *)self;
! 234: struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
! 235: struct ni_msg *msg;
! 236: struct ni_ptdb *ptdb;
! 237: caddr_t va;
! 238: int i, j, s, res;
! 239: u_short type;
! 240:
! 241: type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE);
! 242: printf(": DEBN%c\n", type == BIDT_DEBNA ? 'A' : type == BIDT_DEBNT ?
! 243: 'T' : 'K');
! 244: sc->sc_iot = ba->ba_iot;
! 245: sc->sc_ioh = ba->ba_ioh;
! 246: sc->sc_dmat = ba->ba_dmat;
! 247:
! 248: bi_intr_establish(ba->ba_icookie, ba->ba_ivec, niintr, sc);
! 249:
! 250: ni_getpgs(sc, sizeof(struct ni_gvppqb), (caddr_t *)&sc->sc_gvppqb,
! 251: (paddr_t *)&sc->sc_pgvppqb);
! 252: ni_getpgs(sc, sizeof(struct ni_fqb), (caddr_t *)&sc->sc_fqb, 0);
! 253: ni_getpgs(sc, NBDESCS * sizeof(struct ni_bbd),
! 254: (caddr_t *)&sc->sc_bbd, 0);
! 255: /*
! 256: * Zero the newly allocated memory.
! 257: */
! 258:
! 259: nipqb->np_veclvl = (ba->ba_ivec << 2) + 2;
! 260: nipqb->np_node = ba->ba_intcpu;
! 261: nipqb->np_vpqb = (u_int32_t)gvp;
! 262: #ifdef __vax__
! 263: nipqb->np_spt = nipqb->np_gpt = mfpr(PR_SBR);
! 264: nipqb->np_sptlen = nipqb->np_gptlen = mfpr(PR_SLR);
! 265: #else
! 266: #error Must fix support for non-vax.
! 267: #endif
! 268: nipqb->np_bvplvl = 1;
! 269: nipqb->np_vfqb = (u_int32_t)fqb;
! 270: nipqb->np_vbdt = (u_int32_t)bbd;
! 271: nipqb->np_nbdr = NBDESCS;
! 272:
! 273: /* Free queue block */
! 274: nipqb->np_freeq = NQUEUES;
! 275: fqb->nf_mlen = PKTHDR+MSGADD;
! 276: fqb->nf_dlen = PKTHDR+TXADD;
! 277: fqb->nf_rlen = PKTHDR+RXADD;
! 278:
! 279: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
! 280: ifp->if_softc = sc;
! 281: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 282: ifp->if_start = nistart;
! 283: ifp->if_ioctl = niioctl;
! 284: ifp->if_watchdog = nitimeout;
! 285: IFQ_SET_READY(&ifp->if_snd);
! 286:
! 287: /*
! 288: * Start init sequence.
! 289: */
! 290:
! 291: /* Reset the node */
! 292: NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST);
! 293: DELAY(500000);
! 294: i = 20;
! 295: while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i)
! 296: DELAY(500000);
! 297: if (i == 0) {
! 298: printf("%s: BROKE bit set after reset\n", sc->sc_dev.dv_xname);
! 299: return;
! 300: }
! 301:
! 302: /* Check state */
! 303: if (failtest(sc, NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state"))
! 304: return;
! 305:
! 306: /* Clear owner bits */
! 307: NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
! 308: NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN);
! 309:
! 310: /* kick off init */
! 311: NI_WREG(NI_PCR, (u_int32_t)sc->sc_pgvppqb | PCR_INIT | PCR_OWN);
! 312: while (NI_RREG(NI_PCR) & PCR_OWN)
! 313: DELAY(100000);
! 314:
! 315: /* Check state */
! 316: if (failtest(sc, NI_PSR, PSR_INITED, PSR_INITED, "failed initialize"))
! 317: return;
! 318:
! 319: NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
! 320:
! 321: WAITREG(NI_PCR, PCR_OWN);
! 322: NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE);
! 323: WAITREG(NI_PCR, PCR_OWN);
! 324: WAITREG(NI_PSR, PSR_OWN);
! 325:
! 326: /* Check state */
! 327: if (failtest(sc, NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable"))
! 328: return;
! 329:
! 330: NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
! 331:
! 332: /*
! 333: * The message queue packets must be located on the beginning
! 334: * of a page. A VAX page is 512 bytes, but it clusters 8 pages.
! 335: * This knowledge is used here when allocating pages.
! 336: * !!! How should this be done on MIPS and Alpha??? !!!
! 337: */
! 338: #if NBPG < 4096
! 339: #error pagesize too small
! 340: #endif
! 341: s = splvm();
! 342: /* Set up message free queue */
! 343: ni_getpgs(sc, NMSGBUF * 512, &va, 0);
! 344: for (i = 0; i < NMSGBUF; i++) {
! 345: struct ni_msg *msg;
! 346:
! 347: msg = (void *)(va + i * 512);
! 348:
! 349: res = INSQTI(msg, &fqb->nf_mforw);
! 350: }
! 351: WAITREG(NI_PCR, PCR_OWN);
! 352: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
! 353: WAITREG(NI_PCR, PCR_OWN);
! 354:
! 355: /* Set up xmit queue */
! 356: ni_getpgs(sc, NTXBUF * 512, &va, 0);
! 357: for (i = 0; i < NTXBUF; i++) {
! 358: struct ni_dg *data;
! 359:
! 360: data = (void *)(va + i * 512);
! 361: data->nd_status = 0;
! 362: data->nd_len = TXADD;
! 363: data->nd_ptdbidx = 1;
! 364: data->nd_opcode = BVP_DGRAM;
! 365: for (j = 0; j < NTXFRAGS; j++) {
! 366: data->bufs[j]._offset = 0;
! 367: data->bufs[j]._key = 1;
! 368: bbd[i * NTXFRAGS + j].nb_key = 1;
! 369: bbd[i * NTXFRAGS + j].nb_status = 0;
! 370: data->bufs[j]._index = i * NTXFRAGS + j;
! 371: }
! 372: res = INSQTI(data, &fqb->nf_dforw);
! 373: }
! 374: WAITREG(NI_PCR, PCR_OWN);
! 375: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
! 376: WAITREG(NI_PCR, PCR_OWN);
! 377:
! 378: /* recv buffers */
! 379: ni_getpgs(sc, NRXBUF * 512, &va, 0);
! 380: for (i = 0; i < NRXBUF; i++) {
! 381: struct ni_dg *data;
! 382: int idx;
! 383:
! 384: data = (void *)(va + i * 512);
! 385: data->nd_len = RXADD;
! 386: data->nd_opcode = BVP_DGRAMRX;
! 387: data->nd_ptdbidx = 2;
! 388: data->bufs[0]._key = 1;
! 389:
! 390: idx = NTXBUF * NTXFRAGS + i;
! 391: if (ni_add_rxbuf(sc, data, idx))
! 392: panic("niattach: ni_add_rxbuf: out of mbufs");
! 393:
! 394: res = INSQTI(data, &fqb->nf_rforw);
! 395: }
! 396: WAITREG(NI_PCR, PCR_OWN);
! 397: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
! 398: WAITREG(NI_PCR, PCR_OWN);
! 399:
! 400: splx(s);
! 401:
! 402: /* Set initial parameters */
! 403: msg = REMQHI(&fqb->nf_mforw);
! 404:
! 405: msg->nm_opcode = BVP_MSG;
! 406: msg->nm_status = 0;
! 407: msg->nm_len = sizeof(struct ni_param) + 6;
! 408: msg->nm_opcode2 = NI_WPARAM;
! 409: ((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD;
! 410:
! 411: endwait = retry = 0;
! 412: res = INSQTI(msg, &gvp->nc_forw0);
! 413:
! 414: retry: WAITREG(NI_PCR, PCR_OWN);
! 415: NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
! 416: WAITREG(NI_PCR, PCR_OWN);
! 417: i = 1000;
! 418: while (endwait == 0 && --i)
! 419: DELAY(10000);
! 420:
! 421: if (endwait == 0) {
! 422: if (++retry < 3)
! 423: goto retry;
! 424: printf("%s: no response to set params\n", sc->sc_dev.dv_xname);
! 425: return;
! 426: }
! 427:
! 428: /* Clear counters */
! 429: msg = REMQHI(&fqb->nf_mforw);
! 430: msg->nm_opcode = BVP_MSG;
! 431: msg->nm_status = 0;
! 432: msg->nm_len = sizeof(struct ni_param) + 6;
! 433: msg->nm_opcode2 = NI_RCCNTR;
! 434:
! 435: res = INSQTI(msg, &gvp->nc_forw0);
! 436:
! 437: WAITREG(NI_PCR, PCR_OWN);
! 438: NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
! 439: WAITREG(NI_PCR, PCR_OWN);
! 440:
! 441: /* Enable transmit logic */
! 442: msg = REMQHI(&fqb->nf_mforw);
! 443:
! 444: msg->nm_opcode = BVP_MSG;
! 445: msg->nm_status = 0;
! 446: msg->nm_len = 18;
! 447: msg->nm_opcode2 = NI_STPTDB;
! 448: ptdb = (struct ni_ptdb *)&msg->nm_text[0];
! 449: memset(ptdb, 0, sizeof(struct ni_ptdb));
! 450: ptdb->np_index = 1;
! 451: ptdb->np_fque = 1;
! 452:
! 453: res = INSQTI(msg, &gvp->nc_forw0);
! 454:
! 455: WAITREG(NI_PCR, PCR_OWN);
! 456: NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
! 457: WAITREG(NI_PCR, PCR_OWN);
! 458:
! 459: /* Wait for everything to finish */
! 460: WAITREG(NI_PSR, PSR_OWN);
! 461:
! 462: printf("%s: address %s\n", sc->sc_dev.dv_xname,
! 463: ether_sprintf(sc->sc_enaddr));
! 464:
! 465: /*
! 466: * Attach the interface.
! 467: */
! 468: if_attach(ifp);
! 469: ether_ifattach(ifp, sc->sc_enaddr);
! 470: if (shutdownhook_establish(ni_shutdown, sc) == 0)
! 471: printf("%s: WARNING: unable to establish shutdown hook\n",
! 472: sc->sc_dev.dv_xname);
! 473: }
! 474:
! 475: /*
! 476: * Initialization of interface.
! 477: */
! 478: void
! 479: niinit(sc)
! 480: struct ni_softc *sc;
! 481: {
! 482: struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
! 483:
! 484: /*
! 485: * Set flags (so ni_setup() do the right thing).
! 486: */
! 487: ifp->if_flags |= IFF_RUNNING;
! 488: ifp->if_flags &= ~IFF_OACTIVE;
! 489:
! 490: /*
! 491: * Send setup messages so that the rx/tx locic starts.
! 492: */
! 493: ni_setup(sc);
! 494:
! 495: }
! 496:
! 497: /*
! 498: * Start output on interface.
! 499: */
! 500: void
! 501: nistart(ifp)
! 502: struct ifnet *ifp;
! 503: {
! 504: struct ni_softc *sc = ifp->if_softc;
! 505: struct ni_dg *data;
! 506: struct ni_bbd *bdp;
! 507: struct mbuf *m, *m0;
! 508: int i, cnt, res, mlen;
! 509:
! 510: if (ifp->if_flags & IFF_OACTIVE)
! 511: return;
! 512: #ifdef DEBUG
! 513: if (ifp->if_flags & IFF_DEBUG)
! 514: printf("%s: nistart\n", sc->sc_dev.dv_xname);
! 515: #endif
! 516:
! 517: while (fqb->nf_dforw) {
! 518: IFQ_POLL(&ifp->if_snd, m);
! 519: if (m == 0)
! 520: break;
! 521:
! 522: data = REMQHI(&fqb->nf_dforw);
! 523: if ((int)data == Q_EMPTY) {
! 524: ifp->if_flags |= IFF_OACTIVE;
! 525: break;
! 526: }
! 527:
! 528: IFQ_DEQUEUE(&ifp->if_snd, m);
! 529:
! 530: /*
! 531: * Count number of mbufs in chain.
! 532: * Always do DMA directly from mbufs, therefore the transmit
! 533: * ring is really big.
! 534: */
! 535: for (m0 = m, cnt = 0; m0; m0 = m0->m_next)
! 536: if (m0->m_len)
! 537: cnt++;
! 538: if (cnt > NTXFRAGS)
! 539: panic("nistart"); /* XXX */
! 540:
! 541: #if NBPFILTER > 0
! 542: if (ifp->if_bpf)
! 543: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 544: #endif
! 545: bdp = &bbd[(data->bufs[0]._index & 0x7fff)];
! 546: for (m0 = m, i = 0, mlen = 0; m0; m0 = m0->m_next) {
! 547: if (m0->m_len == 0)
! 548: continue;
! 549: bdp->nb_status = (mtod(m0, u_int32_t) & NIBD_OFFSET) |
! 550: NIBD_VALID;
! 551: bdp->nb_pte = (u_int32_t)kvtopte(mtod(m0, void *));
! 552: bdp->nb_len = m0->m_len;
! 553: data->bufs[i]._offset = 0;
! 554: data->bufs[i]._len = bdp->nb_len;
! 555: data->bufs[i]._index |= NIDG_CHAIN;
! 556: mlen += bdp->nb_len;
! 557: bdp++;
! 558: i++;
! 559: }
! 560: data->nd_opcode = BVP_DGRAM;
! 561: data->nd_pad3 = 1;
! 562: data->nd_ptdbidx = 1;
! 563: data->nd_len = 10 + i * 8;
! 564: data->bufs[i - 1]._index &= ~NIDG_CHAIN;
! 565: if (mlen < 64)
! 566: data->bufs[i - 1]._len = bdp[-1].nb_len += (64 - mlen);
! 567: data->nd_cmdref = (u_int32_t)m;
! 568: #ifdef DEBUG
! 569: if (ifp->if_flags & IFF_DEBUG)
! 570: printf("%s: sending %d bytes (%d segments)\n",
! 571: sc->sc_dev.dv_xname, mlen, i);
! 572: #endif
! 573:
! 574: res = INSQTI(data, &gvp->nc_forw0);
! 575: if (res == Q_EMPTY) {
! 576: WAITREG(NI_PCR, PCR_OWN);
! 577: NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
! 578: }
! 579: }
! 580: }
! 581:
! 582: void
! 583: niintr(void *arg)
! 584: {
! 585: struct ni_softc *sc = arg;
! 586: struct ni_dg *data;
! 587: struct ni_msg *msg;
! 588: struct ifnet *ifp = &sc->sc_if;
! 589: struct ni_bbd *bd;
! 590: struct mbuf *m;
! 591: int idx, res;
! 592:
! 593: if ((NI_RREG(NI_PSR) & PSR_STATE) != PSR_ENABLED)
! 594: return;
! 595:
! 596: if ((NI_RREG(NI_PSR) & PSR_ERR))
! 597: printf("%s: PSR %x\n", sc->sc_dev.dv_xname, NI_RREG(NI_PSR));
! 598:
! 599: KERNEL_LOCK();
! 600: /* Got any response packets? */
! 601: while ((NI_RREG(NI_PSR) & PSR_RSQ) && (data = REMQHI(&gvp->nc_forwr))) {
! 602:
! 603: switch (data->nd_opcode) {
! 604: case BVP_DGRAMRX: /* Receive datagram */
! 605: idx = data->bufs[0]._index;
! 606: bd = &bbd[idx];
! 607: m = (void *)data->nd_cmdref;
! 608: m->m_pkthdr.len = m->m_len =
! 609: data->bufs[0]._len - ETHER_CRC_LEN;
! 610: m->m_pkthdr.rcvif = ifp;
! 611: if (ni_add_rxbuf(sc, data, idx)) {
! 612: bd->nb_len = (m->m_ext.ext_size - 2);
! 613: bd->nb_pte =
! 614: (long)kvtopte(m->m_ext.ext_buf);
! 615: bd->nb_status = 2 | NIBD_VALID;
! 616: bd->nb_key = 1;
! 617: }
! 618: data->nd_len = RXADD;
! 619: data->nd_status = 0;
! 620: res = INSQTI(data, &fqb->nf_rforw);
! 621: if (res == Q_EMPTY) {
! 622: WAITREG(NI_PCR, PCR_OWN);
! 623: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
! 624: }
! 625: if (m == (void *)data->nd_cmdref)
! 626: break; /* Out of mbufs */
! 627:
! 628: #if NBPFILTER > 0
! 629: if (ifp->if_bpf)
! 630: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 631: #endif
! 632: (*ifp->if_input)(ifp, m);
! 633: break;
! 634:
! 635: case BVP_DGRAM:
! 636: m = (struct mbuf *)data->nd_cmdref;
! 637: ifp->if_flags &= ~IFF_OACTIVE;
! 638: m_freem(m);
! 639: res = INSQTI(data, &fqb->nf_dforw);
! 640: if (res == Q_EMPTY) {
! 641: WAITREG(NI_PCR, PCR_OWN);
! 642: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
! 643: }
! 644: break;
! 645:
! 646: case BVP_MSGRX:
! 647: msg = (struct ni_msg *)data;
! 648: switch (msg->nm_opcode2) {
! 649: case NI_WPARAM:
! 650: memcpy(sc->sc_enaddr, ((struct ni_param *)&msg->nm_text[0])->np_dpa, ETHER_ADDR_LEN);
! 651: endwait = 1;
! 652: break;
! 653:
! 654: case NI_RCCNTR:
! 655: case NI_CLPTDB:
! 656: case NI_STPTDB:
! 657: break;
! 658:
! 659: default:
! 660: printf("Unkn resp %d\n",
! 661: msg->nm_opcode2);
! 662: break;
! 663: }
! 664: res = INSQTI(data, &fqb->nf_mforw);
! 665: if (res == Q_EMPTY) {
! 666: WAITREG(NI_PCR, PCR_OWN);
! 667: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
! 668: }
! 669: break;
! 670:
! 671: default:
! 672: printf("Unknown opcode %d\n", data->nd_opcode);
! 673: res = INSQTI(data, &fqb->nf_mforw);
! 674: if (res == Q_EMPTY) {
! 675: WAITREG(NI_PCR, PCR_OWN);
! 676: NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
! 677: }
! 678: }
! 679: }
! 680:
! 681: /* Try to kick on the start routine again */
! 682: nistart(ifp);
! 683:
! 684: NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ));
! 685: KERNEL_UNLOCK();
! 686: }
! 687:
! 688: /*
! 689: * Process an ioctl request.
! 690: */
! 691: int
! 692: niioctl(ifp, cmd, data)
! 693: register struct ifnet *ifp;
! 694: u_long cmd;
! 695: caddr_t data;
! 696: {
! 697: struct ni_softc *sc = ifp->if_softc;
! 698: struct ifreq *ifr = (struct ifreq *)data;
! 699: struct ifaddr *ifa = (struct ifaddr *)data;
! 700: int s = splnet(), error = 0;
! 701:
! 702: switch (cmd) {
! 703:
! 704: case SIOCSIFADDR:
! 705: ifp->if_flags |= IFF_UP;
! 706: switch(ifa->ifa_addr->sa_family) {
! 707: #ifdef INET
! 708: case AF_INET:
! 709: niinit(sc);
! 710: arp_ifinit(ifp, ifa);
! 711: break;
! 712: #endif
! 713: }
! 714: break;
! 715:
! 716: case SIOCSIFFLAGS:
! 717: if ((ifp->if_flags & IFF_UP) == 0 &&
! 718: (ifp->if_flags & IFF_RUNNING) != 0) {
! 719: /*
! 720: * If interface is marked down and it is running,
! 721: * stop it.
! 722: */
! 723: ifp->if_flags &= ~IFF_RUNNING;
! 724: ni_setup(sc);
! 725: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 726: (ifp->if_flags & IFF_RUNNING) == 0) {
! 727: /*
! 728: * If interface it marked up and it is stopped, then
! 729: * start it.
! 730: */
! 731: niinit(sc);
! 732: } else if ((ifp->if_flags & IFF_UP) != 0) {
! 733: /*
! 734: * Send a new setup packet to match any new changes.
! 735: * (Like IFF_PROMISC etc)
! 736: */
! 737: ni_setup(sc);
! 738: }
! 739: break;
! 740:
! 741: case SIOCADDMULTI:
! 742: case SIOCDELMULTI:
! 743: /*
! 744: * Update our multicast list.
! 745: */
! 746: error = (cmd == SIOCADDMULTI) ?
! 747: ether_addmulti(ifr, &sc->sc_ec):
! 748: ether_delmulti(ifr, &sc->sc_ec);
! 749:
! 750: if (error == ENETRESET) {
! 751: /*
! 752: * Multicast list has changed; set the hardware filter
! 753: * accordingly.
! 754: */
! 755: if (ifp->if_flags & IFF_RUNNING)
! 756: ni_setup(sc);
! 757: error = 0;
! 758: }
! 759: break;
! 760:
! 761: default:
! 762: error = EINVAL;
! 763:
! 764: }
! 765: splx(s);
! 766: return (error);
! 767: }
! 768:
! 769: /*
! 770: * Add a receive buffer to the indicated descriptor.
! 771: */
! 772: int
! 773: ni_add_rxbuf(struct ni_softc *sc, struct ni_dg *data, int idx)
! 774: {
! 775: struct ni_bbd *bd = &bbd[idx];
! 776: struct mbuf *m;
! 777:
! 778: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 779: if (m == NULL)
! 780: return (ENOBUFS);
! 781:
! 782: MCLGET(m, M_DONTWAIT);
! 783: if ((m->m_flags & M_EXT) == 0) {
! 784: m_freem(m);
! 785: return (ENOBUFS);
! 786: }
! 787:
! 788: m->m_data += 2;
! 789: bd->nb_len = (m->m_ext.ext_size - 2);
! 790: bd->nb_pte = (long)kvtopte(m->m_ext.ext_buf);
! 791: bd->nb_status = 2 | NIBD_VALID;
! 792: bd->nb_key = 1;
! 793:
! 794: data->bufs[0]._offset = 0;
! 795: data->bufs[0]._len = bd->nb_len;
! 796: data->bufs[0]._index = idx;
! 797: data->nd_cmdref = (long)m;
! 798:
! 799: return (0);
! 800: }
! 801:
! 802: /*
! 803: * Create setup packet and put in queue for sending.
! 804: */
! 805: void
! 806: ni_setup(struct ni_softc *sc)
! 807: {
! 808: struct ifnet *ifp = &sc->sc_if;
! 809: struct ni_msg *msg;
! 810: struct ni_ptdb *ptdb;
! 811: struct ether_multi *enm;
! 812: struct ether_multistep step;
! 813: int i, res;
! 814:
! 815: msg = REMQHI(&fqb->nf_mforw);
! 816: if ((int)msg == Q_EMPTY)
! 817: return; /* What to do? */
! 818:
! 819: ptdb = (struct ni_ptdb *)&msg->nm_text[0];
! 820: memset(ptdb, 0, sizeof(struct ni_ptdb));
! 821:
! 822: msg->nm_opcode = BVP_MSG;
! 823: msg->nm_len = 18;
! 824: ptdb->np_index = 2; /* definition type index */
! 825: ptdb->np_fque = 2; /* Free queue */
! 826: if (ifp->if_flags & IFF_RUNNING) {
! 827: msg->nm_opcode2 = NI_STPTDB;
! 828: ptdb->np_type = ETHERTYPE_IP;
! 829: ptdb->np_flags = PTDB_UNKN|PTDB_BDC;
! 830: if (ifp->if_flags & IFF_PROMISC)
! 831: ptdb->np_flags |= PTDB_PROMISC;
! 832: memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); /* Broadcast */
! 833: ptdb->np_adrlen = 1;
! 834: msg->nm_len += 8;
! 835: ifp->if_flags &= ~IFF_ALLMULTI;
! 836: if ((ifp->if_flags & IFF_PROMISC) == 0) {
! 837: ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
! 838: i = 1;
! 839: while (enm != NULL) {
! 840: if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
! 841: ifp->if_flags |= IFF_ALLMULTI;
! 842: ptdb->np_flags |= PTDB_AMC;
! 843: break;
! 844: }
! 845: msg->nm_len += 8;
! 846: ptdb->np_adrlen++;
! 847: memcpy(ptdb->np_mcast[i++], enm->enm_addrlo,
! 848: ETHER_ADDR_LEN);
! 849: ETHER_NEXT_MULTI(step, enm);
! 850: }
! 851: }
! 852: } else
! 853: msg->nm_opcode2 = NI_CLPTDB;
! 854:
! 855: res = INSQTI(msg, &gvp->nc_forw0);
! 856: if (res == Q_EMPTY) {
! 857: WAITREG(NI_PCR, PCR_OWN);
! 858: NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
! 859: }
! 860: }
! 861:
! 862: /*
! 863: * Check for dead transmit logic. Not uncommon.
! 864: */
! 865: void
! 866: nitimeout(ifp)
! 867: struct ifnet *ifp;
! 868: {
! 869: #if 0
! 870: struct ni_softc *sc = ifp->if_softc;
! 871:
! 872: if (sc->sc_inq == 0)
! 873: return;
! 874:
! 875: printf("%s: xmit logic died, resetting...\n", sc->sc_dev.dv_xname);
! 876: /*
! 877: * Do a reset of interface, to get it going again.
! 878: * Will it work by just restart the transmit logic?
! 879: */
! 880: niinit(sc);
! 881: #endif
! 882: }
! 883:
! 884: /*
! 885: * Shutdown hook. Make sure the interface is stopped at reboot.
! 886: */
! 887: void
! 888: ni_shutdown(arg)
! 889: void *arg;
! 890: {
! 891: struct ni_softc *sc = arg;
! 892:
! 893: WAITREG(NI_PCR, PCR_OWN);
! 894: NI_WREG(NI_PCR, PCR_OWN|PCR_SHUTDOWN);
! 895: WAITREG(NI_PCR, PCR_OWN);
! 896: WAITREG(NI_PSR, PSR_OWN);
! 897:
! 898: }
! 899:
CVSweb