1285612Sdelphij/* $NetBSD: if_ni.c,v 1.50 2022/09/18 16:51:28 thorpej Exp $ */ 2181834Sroberto/* 3285612Sdelphij * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. 4330567Sgordon * 5181834Sroberto * Redistribution and use in source and binary forms, with or without 6181834Sroberto * modification, are permitted provided that the following conditions 7181834Sroberto * are met: 8285612Sdelphij * 1. Redistributions of source code must retain the above copyright 9181834Sroberto * notice, this list of conditions and the following disclaimer. 10285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11285612Sdelphij * notice, this list of conditions and the following disclaimer in the 12285612Sdelphij * documentation and/or other materials provided with the distribution. 13285612Sdelphij * 3. All advertising materials mentioning features or use of this software 14285612Sdelphij * must display the following acknowledgement: 15285612Sdelphij * This product includes software developed at Ludd, University of 16285612Sdelphij * Lule}, Sweden and its contributors. 17181834Sroberto * 4. The name of the author may not be used to endorse or promote products 18285612Sdelphij * derived from this software without specific prior written permission 19285612Sdelphij * 20181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21316722Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22285612Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23285612Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24285612Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25285612Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26285612Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27285612Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28285612Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29285612Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30285612Sdelphij */ 31285612Sdelphij 32285612Sdelphij/* 33285612Sdelphij * Driver for DEBNA/DEBNT/DEBNK ethernet cards. 34285612Sdelphij * Things that is still to do: 35285612Sdelphij * Collect statistics. 36285612Sdelphij */ 37181834Sroberto 38285612Sdelphij#include <sys/cdefs.h> 39181834Sroberto__KERNEL_RCSID(0, "$NetBSD: if_ni.c,v 1.50 2022/09/18 16:51:28 thorpej Exp $"); 40181834Sroberto 41181834Sroberto#include "opt_inet.h" 42181834Sroberto 43181834Sroberto#include <sys/param.h> 44181834Sroberto#include <sys/mbuf.h> 45285612Sdelphij#include <sys/socket.h> 46181834Sroberto#include <sys/device.h> 47181834Sroberto#include <sys/systm.h> 48181834Sroberto#include <sys/sockio.h> 49285612Sdelphij#include <sys/sched.h> 50181834Sroberto 51181834Sroberto#include <net/if.h> 52181834Sroberto#include <net/if_ether.h> 53181834Sroberto#include <net/if_dl.h> 54181834Sroberto#include <net/bpf.h> 55181834Sroberto 56285612Sdelphij#include <netinet/in.h> 57181834Sroberto#include <netinet/if_inarp.h> 58181834Sroberto 59181834Sroberto#include <sys/bus.h> 60181834Sroberto#ifdef __vax__ 61181834Sroberto#include <machine/mtpr.h> 62181834Sroberto#include <machine/pte.h> 63285612Sdelphij#endif 64285612Sdelphij 65181834Sroberto#include <dev/bi/bireg.h> 66181834Sroberto#include <dev/bi/bivar.h> 67285612Sdelphij 68285612Sdelphij#include "ioconf.h" 69285612Sdelphij#include "locators.h" 70285612Sdelphij 71285612Sdelphij/* 72285612Sdelphij * Tunable buffer parameters. Good idea to have them as power of 8; then 73285612Sdelphij * they will fit into a logical VAX page. 74285612Sdelphij */ 75285612Sdelphij#define NMSGBUF 8 /* Message queue entries */ 76285612Sdelphij#define NTXBUF 16 /* Transmit queue entries */ 77285612Sdelphij#define NTXFRAGS 8 /* Number of transmit buffer fragments */ 78285612Sdelphij#define NRXBUF 24 /* Receive queue entries */ 79285612Sdelphij#define NBDESCS (NTXBUF * NTXFRAGS + NRXBUF) 80285612Sdelphij#define NQUEUES 3 /* RX + TX + MSG */ 81285612Sdelphij#define PKTHDR 18 /* Length of (control) packet header */ 82285612Sdelphij#define RXADD 18 /* Additional length of receive datagram */ 83285612Sdelphij#define TXADD (10+NTXFRAGS*8) /* "" transmit "" */ 84285612Sdelphij#define MSGADD 134 /* "" message "" */ 85285612Sdelphij 86285612Sdelphij#include <dev/bi/if_nireg.h> /* XXX include earlier */ 87285612Sdelphij 88285612Sdelphij/* 89285612Sdelphij * Macros for (most cases of) insqti/remqhi. 90285612Sdelphij * Retry NRETRIES times to do the operation, if it still fails assume 91285612Sdelphij * a lost lock and panic. 92285612Sdelphij */ 93285612Sdelphij#define NRETRIES 100 94285612Sdelphij#define INSQTI(e, h) ({ \ 95285612Sdelphij int ret = 0, __i; \ 96285612Sdelphij for (__i = 0; __i < NRETRIES; __i++) { \ 97285612Sdelphij if ((ret = insqti(e, h)) != ILCK_FAILED) \ 98285612Sdelphij break; \ 99285612Sdelphij } \ 100285612Sdelphij if (__i == NRETRIES) \ 101285612Sdelphij panic("ni: insqti failed at %d", __LINE__); \ 102285612Sdelphij ret; \ 103285612Sdelphij}) 104285612Sdelphij#define REMQHI(h) ({ \ 105181834Sroberto int __i; void *ret = NULL; \ 106285612Sdelphij for (__i = 0; __i < NRETRIES; __i++) { \ 107285612Sdelphij if ((ret = remqhi(h)) != (void *)ILCK_FAILED) \ 108285612Sdelphij break; \ 109330567Sgordon } \ 110285612Sdelphij if (__i == NRETRIES) \ 111330567Sgordon panic("ni: remqhi failed at %d", __LINE__); \ 112181834Sroberto ret; \ 113285612Sdelphij}) 114181834Sroberto 115181834Sroberto 116285612Sdelphij#define nipqb (&sc->sc_gvppqb->nc_pqb) 117181834Sroberto#define gvp sc->sc_gvppqb 118181834Sroberto#define fqb sc->sc_fqb 119285612Sdelphij#define bbd sc->sc_bbd 120181834Sroberto 121285612Sdelphijstruct ni_softc { 122181834Sroberto device_t sc_dev; /* Configuration common part */ 123285612Sdelphij struct evcnt sc_intrcnt; /* Interrupt coounting */ 124285612Sdelphij struct ethercom sc_ec; /* Ethernet common part */ 125285612Sdelphij#define sc_if sc_ec.ec_if /* network-visible interface */ 126285612Sdelphij bus_space_tag_t sc_iot; 127181834Sroberto bus_addr_t sc_ioh; 128285612Sdelphij bus_dma_tag_t sc_dmat; 129181834Sroberto struct ni_gvppqb *sc_gvppqb; /* Port queue block */ 130285612Sdelphij struct ni_gvppqb *sc_pgvppqb; /* Phys address of PQB */ 131181834Sroberto struct ni_fqb *sc_fqb; /* Free Queue block */ 132285612Sdelphij struct ni_bbd *sc_bbd; /* Buffer descriptors */ 133181834Sroberto uint8_t sc_enaddr[ETHER_ADDR_LEN]; 134285612Sdelphij}; 135181834Sroberto 136285612Sdelphijstatic int nimatch(device_t, cfdata_t, void *); 137285612Sdelphijstatic void niattach(device_t, device_t, void *); 138181834Srobertostatic void niinit(struct ni_softc *); 139285612Sdelphijstatic void nistart(struct ifnet *); 140285612Sdelphijstatic void niintr(void *); 141181834Srobertostatic int niioctl(struct ifnet *, u_long, void *); 142285612Sdelphijstatic int ni_add_rxbuf(struct ni_softc *, struct ni_dg *, int); 143181834Srobertostatic void ni_setup(struct ni_softc *); 144181834Srobertostatic void nitimeout(struct ifnet *); 145285612Sdelphijstatic void ni_shutdown(void *); 146181834Srobertostatic void ni_getpgs(struct ni_softc *, int, void **, paddr_t *); 147181834Srobertostatic int failtest(struct ni_softc *, int, int, int, const char *); 148285612Sdelphij 149285612Sdelphijvolatile int endwait, retry; /* Used during autoconfig */ 150285612Sdelphij 151285612SdelphijCFATTACH_DECL_NEW(ni, sizeof(struct ni_softc), 152285612Sdelphij nimatch, niattach, NULL, NULL); 153285612Sdelphij 154285612Sdelphij#define NI_WREG(csr, val) \ 155285612Sdelphij bus_space_write_4(sc->sc_iot, sc->sc_ioh, csr, val) 156285612Sdelphij#define NI_RREG(csr) \ 157285612Sdelphij bus_space_read_4(sc->sc_iot, sc->sc_ioh, csr) 158285612Sdelphij 159285612Sdelphij#define WAITREG(csr,val) while (NI_RREG(csr) & val); 160181834Sroberto/* 161181834Sroberto * Check for present device. 162181834Sroberto */ 163181834Srobertostatic int 164181834Srobertonimatch(device_t parent, cfdata_t cf, void *aux) 165181834Sroberto{ 166181834Sroberto struct bi_attach_args *ba = aux; 167181834Sroberto u_short type; 168181834Sroberto 169181834Sroberto type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE); 170181834Sroberto if (type != BIDT_DEBNA && type != BIDT_DEBNT && type != BIDT_DEBNK) 171181834Sroberto return 0; 172181834Sroberto 173181834Sroberto if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT && 174181834Sroberto cf->cf_loc[BICF_NODE] != ba->ba_nodenr) 175181834Sroberto return 0; 176181834Sroberto 177181834Sroberto return 1; 178181834Sroberto} 179181834Sroberto 180181834Sroberto/* 181181834Sroberto * Allocate a bunch of descriptor-safe memory. 182181834Sroberto * We need to get the structures from the beginning of its own pages. 183181834Sroberto */ 184181834Srobertostatic void 185181834Srobertoni_getpgs(struct ni_softc *sc, int size, void **v, paddr_t *p) 186181834Sroberto{ 187181834Sroberto bus_dma_segment_t seg; 188181834Sroberto int nsegs, error; 189181834Sroberto 190181834Sroberto if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 191181834Sroberto &nsegs, BUS_DMA_NOWAIT)) != 0) 192181834Sroberto panic(" unable to allocate memory: error %d", error); 193181834Sroberto 194181834Sroberto if ((error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, v, 195181834Sroberto BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) 196181834Sroberto panic(" unable to map memory: error %d", error); 197181834Sroberto 198181834Sroberto if (p) 199181834Sroberto *p = seg.ds_addr; 200181834Sroberto memset(*v, 0, size); 201181834Sroberto} 202181834Sroberto 203285612Sdelphijstatic int 204285612Sdelphijfailtest(struct ni_softc *sc, int reg, int mask, int test, const char *str) 205285612Sdelphij{ 206285612Sdelphij int i = 100; 207181834Sroberto 208181834Sroberto do { 209181834Sroberto DELAY(100000); 210181834Sroberto } while (((NI_RREG(reg) & mask) != test) && --i); 211181834Sroberto 212181834Sroberto if (i == 0) { 213181834Sroberto printf("%s: %s\n", device_xname(sc->sc_dev), str); 214181834Sroberto return 1; 215181834Sroberto } 216181834Sroberto return 0; 217181834Sroberto} 218181834Sroberto 219181834Sroberto 220181834Sroberto/* 221181834Sroberto * Interface exists: make available by filling in network interface 222181834Sroberto * record. System will initialize the interface when it is ready 223181834Sroberto * to accept packets. 224181834Sroberto */ 225181834Srobertostatic void 226181834Srobertoniattach(device_t parent, device_t self, void *aux) 227181834Sroberto{ 228181834Sroberto struct bi_attach_args *ba = aux; 229181834Sroberto struct ni_softc *sc = device_private(self); 230181834Sroberto struct ifnet *ifp = (struct ifnet *)&sc->sc_if; 231181834Sroberto struct ni_msg *msg; 232181834Sroberto struct ni_ptdb *ptdb; 233181834Sroberto void *va; 234181834Sroberto int i, j, s; 235181834Sroberto u_short type; 236181834Sroberto 237181834Sroberto sc->sc_dev = self; 238181834Sroberto 239181834Sroberto type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE); 240181834Sroberto aprint_normal(": DEBN%c\n", type == BIDT_DEBNA ? 'A' 241181834Sroberto : type == BIDT_DEBNT ? 'T' : 'K'); 242181834Sroberto sc->sc_iot = ba->ba_iot; 243181834Sroberto sc->sc_ioh = ba->ba_ioh; 244181834Sroberto sc->sc_dmat = ba->ba_dmat; 245181834Sroberto 246181834Sroberto bi_intr_establish(ba->ba_icookie, ba->ba_ivec, 247181834Sroberto niintr, sc, &sc->sc_intrcnt); 248181834Sroberto evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 249181834Sroberto device_xname(self), "intr"); 250181834Sroberto 251181834Sroberto ni_getpgs(sc, sizeof(struct ni_gvppqb), (void **)&sc->sc_gvppqb, 252181834Sroberto (paddr_t *)&sc->sc_pgvppqb); 253181834Sroberto ni_getpgs(sc, sizeof(struct ni_fqb), (void **)&sc->sc_fqb, 0); 254181834Sroberto ni_getpgs(sc, NBDESCS * sizeof(struct ni_bbd), 255285612Sdelphij (void **)&sc->sc_bbd, 0); 256285612Sdelphij /* 257285612Sdelphij * Zero the newly allocated memory. 258181834Sroberto */ 259181834Sroberto 260181834Sroberto nipqb->np_veclvl = (ba->ba_ivec << 2) + 2; 261181834Sroberto nipqb->np_node = ba->ba_intcpu; 262181834Sroberto nipqb->np_vpqb = (uint32_t)gvp; 263181834Sroberto#ifdef __vax__ 264181834Sroberto nipqb->np_spt = nipqb->np_gpt = mfpr(PR_SBR); 265181834Sroberto nipqb->np_sptlen = nipqb->np_gptlen = mfpr(PR_SLR); 266181834Sroberto#else 267181834Sroberto#error Must fix support for non-vax. 268181834Sroberto#endif 269181834Sroberto nipqb->np_bvplvl = 1; 270181834Sroberto nipqb->np_vfqb = (uint32_t)fqb; 271285612Sdelphij nipqb->np_vbdt = (uint32_t)bbd; 272285612Sdelphij nipqb->np_nbdr = NBDESCS; 273285612Sdelphij 274285612Sdelphij /* Free queue block */ 275181834Sroberto nipqb->np_freeq = NQUEUES; 276181834Sroberto fqb->nf_mlen = PKTHDR+MSGADD; 277181834Sroberto fqb->nf_dlen = PKTHDR+TXADD; 278181834Sroberto fqb->nf_rlen = PKTHDR+RXADD; 279181834Sroberto 280181834Sroberto strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 281181834Sroberto ifp->if_softc = sc; 282181834Sroberto ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 283285612Sdelphij ifp->if_start = nistart; 284285612Sdelphij ifp->if_ioctl = niioctl; 285285612Sdelphij ifp->if_watchdog = nitimeout; 286285612Sdelphij IFQ_SET_READY(&ifp->if_snd); 287181834Sroberto 288181834Sroberto /* 289181834Sroberto * Start init sequence. 290181834Sroberto */ 291285612Sdelphij 292285612Sdelphij /* Reset the node */ 293285612Sdelphij NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST); 294285612Sdelphij DELAY(500000); 295285612Sdelphij i = 20; 296285612Sdelphij while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i) 297285612Sdelphij DELAY(500000); 298285612Sdelphij if (i == 0) { 299285612Sdelphij aprint_error_dev(self, "BROKE bit set after reset\n"); 300285612Sdelphij return; 301285612Sdelphij } 302285612Sdelphij 303181834Sroberto /* Check state */ 304181834Sroberto if (failtest(sc, NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state")) 305181834Sroberto return; 306181834Sroberto 307181834Sroberto /* Clear owner bits */ 308181834Sroberto NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); 309181834Sroberto NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN); 310181834Sroberto 311181834Sroberto /* kick off init */ 312181834Sroberto NI_WREG(NI_PCR, (uint32_t)sc->sc_pgvppqb | PCR_INIT | PCR_OWN); 313181834Sroberto while (NI_RREG(NI_PCR) & PCR_OWN) 314285612Sdelphij DELAY(100000); 315181834Sroberto 316181834Sroberto /* Check state */ 317181834Sroberto if (failtest(sc, NI_PSR, PSR_INITED, PSR_INITED, "failed initialize")) 318181834Sroberto return; 319181834Sroberto 320181834Sroberto NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); 321181834Sroberto 322181834Sroberto WAITREG(NI_PCR, PCR_OWN); 323181834Sroberto NI_WREG(NI_PCR, PCR_OWN | PCR_ENABLE); 324181834Sroberto WAITREG(NI_PCR, PCR_OWN); 325181834Sroberto WAITREG(NI_PSR, PSR_OWN); 326181834Sroberto 327285612Sdelphij /* Check state */ 328181834Sroberto if (failtest(sc, NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable")) 329181834Sroberto return; 330181834Sroberto 331285612Sdelphij NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); 332181834Sroberto 333181834Sroberto /* 334285612Sdelphij * The message queue packets must be located on the beginning 335181834Sroberto * of a page. A VAX page is 512 bytes, but it clusters 8 pages. 336285612Sdelphij * This knowledge is used here when allocating pages. 337285612Sdelphij * !!! How should this be done on MIPS and Alpha??? !!! 338285612Sdelphij */ 339181834Sroberto#if NBPG < 4096 340181834Sroberto#error pagesize too small 341285612Sdelphij#endif 342181834Sroberto s = splvm(); 343285612Sdelphij /* Set up message free queue */ 344181834Sroberto ni_getpgs(sc, NMSGBUF * 512, &va, 0); 345181834Sroberto for (i = 0; i < NMSGBUF; i++) { 346181834Sroberto msg = (void *)((char *)va + i * 512); 347181834Sroberto INSQTI(msg, &fqb->nf_mforw); 348181834Sroberto } 349181834Sroberto WAITREG(NI_PCR, PCR_OWN); 350181834Sroberto NI_WREG(NI_PCR, PCR_FREEQNE | PCR_MFREEQ | PCR_OWN); 351181834Sroberto WAITREG(NI_PCR, PCR_OWN); 352181834Sroberto 353285612Sdelphij /* Set up xmit queue */ 354285612Sdelphij ni_getpgs(sc, NTXBUF * 512, &va, 0); 355181834Sroberto for (i = 0; i < NTXBUF; i++) { 356181834Sroberto struct ni_dg *data; 357285612Sdelphij 358181834Sroberto data = (void *)((char *)va + i * 512); 359181834Sroberto data->nd_status = 0; 360181834Sroberto data->nd_len = TXADD; 361181834Sroberto data->nd_ptdbidx = 1; 362181834Sroberto data->nd_opcode = BVP_DGRAM; 363181834Sroberto for (j = 0; j < NTXFRAGS; j++) { 364181834Sroberto data->bufs[j]._offset = 0; 365181834Sroberto data->bufs[j]._key = 1; 366181834Sroberto bbd[i * NTXFRAGS + j].nb_key = 1; 367181834Sroberto bbd[i * NTXFRAGS + j].nb_status = 0; 368285612Sdelphij data->bufs[j]._index = i * NTXFRAGS + j; 369181834Sroberto } 370181834Sroberto INSQTI(data, &fqb->nf_dforw); 371181834Sroberto } 372285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 373181834Sroberto NI_WREG(NI_PCR, PCR_FREEQNE | PCR_DFREEQ | PCR_OWN); 374181834Sroberto WAITREG(NI_PCR, PCR_OWN); 375181834Sroberto 376285612Sdelphij /* recv buffers */ 377285612Sdelphij ni_getpgs(sc, NRXBUF * 512, &va, 0); 378285612Sdelphij for (i = 0; i < NRXBUF; i++) { 379285612Sdelphij struct ni_dg *data; 380285612Sdelphij int idx; 381285612Sdelphij 382285612Sdelphij data = (void *)((char *)va + i * 512); 383285612Sdelphij data->nd_len = RXADD; 384285612Sdelphij data->nd_opcode = BVP_DGRAMRX; 385181834Sroberto data->nd_ptdbidx = 2; 386285612Sdelphij data->bufs[0]._key = 1; 387285612Sdelphij 388285612Sdelphij idx = NTXBUF * NTXFRAGS + i; 389285612Sdelphij if (ni_add_rxbuf(sc, data, idx)) 390181834Sroberto panic("niattach: ni_add_rxbuf: out of mbufs"); 391285612Sdelphij 392181834Sroberto INSQTI(data, &fqb->nf_rforw); 393285612Sdelphij } 394285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 395181834Sroberto NI_WREG(NI_PCR, PCR_FREEQNE | PCR_RFREEQ | PCR_OWN); 396181834Sroberto WAITREG(NI_PCR, PCR_OWN); 397181834Sroberto 398285612Sdelphij splx(s); 399285612Sdelphij 400181834Sroberto /* Set initial parameters */ 401181834Sroberto msg = REMQHI(&fqb->nf_mforw); 402181834Sroberto 403181834Sroberto msg->nm_opcode = BVP_MSG; 404285612Sdelphij msg->nm_status = 0; 405181834Sroberto msg->nm_len = sizeof(struct ni_param) + 6; 406285612Sdelphij msg->nm_opcode2 = NI_WPARAM; 407285612Sdelphij ((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD; 408285612Sdelphij 409285612Sdelphij endwait = retry = 0; 410285612Sdelphij INSQTI(msg, &gvp->nc_forw0); 411181834Sroberto 412181834Srobertoretry: WAITREG(NI_PCR, PCR_OWN); 413181834Sroberto NI_WREG(NI_PCR, PCR_CMDQNE | PCR_CMDQ0 | PCR_OWN); 414181834Sroberto WAITREG(NI_PCR, PCR_OWN); 415285612Sdelphij i = 1000; 416181834Sroberto while (endwait == 0 && --i) 417285612Sdelphij DELAY(10000); 418285612Sdelphij 419285612Sdelphij if (endwait == 0) { 420285612Sdelphij if (++retry < 3) 421285612Sdelphij goto retry; 422285612Sdelphij aprint_error_dev(self, "no response to set params\n"); 423285612Sdelphij return; 424285612Sdelphij } 425181834Sroberto 426285612Sdelphij /* Clear counters */ 427285612Sdelphij msg = REMQHI(&fqb->nf_mforw); 428285612Sdelphij msg->nm_opcode = BVP_MSG; 429181834Sroberto msg->nm_status = 0; 430285612Sdelphij msg->nm_len = sizeof(struct ni_param) + 6; 431285612Sdelphij msg->nm_opcode2 = NI_RCCNTR; 432285612Sdelphij 433285612Sdelphij INSQTI(msg, &gvp->nc_forw0); 434285612Sdelphij 435285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 436285612Sdelphij NI_WREG(NI_PCR, PCR_CMDQNE | PCR_CMDQ0 | PCR_OWN); 437285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 438285612Sdelphij 439285612Sdelphij /* Enable transmit logic */ 440285612Sdelphij msg = REMQHI(&fqb->nf_mforw); 441285612Sdelphij 442285612Sdelphij msg->nm_opcode = BVP_MSG; 443285612Sdelphij msg->nm_status = 0; 444285612Sdelphij msg->nm_len = 18; 445285612Sdelphij msg->nm_opcode2 = NI_STPTDB; 446285612Sdelphij ptdb = (struct ni_ptdb *)&msg->nm_text[0]; 447285612Sdelphij memset(ptdb, 0, sizeof(struct ni_ptdb)); 448285612Sdelphij ptdb->np_index = 1; 449285612Sdelphij ptdb->np_fque = 1; 450285612Sdelphij 451285612Sdelphij INSQTI(msg, &gvp->nc_forw0); 452285612Sdelphij 453285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 454285612Sdelphij NI_WREG(NI_PCR, PCR_CMDQNE | PCR_CMDQ0 | PCR_OWN); 455285612Sdelphij WAITREG(NI_PCR, PCR_OWN); 456285612Sdelphij 457285612Sdelphij /* Wait for everything to finish */ 458285612Sdelphij WAITREG(NI_PSR, PSR_OWN); 459285612Sdelphij 460181834Sroberto aprint_normal_dev(self, "hardware address %s\n", 461181834Sroberto ether_sprintf(sc->sc_enaddr)); 462181834Sroberto 463181834Sroberto /* 464285612Sdelphij * Attach the interface. 465181834Sroberto */ 466 if_attach(ifp); 467 ether_ifattach(ifp, sc->sc_enaddr); 468 if (shutdownhook_establish(ni_shutdown, sc) == 0) 469 aprint_error_dev(self, 470 "WARNING: unable to establish shutdown hook\n"); 471} 472 473/* 474 * Initialization of interface. 475 */ 476void 477niinit(struct ni_softc *sc) 478{ 479 struct ifnet *ifp = &sc->sc_if; 480 481 /* 482 * Set flags (so ni_setup() do the right thing). 483 */ 484 ifp->if_flags |= IFF_RUNNING; 485 486 /* 487 * Send setup messages so that the rx/tx locic starts. 488 */ 489 ni_setup(sc); 490 491} 492 493/* 494 * Start output on interface. 495 */ 496void 497nistart(struct ifnet *ifp) 498{ 499 struct ni_softc *sc = ifp->if_softc; 500 struct ni_dg *data; 501 struct ni_bbd *bdp; 502 struct mbuf *m, *m0; 503 int i, cnt, res, mlen; 504 505#ifdef DEBUG 506 if (ifp->if_flags & IFF_DEBUG) 507 printf("%s: nistart\n", device_xname(sc->sc_dev)); 508#endif 509 510 while (fqb->nf_dforw) { 511 IFQ_POLL(&ifp->if_snd, m); 512 if (m == 0) 513 break; 514 515 data = REMQHI(&fqb->nf_dforw); 516 if ((int)data == Q_EMPTY) { 517 break; 518 } 519 520 IFQ_DEQUEUE(&ifp->if_snd, m); 521 522 /* 523 * Count number of mbufs in chain. 524 * Always do DMA directly from mbufs, therefore the transmit 525 * ring is really big. 526 */ 527 for (m0 = m, cnt = 0; m0; m0 = m0->m_next) 528 if (m0->m_len) 529 cnt++; 530 if (cnt > NTXFRAGS) 531 panic("nistart"); /* XXX */ 532 533 bpf_mtap(ifp, m, BPF_D_OUT); 534 bdp = &bbd[(data->bufs[0]._index & 0x7fff)]; 535 for (m0 = m, i = 0, mlen = 0; m0; m0 = m0->m_next) { 536 if (m0->m_len == 0) 537 continue; 538 bdp->nb_status = (mtod(m0, uint32_t) & NIBD_OFFSET) | 539 NIBD_VALID; 540 bdp->nb_pte = (uint32_t)kvtopte(mtod(m0, void *)); 541 bdp->nb_len = m0->m_len; 542 data->bufs[i]._offset = 0; 543 data->bufs[i]._len = bdp->nb_len; 544 data->bufs[i]._index |= NIDG_CHAIN; 545 mlen += bdp->nb_len; 546 bdp++; 547 i++; 548 } 549 data->nd_opcode = BVP_DGRAM; 550 data->nd_pad3 = 1; 551 data->nd_ptdbidx = 1; 552 data->nd_len = 10 + i * 8; 553 data->bufs[i - 1]._index &= ~NIDG_CHAIN; 554 data->nd_cmdref = (uint32_t)m; 555#ifdef DEBUG 556 if (ifp->if_flags & IFF_DEBUG) 557 printf("%s: sending %d bytes (%d segments)\n", 558 device_xname(sc->sc_dev), mlen, i); 559#endif 560 561 res = INSQTI(data, &gvp->nc_forw0); 562 if (res == Q_EMPTY) { 563 WAITREG(NI_PCR, PCR_OWN); 564 NI_WREG(NI_PCR, PCR_CMDQNE | PCR_CMDQ0 | PCR_OWN); 565 } 566 } 567} 568 569void 570niintr(void *arg) 571{ 572 struct ni_softc *sc = arg; 573 struct ni_dg *data; 574 struct ni_msg *msg; 575 struct ifnet *ifp = &sc->sc_if; 576 struct ni_bbd *bd; 577 struct mbuf *m; 578 int idx, res; 579 580 if ((NI_RREG(NI_PSR) & PSR_STATE) != PSR_ENABLED) 581 return; 582 583 if ((NI_RREG(NI_PSR) & PSR_ERR)) 584 printf("%s: PSR %x\n", device_xname(sc->sc_dev), 585 NI_RREG(NI_PSR)); 586 587 KERNEL_LOCK(1, NULL); 588 /* Got any response packets? */ 589 while ((NI_RREG(NI_PSR) & PSR_RSQ) && (data = REMQHI(&gvp->nc_forwr))) { 590 591 switch (data->nd_opcode) { 592 case BVP_DGRAMRX: /* Receive datagram */ 593 idx = data->bufs[0]._index; 594 bd = &bbd[idx]; 595 m = (void *)data->nd_cmdref; 596 m->m_pkthdr.len = m->m_len = 597 data->bufs[0]._len - ETHER_CRC_LEN; 598 m_set_rcvif(m, ifp); 599 if (ni_add_rxbuf(sc, data, idx)) { 600 bd->nb_len = (m->m_ext.ext_size - 2); 601 bd->nb_pte = 602 (long)kvtopte(m->m_ext.ext_buf); 603 bd->nb_status = 2 | NIBD_VALID; 604 bd->nb_key = 1; 605 } 606 data->nd_len = RXADD; 607 data->nd_status = 0; 608 res = INSQTI(data, &fqb->nf_rforw); 609 if (res == Q_EMPTY) { 610 WAITREG(NI_PCR, PCR_OWN); 611 NI_WREG(NI_PCR, 612 PCR_FREEQNE | PCR_RFREEQ | PCR_OWN); 613 } 614 if (m == (void *)data->nd_cmdref) 615 break; /* Out of mbufs */ 616 617 if_percpuq_enqueue(ifp->if_percpuq, m); 618 break; 619 620 case BVP_DGRAM: 621 m = (struct mbuf *)data->nd_cmdref; 622 m_freem(m); 623 res = INSQTI(data, &fqb->nf_dforw); 624 if (res == Q_EMPTY) { 625 WAITREG(NI_PCR, PCR_OWN); 626 NI_WREG(NI_PCR, 627 PCR_FREEQNE | PCR_DFREEQ | PCR_OWN); 628 } 629 break; 630 631 case BVP_MSGRX: 632 msg = (struct ni_msg *)data; 633 switch (msg->nm_opcode2) { 634 case NI_WPARAM: 635 memcpy(sc->sc_enaddr, ((struct ni_param *)&msg->nm_text[0])->np_dpa, ETHER_ADDR_LEN); 636 endwait = 1; 637 break; 638 639 case NI_RCCNTR: 640 case NI_CLPTDB: 641 case NI_STPTDB: 642 break; 643 644 default: 645 printf("Unkn resp %d\n", 646 msg->nm_opcode2); 647 break; 648 } 649 res = INSQTI(data, &fqb->nf_mforw); 650 if (res == Q_EMPTY) { 651 WAITREG(NI_PCR, PCR_OWN); 652 NI_WREG(NI_PCR, 653 PCR_FREEQNE | PCR_MFREEQ | PCR_OWN); 654 } 655 break; 656 657 default: 658 printf("Unknown opcode %d\n", data->nd_opcode); 659 res = INSQTI(data, &fqb->nf_mforw); 660 if (res == Q_EMPTY) { 661 WAITREG(NI_PCR, PCR_OWN); 662 NI_WREG(NI_PCR, 663 PCR_FREEQNE | PCR_MFREEQ | PCR_OWN); 664 } 665 } 666 } 667 668 /* Try to kick on the start routine again */ 669 nistart(ifp); 670 671 NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN | PSR_RSQ)); 672 KERNEL_UNLOCK_ONE(NULL); 673} 674 675/* 676 * Process an ioctl request. 677 */ 678int 679niioctl(struct ifnet *ifp, u_long cmd, void *data) 680{ 681 struct ni_softc *sc = ifp->if_softc; 682 struct ifaddr *ifa = (struct ifaddr *)data; 683 int s = splnet(), error = 0; 684 685 switch (cmd) { 686 687 case SIOCINITIFADDR: 688 ifp->if_flags |= IFF_UP; 689 switch (ifa->ifa_addr->sa_family) { 690#ifdef INET 691 case AF_INET: 692 niinit(sc); 693 arp_ifinit(ifp, ifa); 694 break; 695#endif 696 } 697 break; 698 699 case SIOCSIFFLAGS: 700 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 701 break; 702 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 703 case IFF_RUNNING: 704 /* 705 * If interface is marked down and it is running, 706 * stop it. 707 */ 708 ifp->if_flags &= ~IFF_RUNNING; 709 ni_setup(sc); 710 break; 711 case IFF_UP: 712 /* 713 * If interface it marked up and it is stopped, then 714 * start it. 715 */ 716 niinit(sc); 717 break; 718 case IFF_UP | IFF_RUNNING: 719 /* 720 * Send a new setup packet to match any new changes. 721 * (Like IFF_PROMISC etc) 722 */ 723 ni_setup(sc); 724 break; 725 default: 726 break; 727 } 728 break; 729 730 case SIOCADDMULTI: 731 case SIOCDELMULTI: 732 /* 733 * Update our multicast list. 734 */ 735 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 736 /* 737 * Multicast list has changed; set the hardware filter 738 * accordingly. 739 */ 740 if (ifp->if_flags & IFF_RUNNING) 741 ni_setup(sc); 742 error = 0; 743 } 744 break; 745 746 default: 747 error = ether_ioctl(ifp, cmd, data); 748 break; 749 } 750 splx(s); 751 return error; 752} 753 754/* 755 * Add a receive buffer to the indicated descriptor. 756 */ 757int 758ni_add_rxbuf(struct ni_softc *sc, struct ni_dg *data, int idx) 759{ 760 struct ni_bbd *bd = &bbd[idx]; 761 struct mbuf *m; 762 763 MGETHDR(m, M_DONTWAIT, MT_DATA); 764 if (m == NULL) 765 return ENOBUFS; 766 767 MCLGET(m, M_DONTWAIT); 768 if ((m->m_flags & M_EXT) == 0) { 769 m_freem(m); 770 return ENOBUFS; 771 } 772 773 m->m_data += 2; 774 bd->nb_len = (m->m_ext.ext_size - 2); 775 bd->nb_pte = (long)kvtopte(m->m_ext.ext_buf); 776 bd->nb_status = 2 | NIBD_VALID; 777 bd->nb_key = 1; 778 779 data->bufs[0]._offset = 0; 780 data->bufs[0]._len = bd->nb_len; 781 data->bufs[0]._index = idx; 782 data->nd_cmdref = (long)m; 783 784 return 0; 785} 786 787/* 788 * Create setup packet and put in queue for sending. 789 */ 790void 791ni_setup(struct ni_softc *sc) 792{ 793 struct ethercom *ec = &sc->sc_ec; 794 struct ifnet *ifp = &sc->sc_if; 795 struct ni_msg *msg; 796 struct ni_ptdb *ptdb; 797 struct ether_multi *enm; 798 struct ether_multistep step; 799 int i, res; 800 801 msg = REMQHI(&fqb->nf_mforw); 802 if ((int)msg == Q_EMPTY) 803 return; /* What to do? */ 804 805 ptdb = (struct ni_ptdb *)&msg->nm_text[0]; 806 memset(ptdb, 0, sizeof(struct ni_ptdb)); 807 808 msg->nm_opcode = BVP_MSG; 809 msg->nm_len = 18; 810 ptdb->np_index = 2; /* definition type index */ 811 ptdb->np_fque = 2; /* Free queue */ 812 if (ifp->if_flags & IFF_RUNNING) { 813 msg->nm_opcode2 = NI_STPTDB; 814 ptdb->np_type = ETHERTYPE_IP; 815 ptdb->np_flags = PTDB_UNKN | PTDB_BDC; 816 if (ifp->if_flags & IFF_PROMISC) 817 ptdb->np_flags |= PTDB_PROMISC; 818 memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); /* Broadcast */ 819 ptdb->np_adrlen = 1; 820 msg->nm_len += 8; 821 ifp->if_flags &= ~IFF_ALLMULTI; 822 if ((ifp->if_flags & IFF_PROMISC) == 0) { 823 ETHER_LOCK(ec); 824 ETHER_FIRST_MULTI(step, ec, enm); 825 i = 1; 826 while (enm != NULL) { 827 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) { 828 ifp->if_flags |= IFF_ALLMULTI; 829 ptdb->np_flags |= PTDB_AMC; 830 break; 831 } 832 msg->nm_len += 8; 833 ptdb->np_adrlen++; 834 memcpy(ptdb->np_mcast[i++], enm->enm_addrlo, 835 ETHER_ADDR_LEN); 836 ETHER_NEXT_MULTI(step, enm); 837 } 838 ETHER_UNLOCK(ec); 839 } 840 } else 841 msg->nm_opcode2 = NI_CLPTDB; 842 843 res = INSQTI(msg, &gvp->nc_forw0); 844 if (res == Q_EMPTY) { 845 WAITREG(NI_PCR, PCR_OWN); 846 NI_WREG(NI_PCR, PCR_CMDQNE | PCR_CMDQ0 | PCR_OWN); 847 } 848} 849 850/* 851 * Check for dead transmit logic. Not uncommon. 852 */ 853void 854nitimeout(struct ifnet *ifp) 855{ 856#if 0 857 struct ni_softc *sc = ifp->if_softc; 858 859 if (sc->sc_inq == 0) 860 return; 861 862 printf("%s: xmit logic died, resetting...\n", device_xname(sc->sc_dev)); 863 /* 864 * Do a reset of interface, to get it going again. 865 * Will it work by just restart the transmit logic? 866 */ 867 niinit(sc); 868#endif 869} 870 871/* 872 * Shutdown hook. Make sure the interface is stopped at reboot. 873 */ 874void 875ni_shutdown(void *arg) 876{ 877 struct ni_softc *sc = arg; 878 879 WAITREG(NI_PCR, PCR_OWN); 880 NI_WREG(NI_PCR, PCR_OWN | PCR_SHUTDOWN); 881 WAITREG(NI_PCR, PCR_OWN); 882 WAITREG(NI_PSR, PSR_OWN); 883} 884