137939Skjc/* $NetBSD: midway.c,v 1.30 1997/09/29 17:40:38 chuck Exp $ */ 237939Skjc/* (sync'd to midway.c 1.68) */ 325603Skjc 4139749Simp/*- 525603Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University. 625603Skjc * All rights reserved. 725603Skjc * 825603Skjc * Redistribution and use in source and binary forms, with or without 925603Skjc * modification, are permitted provided that the following conditions 1025603Skjc * are met: 1125603Skjc * 1. Redistributions of source code must retain the above copyright 1225603Skjc * notice, this list of conditions and the following disclaimer. 1325603Skjc * 2. Redistributions in binary form must reproduce the above copyright 1425603Skjc * notice, this list of conditions and the following disclaimer in the 1525603Skjc * documentation and/or other materials provided with the distribution. 1625603Skjc * 3. All advertising materials mentioning features or use of this software 1725603Skjc * must display the following acknowledgement: 1825603Skjc * This product includes software developed by Charles D. Cranor and 1925603Skjc * Washington University. 2025603Skjc * 4. The name of the author may not be used to endorse or promote products 2125603Skjc * derived from this software without specific prior written permission. 2225603Skjc * 2325603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2425603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2525603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2625603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2725603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2825603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2925603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3025603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3125603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3225603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3325603Skjc */ 34118489Sharti#include <sys/cdefs.h> 35118489Sharti__FBSDID("$FreeBSD$"); 3625603Skjc 3725603Skjc/* 3825603Skjc * 3925603Skjc * m i d w a y . c e n i 1 5 5 d r i v e r 4025603Skjc * 4125603Skjc * author: Chuck Cranor <chuck@ccrc.wustl.edu> 4225603Skjc * started: spring, 1996 (written from scratch). 4325603Skjc * 4425603Skjc * notes from the author: 4525603Skjc * Extra special thanks go to Werner Almesberger, EPFL LRC. Werner's 4625603Skjc * ENI driver was especially useful in figuring out how this card works. 4725603Skjc * I would also like to thank Werner for promptly answering email and being 4825603Skjc * generally helpful. 4925603Skjc */ 5025603Skjc 5125603Skjc#define EN_DIAG 5225603Skjc#define EN_DDBHOOK 1 /* compile in ddb functions */ 5325603Skjc 5437939Skjc/* 55114018Sharti * Note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card 5637939Skjc * appears to be broken. it works just fine if there is no load... however 5737939Skjc * when the card is loaded the data get corrupted. to see this, one only 5837939Skjc * has to use "telnet" over ATM. do the following command in "telnet": 5937939Skjc * cat /usr/share/misc/termcap 6037939Skjc * "telnet" seems to generate lots of 1023 byte mbufs (which make great 6137939Skjc * use of the byte aligner). watch "netstat -s" for checksum errors. 6237939Skjc * 6337939Skjc * I further tested this by adding a function that compared the transmit 6437939Skjc * data on the card's SRAM with the data in the mbuf chain _after_ the 6537939Skjc * "transmit DMA complete" interrupt. using the "telnet" test I got data 6637939Skjc * mismatches where the byte-aligned data should have been. using ddb 6737939Skjc * and en_dumpmem() I verified that the DTQs fed into the card were 6837939Skjc * absolutely correct. thus, we are forced to concluded that the ENI 6937939Skjc * hardware is buggy. note that the Adaptec version of the card works 7037939Skjc * just fine with byte DMA. 7137939Skjc * 7237939Skjc * bottom line: we set EN_ENIDMAFIX to 1 to avoid byte DMAs on the ENI 7337939Skjc * card. 7437939Skjc */ 7537939Skjc 7625603Skjc#if defined(DIAGNOSTIC) && !defined(EN_DIAG) 7725603Skjc#define EN_DIAG /* link in with master DIAG option */ 7825603Skjc#endif 79114018Sharti 8025603Skjc#define EN_COUNT(X) (X)++ 8125603Skjc 8225603Skjc#ifdef EN_DEBUG 83114018Sharti 8425603Skjc#undef EN_DDBHOOK 8525603Skjc#define EN_DDBHOOK 1 86114018Sharti 87114018Sharti/* 88114018Sharti * This macro removes almost all the EN_DEBUG conditionals in the code that make 89114018Sharti * to code a good deal less readable. 90114018Sharti */ 91114018Sharti#define DBG(SC, FL, PRINT) do { \ 92114018Sharti if ((SC)->debug & DBG_##FL) { \ 93162321Sglebius device_printf((SC)->dev, "%s: "#FL": ", __func__); \ 94114018Sharti printf PRINT; \ 95114018Sharti printf("\n"); \ 96114018Sharti } \ 97114018Sharti } while (0) 98114018Sharti 99114018Shartienum { 100114018Sharti DBG_INIT = 0x0001, /* debug attach/detach */ 101114018Sharti DBG_TX = 0x0002, /* debug transmitting */ 102114018Sharti DBG_SERV = 0x0004, /* debug service interrupts */ 103114018Sharti DBG_IOCTL = 0x0008, /* debug ioctls */ 104114018Sharti DBG_VC = 0x0010, /* debug VC handling */ 105114018Sharti DBG_INTR = 0x0020, /* debug interrupts */ 106114018Sharti DBG_DMA = 0x0040, /* debug DMA probing */ 107114018Sharti DBG_IPACKETS = 0x0080, /* print input packets */ 108114018Sharti DBG_REG = 0x0100, /* print all register access */ 109114018Sharti DBG_LOCK = 0x0200, /* debug locking */ 110114018Sharti}; 111114018Sharti 11225603Skjc#else /* EN_DEBUG */ 113114018Sharti 114114018Sharti#define DBG(SC, FL, PRINT) do { } while (0) 115114018Sharti 11625603Skjc#endif /* EN_DEBUG */ 11725603Skjc 11832350Seivind#include "opt_inet.h" 11932925Seivind#include "opt_natm.h" 12046695Skjc#include "opt_ddb.h" 121114018Sharti 122114018Sharti#ifdef DDB 12346695Skjc#undef EN_DDBHOOK 12446695Skjc#define EN_DDBHOOK 1 12525603Skjc#endif 12625603Skjc 12725603Skjc#include <sys/param.h> 12825603Skjc#include <sys/systm.h> 12937939Skjc#include <sys/queue.h> 13025603Skjc#include <sys/sockio.h> 131114018Sharti#include <sys/socket.h> 13225603Skjc#include <sys/mbuf.h> 133114018Sharti#include <sys/endian.h> 134114018Sharti#include <sys/stdint.h> 135118487Sharti#include <sys/lock.h> 136118487Sharti#include <sys/mutex.h> 137118494Sharti#include <sys/condvar.h> 138114018Sharti#include <vm/uma.h> 13925603Skjc 14025603Skjc#include <net/if.h> 141114739Sharti#include <net/if_media.h> 14225603Skjc#include <net/if_atm.h> 14325603Skjc 144184712Sbz#if defined(NATM) || defined(INET) || defined(INET6) 145184712Sbz#include <netinet/in.h> 14637939Skjc#if defined(INET) || defined(INET6) 14725603Skjc#include <netinet/if_atm.h> 14825603Skjc#endif 149184712Sbz#endif 15025603Skjc 15125603Skjc#ifdef NATM 15225603Skjc#include <netnatm/natm.h> 15325603Skjc#endif 15425603Skjc 15568432Skjc#include <sys/bus.h> 15668432Skjc#include <machine/bus.h> 15768432Skjc#include <sys/rman.h> 158114018Sharti#include <sys/module.h> 159114018Sharti#include <sys/sysctl.h> 160114018Sharti#include <sys/malloc.h> 16168432Skjc#include <machine/resource.h> 162116294Sharti#include <dev/utopia/utopia.h> 16325603Skjc#include <dev/en/midwayreg.h> 16425603Skjc#include <dev/en/midwayvar.h> 16525603Skjc 16637939Skjc#include <net/bpf.h> 16737939Skjc 16825603Skjc/* 16925603Skjc * params 17025603Skjc */ 17125603Skjc#ifndef EN_TXHIWAT 172114018Sharti#define EN_TXHIWAT (64 * 1024) /* max 64 KB waiting to be DMAd out */ 17325603Skjc#endif 17425603Skjc 175114201ShartiSYSCTL_DECL(_hw_atm); 17625603Skjc 17725603Skjc/* 178114018Sharti * dma tables 17925603Skjc * 180114018Sharti * The plan is indexed by the number of words to transfer. 181114018Sharti * The maximum index is 15 for 60 words. 18225603Skjc */ 18325603Skjcstruct en_dmatab { 184114018Sharti uint8_t bcode; /* code */ 185114018Sharti uint8_t divshift; /* byte divisor */ 18625603Skjc}; 18725603Skjc 188114018Shartistatic const struct en_dmatab en_dmaplan[] = { 18925603Skjc { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2}, /* 1 */ 19025603Skjc { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_WORD, 2}, /* 3 */ 19125603Skjc { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_WORD, 2}, /* 5 */ 19225603Skjc { MIDDMA_2WORD, 3}, /* 6 */ { MIDDMA_WORD, 2}, /* 7 */ 19325603Skjc { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_WORD, 2}, /* 9 */ 19425603Skjc { MIDDMA_2WORD, 3}, /* 10 */ { MIDDMA_WORD, 2}, /* 11 */ 19525603Skjc { MIDDMA_4WORD, 4}, /* 12 */ { MIDDMA_WORD, 2}, /* 13 */ 19625603Skjc { MIDDMA_2WORD, 3}, /* 14 */ { MIDDMA_WORD, 2}, /* 15 */ 197114018Sharti { MIDDMA_16WORD,6}, /* 16 */ 19825603Skjc}; 19925603Skjc 20025603Skjc/* 20125603Skjc * prototypes 20225603Skjc */ 20325603Skjc#ifdef EN_DDBHOOK 204114018Shartiint en_dump(int unit, int level); 205114018Shartiint en_dumpmem(int,int,int); 20625603Skjc#endif 207118487Shartistatic void en_close_finish(struct en_softc *sc, struct en_vcc *vc); 20825603Skjc 209114018Sharti#define EN_LOCK(SC) do { \ 210114018Sharti DBG(SC, LOCK, ("ENLOCK %d\n", __LINE__)); \ 211114018Sharti mtx_lock(&sc->en_mtx); \ 212114018Sharti } while (0) 213114018Sharti#define EN_UNLOCK(SC) do { \ 214114018Sharti DBG(SC, LOCK, ("ENUNLOCK %d\n", __LINE__)); \ 215114018Sharti mtx_unlock(&sc->en_mtx); \ 216114018Sharti } while (0) 217116294Sharti#define EN_CHECKLOCK(sc) mtx_assert(&sc->en_mtx, MA_OWNED) 21825603Skjc 21925603Skjc/* 220114018Sharti * While a transmit mbuf is waiting to get transmit DMA resources we 221114018Sharti * need to keep some information with it. We don't want to allocate 222114018Sharti * additional memory for this so we stuff it into free fields in the 223114018Sharti * mbuf packet header. Neither the checksum fields nor the rcvif field are used 224114018Sharti * so use these. 22525603Skjc */ 226114018Sharti#define TX_AAL5 0x1 /* transmit AAL5 PDU */ 227114018Sharti#define TX_HAS_TBD 0x2 /* TBD did fit into mbuf */ 228114018Sharti#define TX_HAS_PAD 0x4 /* padding did fit into mbuf */ 229114018Sharti#define TX_HAS_PDU 0x8 /* PDU trailer did fit into mbuf */ 23025603Skjc 231114018Sharti#define MBUF_SET_TX(M, VCI, FLAGS, DATALEN, PAD, MAP) do { \ 232114018Sharti (M)->m_pkthdr.csum_data = (VCI) | ((FLAGS) << MID_VCI_BITS); \ 233114018Sharti (M)->m_pkthdr.csum_flags = ((DATALEN) & 0xffff) | \ 234114018Sharti ((PAD & 0x3f) << 16); \ 235114018Sharti (M)->m_pkthdr.rcvif = (void *)(MAP); \ 236114018Sharti } while (0) 23725603Skjc 238114018Sharti#define MBUF_GET_TX(M, VCI, FLAGS, DATALEN, PAD, MAP) do { \ 239114018Sharti (VCI) = (M)->m_pkthdr.csum_data & ((1 << MID_VCI_BITS) - 1); \ 240114018Sharti (FLAGS) = ((M)->m_pkthdr.csum_data >> MID_VCI_BITS) & 0xf; \ 241114018Sharti (DATALEN) = (M)->m_pkthdr.csum_flags & 0xffff; \ 242114018Sharti (PAD) = ((M)->m_pkthdr.csum_flags >> 16) & 0x3f; \ 243114018Sharti (MAP) = (void *)((M)->m_pkthdr.rcvif); \ 244114018Sharti } while (0) 24525603Skjc 24625603Skjc 247114018Sharti#define EN_WRAPADD(START, STOP, CUR, VAL) do { \ 248114018Sharti (CUR) = (CUR) + (VAL); \ 249114018Sharti if ((CUR) >= (STOP)) \ 250114018Sharti (CUR) = (START) + ((CUR) - (STOP)); \ 251114018Sharti } while (0) 25225603Skjc 253114018Sharti#define WORD_IDX(START, X) (((X) - (START)) / sizeof(uint32_t)) 25425603Skjc 255114018Sharti#define SETQ_END(SC, VAL) ((SC)->is_adaptec ? \ 256114018Sharti ((VAL) | (MID_DMA_END >> 4)) : \ 257114018Sharti ((VAL) | (MID_DMA_END))) 25825603Skjc 25925603Skjc/* 260114018Sharti * The dtq and drq members are set for each END entry in the corresponding 261114018Sharti * card queue entry. It is used to find out, when a buffer has been 262114018Sharti * finished DMAing and can be freed. 26325603Skjc * 264114018Sharti * We store sc->dtq and sc->drq data in the following format... 265114018Sharti * the 0x80000 ensures we != 0 26625603Skjc */ 267114018Sharti#define EN_DQ_MK(SLOT, LEN) (((SLOT) << 20) | (LEN) | (0x80000)) 268114018Sharti#define EN_DQ_SLOT(X) ((X) >> 20) 269114018Sharti#define EN_DQ_LEN(X) ((X) & 0x3ffff) 27025603Skjc 271118487Sharti/* 272118487Sharti * Variables 273118487Sharti */ 274118487Shartistatic uma_zone_t en_vcc_zone; 275118487Sharti 27625603Skjc/***********************************************************************/ 27725603Skjc 27825603Skjc/* 279114018Sharti * en_read{x}: read a word from the card. These are the only functions 280114018Sharti * that read from the card. 28125603Skjc */ 282114018Shartistatic __inline uint32_t 283114018Shartien_readx(struct en_softc *sc, uint32_t r) 284114018Sharti{ 285114018Sharti uint32_t v; 28625603Skjc 287114018Sharti#ifdef EN_DIAG 288114018Sharti if (r > MID_MAXOFF || (r % 4)) 289114018Sharti panic("en_read out of range, r=0x%x", r); 290114018Sharti#endif 291114018Sharti v = bus_space_read_4(sc->en_memt, sc->en_base, r); 292114018Sharti return (v); 293114018Sharti} 29425603Skjc 295114018Shartistatic __inline uint32_t 296114018Shartien_read(struct en_softc *sc, uint32_t r) 29725603Skjc{ 298114018Sharti uint32_t v; 29925603Skjc 300114018Sharti#ifdef EN_DIAG 301114018Sharti if (r > MID_MAXOFF || (r % 4)) 302114018Sharti panic("en_read out of range, r=0x%x", r); 30325603Skjc#endif 304114018Sharti v = bus_space_read_4(sc->en_memt, sc->en_base, r); 305114018Sharti DBG(sc, REG, ("en_read(%#x) -> %08x", r, v)); 306114018Sharti return (v); 30725603Skjc} 30825603Skjc 30925603Skjc/* 310114018Sharti * en_write: write a word to the card. This is the only function that 31125603Skjc * writes to the card. 31225603Skjc */ 313114018Shartistatic __inline void 314114018Shartien_write(struct en_softc *sc, uint32_t r, uint32_t v) 31525603Skjc{ 316114018Sharti#ifdef EN_DIAG 317114018Sharti if (r > MID_MAXOFF || (r % 4)) 318114018Sharti panic("en_write out of range, r=0x%x", r); 31925603Skjc#endif 320114018Sharti DBG(sc, REG, ("en_write(%#x) <- %08x", r, v)); 321114018Sharti bus_space_write_4(sc->en_memt, sc->en_base, r, v); 32225603Skjc} 32325603Skjc 32425603Skjc/* 32525603Skjc * en_k2sz: convert KBytes to a size parameter (a log2) 32625603Skjc */ 327114018Shartistatic __inline int 328114018Shartien_k2sz(int k) 32925603Skjc{ 330114018Sharti switch(k) { 331114018Sharti case 1: return (0); 332114018Sharti case 2: return (1); 333114018Sharti case 4: return (2); 334114018Sharti case 8: return (3); 335114018Sharti case 16: return (4); 336114018Sharti case 32: return (5); 337114018Sharti case 64: return (6); 338114018Sharti case 128: return (7); 339114018Sharti default: 340114018Sharti panic("en_k2sz"); 341114018Sharti } 342114018Sharti return (0); 34325603Skjc} 34425603Skjc#define en_log2(X) en_k2sz(X) 34525603Skjc 346260275Sdim#if 0 34725603Skjc/* 34825603Skjc * en_b2sz: convert a DMA burst code to its byte size 34925603Skjc */ 350114018Shartistatic __inline int 351114018Shartien_b2sz(int b) 35225603Skjc{ 353114018Sharti switch (b) { 354114018Sharti case MIDDMA_WORD: return (1*4); 355114018Sharti case MIDDMA_2WMAYBE: 356114018Sharti case MIDDMA_2WORD: return (2*4); 357114018Sharti case MIDDMA_4WMAYBE: 358114018Sharti case MIDDMA_4WORD: return (4*4); 359114018Sharti case MIDDMA_8WMAYBE: 360114018Sharti case MIDDMA_8WORD: return (8*4); 361114018Sharti case MIDDMA_16WMAYBE: 362114018Sharti case MIDDMA_16WORD: return (16*4); 363114018Sharti default: 364114018Sharti panic("en_b2sz"); 365114018Sharti } 366114018Sharti return (0); 36725603Skjc} 368260275Sdim#endif 36925603Skjc 37025603Skjc/* 37125603Skjc * en_sz2b: convert a burst size (bytes) to DMA burst code 37225603Skjc */ 373114018Shartistatic __inline int 374114018Shartien_sz2b(int sz) 37525603Skjc{ 376114018Sharti switch (sz) { 377114018Sharti case 1*4: return (MIDDMA_WORD); 378114018Sharti case 2*4: return (MIDDMA_2WORD); 379114018Sharti case 4*4: return (MIDDMA_4WORD); 380114018Sharti case 8*4: return (MIDDMA_8WORD); 381114018Sharti case 16*4: return (MIDDMA_16WORD); 382114018Sharti default: 383114018Sharti panic("en_sz2b"); 384114018Sharti } 385114018Sharti return(0); 38625603Skjc} 38725603Skjc 388114018Sharti#ifdef EN_DEBUG 38925603Skjc/* 390114018Sharti * Dump a packet 39125603Skjc */ 392114018Shartistatic void 393114018Shartien_dump_packet(struct en_softc *sc, struct mbuf *m) 39425603Skjc{ 395114018Sharti int plen = m->m_pkthdr.len; 396114018Sharti u_int pos = 0; 397114018Sharti u_int totlen = 0; 398114018Sharti int len; 399114018Sharti u_char *ptr; 40025603Skjc 401162321Sglebius device_printf(sc->dev, "packet len=%d", plen); 402114018Sharti while (m != NULL) { 403114018Sharti totlen += m->m_len; 404114018Sharti ptr = mtod(m, u_char *); 405114018Sharti for (len = 0; len < m->m_len; len++, pos++, ptr++) { 406114018Sharti if (pos % 16 == 8) 407114018Sharti printf(" "); 408114018Sharti if (pos % 16 == 0) 409114018Sharti printf("\n"); 410114018Sharti printf(" %02x", *ptr); 411114018Sharti } 412114018Sharti m = m->m_next; 413114018Sharti } 414114018Sharti printf("\n"); 415117227Sharti if (totlen != plen) 416114018Sharti printf("sum of m_len=%u\n", totlen); 417114018Sharti} 41825603Skjc#endif 41925603Skjc 420114018Sharti/*********************************************************************/ 421114018Sharti/* 422114018Sharti * DMA maps 423114018Sharti */ 42425603Skjc 425114018Sharti/* 426114018Sharti * Map constructor for a MAP. 427114018Sharti * 428114018Sharti * This is called each time when a map is allocated 429114018Sharti * from the pool and about to be returned to the user. Here we actually 430114018Sharti * allocate the map if there isn't one. The problem is that we may fail 431114018Sharti * to allocate the DMA map yet have no means to signal this error. Therefor 432114018Sharti * when allocating a map, the call must check that there is a map. An 433114018Sharti * additional problem is, that i386 maps will be NULL, yet are ok and must 434114018Sharti * be freed so let's use a flag to signal allocation. 435114018Sharti * 436114018Sharti * Caveat: we have no way to know that we are called from an interrupt context 437114018Sharti * here. We rely on the fact, that bus_dmamap_create uses M_NOWAIT in all 438114018Sharti * its allocations. 439114018Sharti * 440114018Sharti * LOCK: any, not needed 441114018Sharti */ 442132987Sgreenstatic int 443132987Sgreenen_map_ctor(void *mem, int size, void *arg, int flags) 444114018Sharti{ 445114018Sharti struct en_softc *sc = arg; 446114018Sharti struct en_map *map = mem; 447114018Sharti int err; 44825603Skjc 449132987Sgreen err = bus_dmamap_create(sc->txtag, 0, &map->map); 450132987Sgreen if (err != 0) { 451162321Sglebius device_printf(sc->dev, "cannot create DMA map %d\n", err); 452132987Sgreen return (err); 453114018Sharti } 454132987Sgreen map->flags = ENMAP_ALLOC; 455132987Sgreen map->sc = sc; 456132987Sgreen return (0); 45725603Skjc} 45825603Skjc 45925603Skjc/* 460114018Sharti * Map destructor. 461114018Sharti * 462114018Sharti * Called when a map is disposed into the zone. If the map is loaded, unload 463114018Sharti * it. 464114018Sharti * 465114018Sharti * LOCK: any, not needed 46625603Skjc */ 467114018Shartistatic void 468114018Shartien_map_dtor(void *mem, int size, void *arg) 469114018Sharti{ 470114018Sharti struct en_map *map = mem; 47125603Skjc 472114018Sharti if (map->flags & ENMAP_LOADED) { 473114018Sharti bus_dmamap_unload(map->sc->txtag, map->map); 474114018Sharti map->flags &= ~ENMAP_LOADED; 475114018Sharti } 476114018Sharti} 47725603Skjc 478114018Sharti/* 479114018Sharti * Map finializer. 480114018Sharti * 481114018Sharti * This is called each time a map is returned from the zone to the system. 482114018Sharti * Get rid of the dmamap here. 483114018Sharti * 484114018Sharti * LOCK: any, not needed 485114018Sharti */ 486114018Shartistatic void 487114018Shartien_map_fini(void *mem, int size) 48825603Skjc{ 489114018Sharti struct en_map *map = mem; 49025603Skjc 491132987Sgreen bus_dmamap_destroy(map->sc->txtag, map->map); 49225603Skjc} 49325603Skjc 494114018Sharti/*********************************************************************/ 495114018Sharti/* 496114018Sharti * Transmission 497114018Sharti */ 49825603Skjc 49925603Skjc/* 500114018Sharti * Argument structure to load a transmit DMA map 50125603Skjc */ 502114018Shartistruct txarg { 503114018Sharti struct en_softc *sc; 504114018Sharti struct mbuf *m; 505114018Sharti u_int vci; 506114018Sharti u_int chan; /* transmit channel */ 507114018Sharti u_int datalen; /* length of user data */ 508114018Sharti u_int flags; 509114018Sharti u_int wait; /* return: out of resources */ 510114018Sharti}; 51125603Skjc 512114018Sharti/* 513114018Sharti * TX DMA map loader helper. This function is the callback when the map 514114018Sharti * is loaded. It should fill the DMA segment descriptors into the hardware. 515114018Sharti * 516114018Sharti * LOCK: locked, needed 517114018Sharti */ 518114018Shartistatic void 519114018Shartien_txdma_load(void *uarg, bus_dma_segment_t *segs, int nseg, bus_size_t mapsize, 520114018Sharti int error) 521114018Sharti{ 522114018Sharti struct txarg *tx = uarg; 523114018Sharti struct en_softc *sc = tx->sc; 524114018Sharti struct en_txslot *slot = &sc->txslot[tx->chan]; 525114018Sharti uint32_t cur; /* on-card buffer position (bytes offset) */ 526114018Sharti uint32_t dtq; /* on-card queue position (byte offset) */ 527114018Sharti uint32_t last_dtq; /* last DTQ we have written */ 528114018Sharti uint32_t tmp; 529114018Sharti u_int free; /* free queue entries on card */ 530114018Sharti u_int needalign, cnt; 531114018Sharti bus_size_t rest; /* remaining bytes in current segment */ 532114018Sharti bus_addr_t addr; 533114018Sharti bus_dma_segment_t *s; 534114018Sharti uint32_t count, bcode; 535114018Sharti int i; 53625603Skjc 537114018Sharti if (error != 0) 538114018Sharti return; 53925603Skjc 540114018Sharti cur = slot->cur; 541114018Sharti dtq = sc->dtq_us; 542114018Sharti free = sc->dtq_free; 54325603Skjc 544114018Sharti last_dtq = 0; /* make gcc happy */ 54525603Skjc 546114018Sharti /* 547114018Sharti * Local macro to add an entry to the transmit DMA area. If there 548114018Sharti * are no entries left, return. Save the byte offset of the entry 549114018Sharti * in last_dtq for later use. 550114018Sharti */ 551114018Sharti#define PUT_DTQ_ENTRY(ENI, BCODE, COUNT, ADDR) \ 552114018Sharti if (free == 0) { \ 553114018Sharti EN_COUNT(sc->stats.txdtqout); \ 554114018Sharti tx->wait = 1; \ 555114018Sharti return; \ 556114018Sharti } \ 557114018Sharti last_dtq = dtq; \ 558114018Sharti en_write(sc, dtq + 0, (ENI || !sc->is_adaptec) ? \ 559114018Sharti MID_MK_TXQ_ENI(COUNT, tx->chan, 0, BCODE) : \ 560114018Sharti MID_MK_TXQ_ADP(COUNT, tx->chan, 0, BCODE)); \ 561114018Sharti en_write(sc, dtq + 4, ADDR); \ 562114018Sharti \ 563114018Sharti EN_WRAPADD(MID_DTQOFF, MID_DTQEND, dtq, 8); \ 564114018Sharti free--; 56525603Skjc 566114018Sharti /* 567114018Sharti * Local macro to generate a DMA entry to DMA cnt bytes. Updates 568114018Sharti * the current buffer byte offset accordingly. 569114018Sharti */ 570114018Sharti#define DO_DTQ(TYPE) do { \ 571114018Sharti rest -= cnt; \ 572114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, cnt); \ 573114018Sharti DBG(sc, TX, ("tx%d: "TYPE" %u bytes, %ju left, cur %#x", \ 574114018Sharti tx->chan, cnt, (uintmax_t)rest, cur)); \ 575114018Sharti \ 576114018Sharti PUT_DTQ_ENTRY(1, bcode, count, addr); \ 577114018Sharti \ 578114018Sharti addr += cnt; \ 579114018Sharti } while (0) 58025603Skjc 581114018Sharti if (!(tx->flags & TX_HAS_TBD)) { 582114018Sharti /* 583114018Sharti * Prepend the TBD - it did not fit into the first mbuf 584114018Sharti */ 585114018Sharti tmp = MID_TBD_MK1((tx->flags & TX_AAL5) ? 586114018Sharti MID_TBD_AAL5 : MID_TBD_NOAAL5, 587118487Sharti sc->vccs[tx->vci]->txspeed, 588114018Sharti tx->m->m_pkthdr.len / MID_ATMDATASZ); 589114018Sharti en_write(sc, cur, tmp); 590114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, 4); 59125603Skjc 592114018Sharti tmp = MID_TBD_MK2(tx->vci, 0, 0); 593114018Sharti en_write(sc, cur, tmp); 594114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, 4); 59525603Skjc 596114018Sharti /* update DMA address */ 597114018Sharti PUT_DTQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0); 598114018Sharti } 59925603Skjc 600114018Sharti for (i = 0, s = segs; i < nseg; i++, s++) { 601114018Sharti rest = s->ds_len; 602114018Sharti addr = s->ds_addr; 60325603Skjc 604114018Sharti if (sc->is_adaptec) { 605114018Sharti /* adaptec card - simple */ 60625603Skjc 607114018Sharti /* advance the on-card buffer pointer */ 608114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, rest); 609114018Sharti DBG(sc, TX, ("tx%d: adp %ju bytes %#jx (cur now 0x%x)", 610114018Sharti tx->chan, (uintmax_t)rest, (uintmax_t)addr, cur)); 61125603Skjc 612114018Sharti PUT_DTQ_ENTRY(0, 0, rest, addr); 61325603Skjc 614114018Sharti continue; 615114018Sharti } 61625603Skjc 617114018Sharti /* 618114018Sharti * do we need to do a DMA op to align to the maximum 619114018Sharti * burst? Note, that we are alway 32-bit aligned. 620114018Sharti */ 621114018Sharti if (sc->alburst && 622114018Sharti (needalign = (addr & sc->bestburstmask)) != 0) { 623114018Sharti /* compute number of bytes, words and code */ 624114018Sharti cnt = sc->bestburstlen - needalign; 625114018Sharti if (cnt > rest) 626114018Sharti cnt = rest; 627114018Sharti count = cnt / sizeof(uint32_t); 628114018Sharti if (sc->noalbursts) { 629114018Sharti bcode = MIDDMA_WORD; 630114018Sharti } else { 631114018Sharti bcode = en_dmaplan[count].bcode; 632114018Sharti count = cnt >> en_dmaplan[count].divshift; 633114018Sharti } 634114018Sharti DO_DTQ("al_dma"); 635114018Sharti } 63625603Skjc 637114018Sharti /* do we need to do a max-sized burst? */ 638114018Sharti if (rest >= sc->bestburstlen) { 639114018Sharti count = rest >> sc->bestburstshift; 640114018Sharti cnt = count << sc->bestburstshift; 641114018Sharti bcode = sc->bestburstcode; 642114018Sharti DO_DTQ("best_dma"); 643114018Sharti } 64425603Skjc 645114018Sharti /* do we need to do a cleanup burst? */ 646114018Sharti if (rest != 0) { 647114018Sharti cnt = rest; 648114018Sharti count = rest / sizeof(uint32_t); 649114018Sharti if (sc->noalbursts) { 650114018Sharti bcode = MIDDMA_WORD; 651114018Sharti } else { 652114018Sharti bcode = en_dmaplan[count].bcode; 653114018Sharti count = cnt >> en_dmaplan[count].divshift; 654114018Sharti } 655114018Sharti DO_DTQ("clean_dma"); 656114018Sharti } 657114018Sharti } 65825603Skjc 659114018Sharti KASSERT (tx->flags & TX_HAS_PAD, ("PDU not padded")); 66037939Skjc 661114018Sharti if ((tx->flags & TX_AAL5) && !(tx->flags & TX_HAS_PDU)) { 662114018Sharti /* 663114018Sharti * Append the AAL5 PDU trailer 664114018Sharti */ 665114018Sharti tmp = MID_PDU_MK1(0, 0, tx->datalen); 666114018Sharti en_write(sc, cur, tmp); 667114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, 4); 66837939Skjc 669114018Sharti en_write(sc, cur, 0); 670114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, 4); 67125603Skjc 672114018Sharti /* update DMA address */ 673114018Sharti PUT_DTQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0); 674114018Sharti } 67525603Skjc 676114018Sharti /* record the end for the interrupt routine */ 677114018Sharti sc->dtq[MID_DTQ_A2REG(last_dtq)] = 678114018Sharti EN_DQ_MK(tx->chan, tx->m->m_pkthdr.len); 67925603Skjc 680114018Sharti /* set the end flag in the last descriptor */ 681114018Sharti en_write(sc, last_dtq + 0, SETQ_END(sc, en_read(sc, last_dtq + 0))); 68225603Skjc 683114018Sharti#undef PUT_DTQ_ENTRY 684114018Sharti#undef DO_DTQ 68537939Skjc 686114018Sharti /* commit */ 687114018Sharti slot->cur = cur; 688114018Sharti sc->dtq_free = free; 689114018Sharti sc->dtq_us = dtq; 69025603Skjc 691114018Sharti /* tell card */ 692114018Sharti en_write(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_us)); 69325603Skjc} 69425603Skjc 69525603Skjc/* 696114018Sharti * en_txdma: start transmit DMA on the given channel, if possible 69725603Skjc * 698114018Sharti * This is called from two places: when we got new packets from the upper 699114018Sharti * layer or when we found that buffer space has freed up during interrupt 700114018Sharti * processing. 70125603Skjc * 702114018Sharti * LOCK: locked, needed 70325603Skjc */ 704114018Shartistatic void 705114018Shartien_txdma(struct en_softc *sc, struct en_txslot *slot) 70625603Skjc{ 707114018Sharti struct en_map *map; 708114018Sharti struct mbuf *lastm; 709114018Sharti struct txarg tx; 710114018Sharti u_int pad; 711114018Sharti int error; 71225603Skjc 713114018Sharti DBG(sc, TX, ("tx%td: starting ...", slot - sc->txslot)); 714114018Sharti again: 715114018Sharti bzero(&tx, sizeof(tx)); 716114018Sharti tx.chan = slot - sc->txslot; 717114018Sharti tx.sc = sc; 71825603Skjc 719114018Sharti /* 720114018Sharti * get an mbuf waiting for DMA 721114018Sharti */ 722114018Sharti _IF_DEQUEUE(&slot->q, tx.m); 723114018Sharti if (tx.m == NULL) { 724114018Sharti DBG(sc, TX, ("tx%td: ...done!", slot - sc->txslot)); 725114018Sharti return; 726114018Sharti } 727114018Sharti MBUF_GET_TX(tx.m, tx.vci, tx.flags, tx.datalen, pad, map); 72825603Skjc 729114018Sharti /* 730114018Sharti * note: don't use the entire buffer space. if WRTX becomes equal 731114018Sharti * to RDTX, the transmitter stops assuming the buffer is empty! --kjc 732114018Sharti */ 733114018Sharti if (tx.m->m_pkthdr.len >= slot->bfree) { 734114018Sharti EN_COUNT(sc->stats.txoutspace); 735114018Sharti DBG(sc, TX, ("tx%td: out of transmit space", slot - sc->txslot)); 736114018Sharti goto waitres; 737114018Sharti } 738114018Sharti 739114018Sharti lastm = NULL; 740114018Sharti if (!(tx.flags & TX_HAS_PAD)) { 741114018Sharti if (pad != 0) { 742114018Sharti /* Append the padding buffer */ 743114018Sharti (void)m_length(tx.m, &lastm); 744114018Sharti lastm->m_next = sc->padbuf; 745114018Sharti sc->padbuf->m_len = pad; 746114018Sharti } 747114018Sharti tx.flags |= TX_HAS_PAD; 748114018Sharti } 74925603Skjc 750114018Sharti /* 751114018Sharti * Try to load that map 752114018Sharti */ 753114018Sharti error = bus_dmamap_load_mbuf(sc->txtag, map->map, tx.m, 754117641Sharti en_txdma_load, &tx, BUS_DMA_NOWAIT); 75525603Skjc 756114018Sharti if (lastm != NULL) 757114018Sharti lastm->m_next = NULL; 75825603Skjc 759114018Sharti if (error != 0) { 760162321Sglebius device_printf(sc->dev, "loading TX map failed %d\n", 761114739Sharti error); 762114018Sharti goto dequeue_drop; 763114018Sharti } 764114018Sharti map->flags |= ENMAP_LOADED; 765114018Sharti if (tx.wait) { 766114018Sharti /* probably not enough space */ 767114018Sharti bus_dmamap_unload(map->sc->txtag, map->map); 768114018Sharti map->flags &= ~ENMAP_LOADED; 76925603Skjc 770114018Sharti sc->need_dtqs = 1; 771114018Sharti DBG(sc, TX, ("tx%td: out of transmit DTQs", slot - sc->txslot)); 772114018Sharti goto waitres; 773114018Sharti } 77425603Skjc 775114018Sharti EN_COUNT(sc->stats.launch); 776147256Sbrooks sc->ifp->if_opackets++; 777118495Sharti 778118495Sharti sc->vccs[tx.vci]->opackets++; 779118495Sharti sc->vccs[tx.vci]->obytes += tx.datalen; 780118495Sharti 781114018Sharti#ifdef ENABLE_BPF 782165632Sjhb if (bpf_peers_present(sc->ifp->if_bpf)) { 783114018Sharti /* 784114018Sharti * adjust the top of the mbuf to skip the TBD if present 785114018Sharti * before passing the packet to bpf. 786114018Sharti * Also remove padding and the PDU trailer. Assume both of 787114018Sharti * them to be in the same mbuf. pktlen, m_len and m_data 788114018Sharti * are not needed anymore so we can change them. 789114018Sharti */ 790114018Sharti if (tx.flags & TX_HAS_TBD) { 791114018Sharti tx.m->m_data += MID_TBD_SIZE; 792114018Sharti tx.m->m_len -= MID_TBD_SIZE; 793114018Sharti } 794114018Sharti tx.m->m_pkthdr.len = m_length(tx.m, &lastm); 795114018Sharti if (tx.m->m_pkthdr.len > tx.datalen) { 796114018Sharti lastm->m_len -= tx.m->m_pkthdr.len - tx.datalen; 797114018Sharti tx.m->m_pkthdr.len = tx.datalen; 798114018Sharti } 79925603Skjc 800165640Sjhb bpf_mtap(sc->ifp->if_bpf, tx.m); 801114018Sharti } 802114018Sharti#endif 80325603Skjc 804114018Sharti /* 805114018Sharti * do some housekeeping and get the next packet 806114018Sharti */ 807114018Sharti slot->bfree -= tx.m->m_pkthdr.len; 808114018Sharti _IF_ENQUEUE(&slot->indma, tx.m); 80925603Skjc 810114018Sharti goto again; 81125603Skjc 812114018Sharti /* 813114018Sharti * error handling. This is jumped to when we just want to drop 814114018Sharti * the packet. Must be unlocked here. 815114018Sharti */ 816114018Sharti dequeue_drop: 817114018Sharti if (map != NULL) 818114018Sharti uma_zfree(sc->map_zone, map); 81925603Skjc 820114018Sharti slot->mbsize -= tx.m->m_pkthdr.len; 82125603Skjc 822114018Sharti m_freem(tx.m); 82325603Skjc 824114018Sharti goto again; 82525603Skjc 826114018Sharti waitres: 827114018Sharti _IF_PREPEND(&slot->q, tx.m); 828114018Sharti} 82925603Skjc 830114018Sharti/* 831114018Sharti * Create a copy of a single mbuf. It can have either internal or 832114018Sharti * external data, it may have a packet header. External data is really 833114018Sharti * copied, so the new buffer is writeable. 834114018Sharti * 835114018Sharti * LOCK: any, not needed 836114018Sharti */ 837114018Shartistatic struct mbuf * 838114018Sharticopy_mbuf(struct mbuf *m) 839114018Sharti{ 840114018Sharti struct mbuf *new; 84125603Skjc 842248078Smarius MGET(new, M_WAITOK, MT_DATA); 84325603Skjc 844114018Sharti if (m->m_flags & M_PKTHDR) { 845114018Sharti M_MOVE_PKTHDR(new, m); 846177599Sru if (m->m_len > MHLEN) 847248078Smarius MCLGET(new, M_WAITOK); 848114018Sharti } else { 849177599Sru if (m->m_len > MLEN) 850248078Smarius MCLGET(new, M_WAITOK); 851114018Sharti } 85225603Skjc 853114018Sharti bcopy(m->m_data, new->m_data, m->m_len); 854114018Sharti new->m_len = m->m_len; 855114018Sharti new->m_flags &= ~M_RDONLY; 85637939Skjc 857114018Sharti return (new); 858114018Sharti} 85925603Skjc 860114018Sharti/* 861114018Sharti * This function is called when we have an ENI adapter. It fixes the 862114018Sharti * mbuf chain, so that all addresses and lengths are 4 byte aligned. 863114018Sharti * The overall length is already padded to multiple of cells plus the 864114018Sharti * TBD so this must always succeed. The routine can fail, when it 865114018Sharti * needs to copy an mbuf (this may happen if an mbuf is readonly). 866114018Sharti * 867114018Sharti * We assume here, that aligning the virtual addresses to 4 bytes also 868114018Sharti * aligns the physical addresses. 869114018Sharti * 870114018Sharti * LOCK: locked, needed 871114018Sharti */ 872114018Shartistatic struct mbuf * 873114018Shartien_fix_mchain(struct en_softc *sc, struct mbuf *m0, u_int *pad) 874114018Sharti{ 875114018Sharti struct mbuf **prev = &m0; 876114018Sharti struct mbuf *m = m0; 877114018Sharti struct mbuf *new; 878114018Sharti u_char *d; 879114018Sharti int off; 88025603Skjc 881114018Sharti while (m != NULL) { 882114018Sharti d = mtod(m, u_char *); 883114018Sharti if ((off = (uintptr_t)d % sizeof(uint32_t)) != 0) { 884114018Sharti EN_COUNT(sc->stats.mfixaddr); 885114018Sharti if (M_WRITABLE(m)) { 886114018Sharti bcopy(d, d - off, m->m_len); 887114018Sharti m->m_data -= off; 888114018Sharti } else { 889114018Sharti if ((new = copy_mbuf(m)) == NULL) { 890114018Sharti EN_COUNT(sc->stats.mfixfail); 891114018Sharti m_freem(m0); 892114018Sharti return (NULL); 893114018Sharti } 894114018Sharti new->m_next = m_free(m); 895114018Sharti *prev = m = new; 896114018Sharti } 897114018Sharti } 89825603Skjc 899114018Sharti if ((off = m->m_len % sizeof(uint32_t)) != 0) { 900114018Sharti EN_COUNT(sc->stats.mfixlen); 901114018Sharti if (!M_WRITABLE(m)) { 902114018Sharti if ((new = copy_mbuf(m)) == NULL) { 903114018Sharti EN_COUNT(sc->stats.mfixfail); 904114018Sharti m_freem(m0); 905114018Sharti return (NULL); 906114018Sharti } 907114018Sharti new->m_next = m_free(m); 908114018Sharti *prev = m = new; 909114018Sharti } 910114018Sharti d = mtod(m, u_char *) + m->m_len; 911114018Sharti off = 4 - off; 912114018Sharti while (off) { 913114018Sharti while (m->m_next && m->m_next->m_len == 0) 914114018Sharti m->m_next = m_free(m->m_next); 91525603Skjc 916114018Sharti if (m->m_next == NULL) { 917114018Sharti *d++ = 0; 918114018Sharti KASSERT(*pad > 0, ("no padding space")); 919114018Sharti (*pad)--; 920114018Sharti } else { 921114018Sharti *d++ = *mtod(m->m_next, u_char *); 922114018Sharti m->m_next->m_len--; 923114018Sharti m->m_next->m_data++; 924114018Sharti } 925114018Sharti m->m_len++; 926114018Sharti off--; 927114018Sharti } 928114018Sharti } 92925603Skjc 930114018Sharti prev = &m->m_next; 931114018Sharti m = m->m_next; 932114018Sharti } 93325603Skjc 934114018Sharti return (m0); 93525603Skjc} 93625603Skjc 93725603Skjc/* 938114018Sharti * en_start: start transmitting the next packet that needs to go out 939114018Sharti * if there is one. We take off all packets from the interface's queue and 940114018Sharti * put them into the channels queue. 94125603Skjc * 942114018Sharti * Here we also prepend the transmit packet descriptor and append the padding 943114018Sharti * and (for aal5) the PDU trailer. This is different from the original driver: 944114018Sharti * we assume, that allocating one or two additional mbufs is actually cheaper 945114018Sharti * than all this algorithmic fiddling we would need otherwise. 946114018Sharti * 947114018Sharti * While the packet is on the channels wait queue we use the csum_* fields 948114018Sharti * in the packet header to hold the original datalen, the AAL5 flag and the 949114018Sharti * VCI. The packet length field in the header holds the needed buffer space. 950114018Sharti * This may actually be more than the length of the current mbuf chain (when 951114018Sharti * one or more of TBD, padding and PDU do not fit). 952114018Sharti * 953114018Sharti * LOCK: unlocked, needed 95425603Skjc */ 955114018Shartistatic void 956114018Shartien_start(struct ifnet *ifp) 95725603Skjc{ 958114018Sharti struct en_softc *sc = (struct en_softc *)ifp->if_softc; 959114018Sharti struct mbuf *m, *lastm; 960114018Sharti struct atm_pseudohdr *ap; 961114018Sharti u_int pad; /* 0-bytes to pad at PDU end */ 962114018Sharti u_int datalen; /* length of user data */ 963114018Sharti u_int vci; /* the VCI we are transmitting on */ 964114018Sharti u_int flags; 965114018Sharti uint32_t tbd[2]; 966114018Sharti uint32_t pdu[2]; 967118533Sharti struct en_vcc *vc; 968114018Sharti struct en_map *map; 969118487Sharti struct en_txslot *tx; 97025603Skjc 971114018Sharti while (1) { 972114018Sharti IF_DEQUEUE(&ifp->if_snd, m); 973114018Sharti if (m == NULL) 974114018Sharti return; 97525603Skjc 976114018Sharti flags = 0; 97725603Skjc 978114018Sharti ap = mtod(m, struct atm_pseudohdr *); 979114018Sharti vci = ATM_PH_VCI(ap); 98025603Skjc 981118533Sharti if (ATM_PH_VPI(ap) != 0 || vci >= MID_N_VC || 982118533Sharti (vc = sc->vccs[vci]) == NULL || 983118533Sharti (vc->vflags & VCC_CLOSE_RX)) { 984114018Sharti DBG(sc, TX, ("output vpi=%u, vci=%u -- drop", 985114018Sharti ATM_PH_VPI(ap), vci)); 986114018Sharti m_freem(m); 987114018Sharti continue; 98825603Skjc } 989118533Sharti if (vc->vcc.aal == ATMIO_AAL_5) 990118533Sharti flags |= TX_AAL5; 991114018Sharti m_adj(m, sizeof(struct atm_pseudohdr)); 99225603Skjc 993114018Sharti /* 994114018Sharti * (re-)calculate size of packet (in bytes) 995114018Sharti */ 996114018Sharti m->m_pkthdr.len = datalen = m_length(m, &lastm); 99725603Skjc 998114018Sharti /* 999114018Sharti * computing how much padding we need on the end of the mbuf, 1000114018Sharti * then see if we can put the TBD at the front of the mbuf 1001114018Sharti * where the link header goes (well behaved protocols will 1002114018Sharti * reserve room for us). Last, check if room for PDU tail. 1003114018Sharti */ 1004114018Sharti if (flags & TX_AAL5) 1005114018Sharti m->m_pkthdr.len += MID_PDU_SIZE; 1006114018Sharti m->m_pkthdr.len = roundup(m->m_pkthdr.len, MID_ATMDATASZ); 1007114018Sharti pad = m->m_pkthdr.len - datalen; 1008114018Sharti if (flags & TX_AAL5) 1009114018Sharti pad -= MID_PDU_SIZE; 1010114018Sharti m->m_pkthdr.len += MID_TBD_SIZE; 101125603Skjc 1012114018Sharti DBG(sc, TX, ("txvci%d: buflen=%u datalen=%u lead=%d trail=%d", 1013114018Sharti vci, m->m_pkthdr.len, datalen, (int)M_LEADINGSPACE(m), 1014114018Sharti (int)M_TRAILINGSPACE(lastm))); 101525603Skjc 1016114018Sharti /* 1017123593Sharti * From here on we need access to sc 1018123593Sharti */ 1019123593Sharti EN_LOCK(sc); 1020123593Sharti 1021123593Sharti /* 1022114018Sharti * Allocate a map. We do this here rather then in en_txdma, 1023114018Sharti * because en_txdma is also called from the interrupt handler 1024114018Sharti * and we are going to have a locking problem then. We must 1025114018Sharti * use NOWAIT here, because the ip_output path holds various 1026114018Sharti * locks. 1027114018Sharti */ 1028114018Sharti map = uma_zalloc_arg(sc->map_zone, sc, M_NOWAIT); 1029132987Sgreen if (map == NULL) { 1030114018Sharti /* drop that packet */ 1031114018Sharti EN_COUNT(sc->stats.txnomap); 1032123593Sharti EN_UNLOCK(sc); 1033114018Sharti m_freem(m); 1034114018Sharti continue; 1035114018Sharti } 103625603Skjc 1037148887Srwatson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1038114018Sharti EN_UNLOCK(sc); 1039114018Sharti uma_zfree(sc->map_zone, map); 1040114018Sharti m_freem(m); 1041114018Sharti continue; 1042114018Sharti } 104325603Skjc 1044114018Sharti /* 1045114018Sharti * Look, whether we can prepend the TBD (8 byte) 1046114018Sharti */ 1047114018Sharti if (M_WRITABLE(m) && M_LEADINGSPACE(m) >= MID_TBD_SIZE) { 1048114018Sharti tbd[0] = htobe32(MID_TBD_MK1((flags & TX_AAL5) ? 1049114018Sharti MID_TBD_AAL5 : MID_TBD_NOAAL5, 1050118533Sharti vc->txspeed, m->m_pkthdr.len / MID_ATMDATASZ)); 1051114018Sharti tbd[1] = htobe32(MID_TBD_MK2(vci, 0, 0)); 105225603Skjc 1053114018Sharti m->m_data -= MID_TBD_SIZE; 1054114018Sharti bcopy(tbd, m->m_data, MID_TBD_SIZE); 1055114018Sharti m->m_len += MID_TBD_SIZE; 1056114018Sharti flags |= TX_HAS_TBD; 1057114018Sharti } 105825603Skjc 1059114018Sharti /* 1060114018Sharti * Check whether the padding fits (must be writeable - 1061114018Sharti * we pad with zero). 1062114018Sharti */ 1063114018Sharti if (M_WRITABLE(lastm) && M_TRAILINGSPACE(lastm) >= pad) { 1064114018Sharti bzero(lastm->m_data + lastm->m_len, pad); 1065114018Sharti lastm->m_len += pad; 1066114018Sharti flags |= TX_HAS_PAD; 106725603Skjc 1068114018Sharti if ((flags & TX_AAL5) && 1069114018Sharti M_TRAILINGSPACE(lastm) > MID_PDU_SIZE) { 1070114018Sharti pdu[0] = htobe32(MID_PDU_MK1(0, 0, datalen)); 1071114018Sharti pdu[1] = 0; 1072114018Sharti bcopy(pdu, lastm->m_data + lastm->m_len, 1073114018Sharti MID_PDU_SIZE); 1074114018Sharti lastm->m_len += MID_PDU_SIZE; 1075114018Sharti flags |= TX_HAS_PDU; 1076114018Sharti } 1077114018Sharti } 107825603Skjc 1079114018Sharti if (!sc->is_adaptec && 1080114018Sharti (m = en_fix_mchain(sc, m, &pad)) == NULL) { 1081114018Sharti EN_UNLOCK(sc); 1082114018Sharti uma_zfree(sc->map_zone, map); 1083114018Sharti continue; 1084114018Sharti } 108525603Skjc 1086114018Sharti /* 1087118487Sharti * get assigned channel (will be zero unless txspeed is set) 1088114018Sharti */ 1089118533Sharti tx = vc->txslot; 109025603Skjc 1091114018Sharti if (m->m_pkthdr.len > EN_TXSZ * 1024) { 1092156951Sharti DBG(sc, TX, ("tx%td: packet larger than xmit buffer " 1093118487Sharti "(%d > %d)\n", tx - sc->txslot, m->m_pkthdr.len, 1094114018Sharti EN_TXSZ * 1024)); 1095114018Sharti EN_UNLOCK(sc); 1096114018Sharti m_freem(m); 1097114018Sharti uma_zfree(sc->map_zone, map); 1098114018Sharti continue; 1099114018Sharti } 110025603Skjc 1101118487Sharti if (tx->mbsize > EN_TXHIWAT) { 1102114018Sharti EN_COUNT(sc->stats.txmbovr); 1103156951Sharti DBG(sc, TX, ("tx%td: buffer space shortage", 1104118487Sharti tx - sc->txslot)); 1105114018Sharti EN_UNLOCK(sc); 1106114018Sharti m_freem(m); 1107114018Sharti uma_zfree(sc->map_zone, map); 1108114018Sharti continue; 1109114018Sharti } 111025603Skjc 1111114018Sharti /* commit */ 1112118487Sharti tx->mbsize += m->m_pkthdr.len; 111325603Skjc 1114156951Sharti DBG(sc, TX, ("tx%td: VCI=%d, speed=0x%x, buflen=%d, mbsize=%d", 1115118487Sharti tx - sc->txslot, vci, sc->vccs[vci]->txspeed, 1116118487Sharti m->m_pkthdr.len, tx->mbsize)); 111725603Skjc 1118114018Sharti MBUF_SET_TX(m, vci, flags, datalen, pad, map); 111925603Skjc 1120118487Sharti _IF_ENQUEUE(&tx->q, m); 112125603Skjc 1122118487Sharti en_txdma(sc, tx); 1123114018Sharti 1124114018Sharti EN_UNLOCK(sc); 1125114018Sharti } 112625603Skjc} 112725603Skjc 1128114018Sharti/*********************************************************************/ 1129114018Sharti/* 1130114018Sharti * VCs 1131114018Sharti */ 113225603Skjc 113325603Skjc/* 1134114018Sharti * en_loadvc: load a vc tab entry from a slot 1135114018Sharti * 1136114018Sharti * LOCK: locked, needed 113725603Skjc */ 1138114018Shartistatic void 1139118487Shartien_loadvc(struct en_softc *sc, struct en_vcc *vc) 114025603Skjc{ 1141118487Sharti uint32_t reg = en_read(sc, MID_VC(vc->vcc.vci)); 114225603Skjc 1143114018Sharti reg = MIDV_SETMODE(reg, MIDV_TRASH); 1144118487Sharti en_write(sc, MID_VC(vc->vcc.vci), reg); 1145114018Sharti DELAY(27); 114625603Skjc 1147114018Sharti /* no need to set CRC */ 114825603Skjc 1149114018Sharti /* read pointer = 0, desc. start = 0 */ 1150118487Sharti en_write(sc, MID_DST_RP(vc->vcc.vci), 0); 1151114018Sharti /* write pointer = 0 */ 1152118487Sharti en_write(sc, MID_WP_ST_CNT(vc->vcc.vci), 0); 1153114018Sharti /* set mode, size, loc */ 1154118487Sharti en_write(sc, MID_VC(vc->vcc.vci), vc->rxslot->mode); 115525603Skjc 1156118487Sharti vc->rxslot->cur = vc->rxslot->start; 115725603Skjc 1158156951Sharti DBG(sc, VC, ("rx%td: assigned to VCI %d", vc->rxslot - sc->rxslot, 1159118487Sharti vc->vcc.vci)); 116025603Skjc} 116125603Skjc 116225603Skjc/* 1163118494Sharti * Open the given vcc. 1164118494Sharti * 1165114018Sharti * LOCK: unlocked, needed 116625603Skjc */ 1167114018Shartistatic int 1168118494Shartien_open_vcc(struct en_softc *sc, struct atmio_openvcc *op) 1169114018Sharti{ 1170114018Sharti uint32_t oldmode, newmode; 1171118487Sharti struct en_rxslot *slot; 1172118487Sharti struct en_vcc *vc; 1173118487Sharti int error = 0; 117425603Skjc 1175118487Sharti DBG(sc, IOCTL, ("enable vpi=%d, vci=%d, flags=%#x", 1176118494Sharti op->param.vpi, op->param.vci, op->param.flags)); 117725603Skjc 1178118494Sharti if (op->param.vpi != 0 || op->param.vci >= MID_N_VC) 1179114018Sharti return (EINVAL); 118025603Skjc 1181118487Sharti vc = uma_zalloc(en_vcc_zone, M_NOWAIT | M_ZERO); 1182118487Sharti if (vc == NULL) 1183118487Sharti return (ENOMEM); 1184118487Sharti 1185114018Sharti EN_LOCK(sc); 118625603Skjc 1187118494Sharti if (sc->vccs[op->param.vci] != NULL) { 1188118487Sharti error = EBUSY; 1189118487Sharti goto done; 1190118487Sharti } 119125603Skjc 1192118487Sharti /* find a free receive slot */ 1193118487Sharti for (slot = sc->rxslot; slot < &sc->rxslot[sc->en_nrx]; slot++) 1194118487Sharti if (slot->vcc == NULL) 1195118487Sharti break; 1196118487Sharti if (slot == &sc->rxslot[sc->en_nrx]) { 1197118487Sharti error = ENOSPC; 1198118487Sharti goto done; 1199118487Sharti } 120025603Skjc 1201118487Sharti vc->rxslot = slot; 1202118494Sharti vc->rxhand = op->rxhand; 1203118494Sharti vc->vcc = op->param; 120425603Skjc 1205118487Sharti oldmode = slot->mode; 1206118494Sharti newmode = (op->param.aal == ATMIO_AAL_5) ? MIDV_AAL5 : MIDV_NOAAL; 1207118487Sharti slot->mode = MIDV_SETMODE(oldmode, newmode); 1208118487Sharti slot->vcc = vc; 1209118487Sharti 1210118487Sharti KASSERT (_IF_QLEN(&slot->indma) == 0 && _IF_QLEN(&slot->q) == 0, 1211156951Sharti ("en_rxctl: left over mbufs on enable slot=%td", 1212118532Sharti vc->rxslot - sc->rxslot)); 1213118487Sharti 1214118487Sharti vc->txspeed = 0; 1215118487Sharti vc->txslot = sc->txslot; 1216118487Sharti vc->txslot->nref++; /* bump reference count */ 1217118487Sharti 1218118487Sharti en_loadvc(sc, vc); /* does debug printf for us */ 1219118487Sharti 1220118487Sharti /* don't free below */ 1221118494Sharti sc->vccs[vc->vcc.vci] = vc; 1222118487Sharti vc = NULL; 1223118494Sharti sc->vccs_open++; 1224118487Sharti 1225118487Sharti done: 1226118487Sharti if (vc != NULL) 1227118487Sharti uma_zfree(en_vcc_zone, vc); 1228118487Sharti 1229118487Sharti EN_UNLOCK(sc); 1230118487Sharti return (error); 1231118487Sharti} 1232118487Sharti 1233118487Sharti/* 1234118487Sharti * Close finished 1235118487Sharti */ 1236118487Shartistatic void 1237118487Shartien_close_finish(struct en_softc *sc, struct en_vcc *vc) 1238118487Sharti{ 1239118487Sharti 1240118487Sharti if (vc->rxslot != NULL) 1241118487Sharti vc->rxslot->vcc = NULL; 1242118487Sharti 1243118487Sharti DBG(sc, VC, ("vci: %u free (%p)", vc->vcc.vci, vc)); 1244118487Sharti 1245118487Sharti sc->vccs[vc->vcc.vci] = NULL; 1246118487Sharti uma_zfree(en_vcc_zone, vc); 1247118494Sharti sc->vccs_open--; 1248118487Sharti} 1249118487Sharti 1250118487Sharti/* 1251118487Sharti * LOCK: unlocked, needed 1252118487Sharti */ 1253118487Shartistatic int 1254118548Shartien_close_vcc(struct en_softc *sc, struct atmio_closevcc *cl) 1255118487Sharti{ 1256118487Sharti uint32_t oldmode, newmode; 1257118487Sharti struct en_vcc *vc; 1258118487Sharti int error = 0; 1259118487Sharti 1260118494Sharti DBG(sc, IOCTL, ("disable vpi=%d, vci=%d", cl->vpi, cl->vci)); 1261118487Sharti 1262118494Sharti if (cl->vpi != 0 || cl->vci >= MID_N_VC) 1263118487Sharti return (EINVAL); 1264118487Sharti 1265118487Sharti EN_LOCK(sc); 1266118494Sharti if ((vc = sc->vccs[cl->vci]) == NULL) { 1267118487Sharti error = ENOTCONN; 1268118487Sharti goto done; 1269114018Sharti } 127025603Skjc 1271114018Sharti /* 1272114018Sharti * turn off VCI 1273114018Sharti */ 1274118487Sharti if (vc->rxslot == NULL) { 1275118487Sharti error = ENOTCONN; 1276118487Sharti goto done; 1277114018Sharti } 1278118487Sharti if (vc->vflags & VCC_DRAIN) { 1279118487Sharti error = EINVAL; 1280118487Sharti goto done; 1281114018Sharti } 128225603Skjc 1283118494Sharti oldmode = en_read(sc, MID_VC(cl->vci)); 1284114018Sharti newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE; 1285118494Sharti en_write(sc, MID_VC(cl->vci), (newmode | (oldmode & MIDV_INSERVICE))); 128625603Skjc 1287114018Sharti /* halt in tracks, be careful to preserve inservice bit */ 1288114018Sharti DELAY(27); 1289118487Sharti vc->rxslot->mode = newmode; 129025603Skjc 1291118487Sharti vc->txslot->nref--; 129225603Skjc 1293114018Sharti /* if stuff is still going on we are going to have to drain it out */ 1294118487Sharti if (_IF_QLEN(&vc->rxslot->indma) == 0 && 1295118487Sharti _IF_QLEN(&vc->rxslot->q) == 0 && 1296118487Sharti (vc->vflags & VCC_SWSL) == 0) { 1297118487Sharti en_close_finish(sc, vc); 1298118494Sharti goto done; 1299114018Sharti } 1300118487Sharti 1301118494Sharti vc->vflags |= VCC_DRAIN; 1302118494Sharti DBG(sc, IOCTL, ("VCI %u now draining", cl->vci)); 1303118494Sharti 1304118548Sharti if (vc->vcc.flags & ATMIO_FLAG_ASYNC) 1305118494Sharti goto done; 1306118494Sharti 1307118494Sharti vc->vflags |= VCC_CLOSE_RX; 1308148887Srwatson while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) && 1309118494Sharti (vc->vflags & VCC_DRAIN)) 1310118494Sharti cv_wait(&sc->cv_close, &sc->en_mtx); 1311118494Sharti 1312118494Sharti en_close_finish(sc, vc); 1313148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1314118494Sharti error = EIO; 1315118494Sharti goto done; 1316118494Sharti } 1317118494Sharti 1318118494Sharti 1319118487Sharti done: 1320114018Sharti EN_UNLOCK(sc); 1321118487Sharti return (error); 132225603Skjc} 132325603Skjc 1324114018Sharti/*********************************************************************/ 1325114018Sharti/* 1326114018Sharti * starting/stopping the card 1327114018Sharti */ 132825603Skjc 132925603Skjc/* 1330114018Sharti * en_reset_ul: reset the board, throw away work in progress. 1331114018Sharti * must en_init to recover. 1332114018Sharti * 1333114018Sharti * LOCK: locked, needed 133425603Skjc */ 1335114018Shartistatic void 1336114018Shartien_reset_ul(struct en_softc *sc) 1337114018Sharti{ 1338114018Sharti struct en_map *map; 1339114018Sharti struct mbuf *m; 1340118487Sharti struct en_rxslot *rx; 1341118487Sharti int lcv; 134225603Skjc 1343162321Sglebius device_printf(sc->dev, "reset\n"); 1344148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1345118484Sharti 1346114018Sharti if (sc->en_busreset) 1347114018Sharti sc->en_busreset(sc); 1348114018Sharti en_write(sc, MID_RESID, 0x0); /* reset hardware */ 134925603Skjc 1350114018Sharti /* 1351114018Sharti * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset 1352118487Sharti * will free us! Don't release the rxslot from the channel. 1353114018Sharti */ 1354114018Sharti for (lcv = 0 ; lcv < MID_N_VC ; lcv++) { 1355118487Sharti if (sc->vccs[lcv] == NULL) 1356114018Sharti continue; 1357118487Sharti rx = sc->vccs[lcv]->rxslot; 135825603Skjc 1359114018Sharti for (;;) { 1360118487Sharti _IF_DEQUEUE(&rx->indma, m); 1361114018Sharti if (m == NULL) 1362114018Sharti break; 1363114018Sharti map = (void *)m->m_pkthdr.rcvif; 1364114018Sharti uma_zfree(sc->map_zone, map); 1365114018Sharti m_freem(m); 1366114018Sharti } 1367114018Sharti for (;;) { 1368118487Sharti _IF_DEQUEUE(&rx->q, m); 1369114018Sharti if (m == NULL) 1370114018Sharti break; 1371114018Sharti m_freem(m); 1372114018Sharti } 1373118487Sharti sc->vccs[lcv]->vflags = 0; 1374114018Sharti } 137525603Skjc 1376114018Sharti /* 1377114018Sharti * xmit: dump everything 1378114018Sharti */ 1379114018Sharti for (lcv = 0 ; lcv < EN_NTX ; lcv++) { 1380114018Sharti for (;;) { 1381114018Sharti _IF_DEQUEUE(&sc->txslot[lcv].indma, m); 1382114018Sharti if (m == NULL) 1383114018Sharti break; 1384114018Sharti map = (void *)m->m_pkthdr.rcvif; 1385114018Sharti uma_zfree(sc->map_zone, map); 1386114018Sharti m_freem(m); 1387114018Sharti } 1388114018Sharti for (;;) { 1389114018Sharti _IF_DEQUEUE(&sc->txslot[lcv].q, m); 1390114018Sharti if (m == NULL) 1391114018Sharti break; 1392114018Sharti map = (void *)m->m_pkthdr.rcvif; 1393114018Sharti uma_zfree(sc->map_zone, map); 1394114018Sharti m_freem(m); 1395114018Sharti } 1396114018Sharti sc->txslot[lcv].mbsize = 0; 1397114018Sharti } 1398118494Sharti 1399118494Sharti /* 1400118494Sharti * Unstop all waiters 1401118494Sharti */ 1402126396Sscottl cv_broadcast(&sc->cv_close); 1403114018Sharti} 140425603Skjc 1405114018Sharti/* 1406114018Sharti * en_reset: reset the board, throw away work in progress. 1407114018Sharti * must en_init to recover. 1408114018Sharti * 1409114018Sharti * LOCK: unlocked, needed 1410114018Sharti * 1411114018Sharti * Use en_reset_ul if you alreay have the lock 1412114018Sharti */ 1413114018Shartivoid 1414114018Shartien_reset(struct en_softc *sc) 1415114018Sharti{ 1416114018Sharti EN_LOCK(sc); 1417114018Sharti en_reset_ul(sc); 1418114018Sharti EN_UNLOCK(sc); 141925603Skjc} 142025603Skjc 142125603Skjc 142225603Skjc/* 1423114018Sharti * en_init: init board and sync the card with the data in the softc. 1424114018Sharti * 1425114018Sharti * LOCK: locked, needed 142625603Skjc */ 1427114018Shartistatic void 1428114018Shartien_init(struct en_softc *sc) 1429114018Sharti{ 1430114018Sharti int vc, slot; 1431114018Sharti uint32_t loc; 143225603Skjc 1433147256Sbrooks if ((sc->ifp->if_flags & IFF_UP) == 0) { 1434114018Sharti DBG(sc, INIT, ("going down")); 1435114018Sharti en_reset(sc); /* to be safe */ 1436114018Sharti return; 1437114018Sharti } 143825603Skjc 1439114018Sharti DBG(sc, INIT, ("going up")); 1440148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; /* enable */ 144125603Skjc 1442114018Sharti if (sc->en_busreset) 1443114018Sharti sc->en_busreset(sc); 1444114018Sharti en_write(sc, MID_RESID, 0x0); /* reset */ 144525603Skjc 1446118487Sharti /* zero memory */ 1447118487Sharti bus_space_set_region_4(sc->en_memt, sc->en_base, 1448118487Sharti MID_RAMOFF, 0, sc->en_obmemsz / 4); 1449118487Sharti 1450114018Sharti /* 1451114018Sharti * init obmem data structures: vc tab, dma q's, slist. 1452114018Sharti * 1453114018Sharti * note that we set drq_free/dtq_free to one less than the total number 1454114018Sharti * of DTQ/DRQs present. we do this because the card uses the condition 1455114018Sharti * (drq_chip == drq_us) to mean "list is empty"... but if you allow the 1456114018Sharti * circular list to be completely full then (drq_chip == drq_us) [i.e. 1457114018Sharti * the drq_us pointer will wrap all the way around]. by restricting 1458114018Sharti * the number of active requests to (N - 1) we prevent the list from 1459114018Sharti * becoming completely full. note that the card will sometimes give 1460114018Sharti * us an interrupt for a DTQ/DRQ we have already processes... this helps 1461114018Sharti * keep that interrupt from messing us up. 1462114018Sharti */ 1463114018Sharti bzero(&sc->drq, sizeof(sc->drq)); 1464114018Sharti sc->drq_free = MID_DRQ_N - 1; 1465114018Sharti sc->drq_chip = MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX)); 1466114018Sharti en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip)); 1467114018Sharti sc->drq_us = sc->drq_chip; 146825603Skjc 1469114018Sharti bzero(&sc->dtq, sizeof(sc->dtq)); 1470114018Sharti sc->dtq_free = MID_DTQ_N - 1; 1471114018Sharti sc->dtq_chip = MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX)); 1472114018Sharti en_write(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip)); 1473114018Sharti sc->dtq_us = sc->dtq_chip; 147425603Skjc 1475114018Sharti sc->hwslistp = MID_SL_REG2A(en_read(sc, MID_SERV_WRITE)); 1476114018Sharti sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0; 147737939Skjc 1478114018Sharti DBG(sc, INIT, ("drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, " 1479114018Sharti "hwslist: 0x%x", sc->drq_free, sc->drq_chip, sc->dtq_free, 1480114018Sharti sc->dtq_chip, sc->hwslistp)); 148125603Skjc 1482114018Sharti for (slot = 0 ; slot < EN_NTX ; slot++) { 1483114018Sharti sc->txslot[slot].bfree = EN_TXSZ * 1024; 1484114018Sharti en_write(sc, MIDX_READPTR(slot), 0); 1485114018Sharti en_write(sc, MIDX_DESCSTART(slot), 0); 1486114018Sharti loc = sc->txslot[slot].cur = sc->txslot[slot].start; 1487114018Sharti loc = loc - MID_RAMOFF; 1488114018Sharti /* mask, cvt to words */ 1489114018Sharti loc = (loc & ~((EN_TXSZ * 1024) - 1)) >> 2; 1490114018Sharti /* top 11 bits */ 1491114018Sharti loc = loc >> MIDV_LOCTOPSHFT; 1492114018Sharti en_write(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ), 1493114018Sharti loc)); 1494114018Sharti DBG(sc, INIT, ("tx%d: place 0x%x", slot, 1495114018Sharti (u_int)en_read(sc, MIDX_PLACE(slot)))); 1496114018Sharti } 149725603Skjc 1498118487Sharti for (vc = 0; vc < MID_N_VC; vc++) 1499118490Sharti if (sc->vccs[vc] != NULL) 1500118487Sharti en_loadvc(sc, sc->vccs[vc]); 1501118487Sharti 1502114018Sharti /* 1503114018Sharti * enable! 1504114018Sharti */ 1505114018Sharti en_write(sc, MID_INTENA, MID_INT_TX | MID_INT_DMA_OVR | MID_INT_IDENT | 1506114018Sharti MID_INT_LERR | MID_INT_DMA_ERR | MID_INT_DMA_RX | MID_INT_DMA_TX | 1507116294Sharti MID_INT_SERVICE | MID_INT_SUNI | MID_INT_STATS); 1508114018Sharti en_write(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl) | MID_MCSR_ENDMA | 1509114018Sharti MID_MCSR_ENTX | MID_MCSR_ENRX); 1510114018Sharti} 151125603Skjc 1512114018Sharti/*********************************************************************/ 1513114018Sharti/* 1514114018Sharti * Ioctls 1515114018Sharti */ 1516116297Sharti/* 1517114018Sharti * en_ioctl: handle ioctl requests 1518114018Sharti * 1519114018Sharti * NOTE: if you add an ioctl to set txspeed, you should choose a new 1520114018Sharti * TX channel/slot. Choose the one with the lowest sc->txslot[slot].nref 1521114018Sharti * value, subtract one from sc->txslot[0].nref, add one to the 1522114018Sharti * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set 1523114018Sharti * txspeed[vci]. 1524114018Sharti * 1525114018Sharti * LOCK: unlocked, needed 1526114018Sharti */ 1527114018Shartistatic int 1528114018Shartien_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1529114018Sharti{ 1530114018Sharti struct en_softc *sc = (struct en_softc *)ifp->if_softc; 1531184712Sbz#if defined(INET) || defined(INET6) 1532114018Sharti struct ifaddr *ifa = (struct ifaddr *)data; 1533184712Sbz#endif 1534114018Sharti struct ifreq *ifr = (struct ifreq *)data; 1535116297Sharti struct atmio_vcctable *vtab; 1536114018Sharti int error = 0; 153725603Skjc 1538114018Sharti switch (cmd) { 153925603Skjc 1540114018Sharti case SIOCSIFADDR: 1541114018Sharti EN_LOCK(sc); 1542114018Sharti ifp->if_flags |= IFF_UP; 1543114018Sharti#if defined(INET) || defined(INET6) 1544114018Sharti if (ifa->ifa_addr->sa_family == AF_INET 1545114018Sharti || ifa->ifa_addr->sa_family == AF_INET6) { 1546148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1547114018Sharti en_reset_ul(sc); 1548114018Sharti en_init(sc); 1549114018Sharti } 1550114018Sharti ifa->ifa_rtrequest = atm_rtrequest; /* ??? */ 1551114018Sharti EN_UNLOCK(sc); 1552114018Sharti break; 1553114018Sharti } 1554114018Sharti#endif /* INET */ 1555148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1556114018Sharti en_reset_ul(sc); 1557114018Sharti en_init(sc); 1558114018Sharti } 1559114018Sharti EN_UNLOCK(sc); 1560114018Sharti break; 156125603Skjc 1562114018Sharti case SIOCSIFFLAGS: 1563114018Sharti EN_LOCK(sc); 1564114018Sharti if (ifp->if_flags & IFF_UP) { 1565148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1566114018Sharti en_init(sc); 1567114018Sharti } else { 1568148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1569114018Sharti en_reset_ul(sc); 1570114018Sharti } 1571114018Sharti EN_UNLOCK(sc); 1572114018Sharti break; 157325603Skjc 1574114018Sharti case SIOCSIFMTU: 1575114018Sharti /* 1576114018Sharti * Set the interface MTU. 1577114018Sharti */ 1578114018Sharti if (ifr->ifr_mtu > ATMMTU) { 1579114018Sharti error = EINVAL; 1580114018Sharti break; 1581114018Sharti } 1582114018Sharti ifp->if_mtu = ifr->ifr_mtu; 1583114018Sharti break; 158425603Skjc 1585116294Sharti case SIOCSIFMEDIA: 1586116294Sharti case SIOCGIFMEDIA: 1587116294Sharti error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 1588116294Sharti break; 1589116294Sharti 1590118548Sharti case SIOCATMOPENVCC: /* kernel internal use */ 1591118494Sharti error = en_open_vcc(sc, (struct atmio_openvcc *)data); 1592118494Sharti break; 1593118494Sharti 1594118548Sharti case SIOCATMCLOSEVCC: /* kernel internal use */ 1595118548Sharti error = en_close_vcc(sc, (struct atmio_closevcc *)data); 1596118494Sharti break; 1597118494Sharti 1598116297Sharti case SIOCATMGETVCCS: /* internal netgraph use */ 1599118491Sharti vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 1600118491Sharti MID_N_VC, sc->vccs_open, &sc->en_mtx, 0); 1601116297Sharti if (vtab == NULL) { 1602116297Sharti error = ENOMEM; 1603116297Sharti break; 1604116297Sharti } 1605116297Sharti *(void **)data = vtab; 1606116297Sharti break; 1607116297Sharti 1608116297Sharti case SIOCATMGVCCS: /* return vcc table */ 1609118491Sharti vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 1610118491Sharti MID_N_VC, sc->vccs_open, &sc->en_mtx, 1); 1611116297Sharti error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) + 1612116297Sharti vtab->count * sizeof(vtab->vccs[0])); 1613116297Sharti free(vtab, M_DEVBUF); 1614116297Sharti break; 1615116297Sharti 1616114018Sharti default: 1617114018Sharti error = EINVAL; 1618114018Sharti break; 161925603Skjc } 1620114018Sharti return (error); 1621114018Sharti} 162225603Skjc 1623114018Sharti/*********************************************************************/ 1624114018Sharti/* 1625114018Sharti * Sysctl's 1626114018Sharti */ 162725603Skjc 1628114018Sharti/* 1629114018Sharti * Sysctl handler for internal statistics 1630114018Sharti * 1631114018Sharti * LOCK: unlocked, needed 1632114018Sharti */ 1633114018Shartistatic int 1634114018Shartien_sysctl_istats(SYSCTL_HANDLER_ARGS) 1635114018Sharti{ 1636114018Sharti struct en_softc *sc = arg1; 1637115833Sharti uint32_t *ret; 1638114018Sharti int error; 163925603Skjc 1640115833Sharti ret = malloc(sizeof(sc->stats), M_TEMP, M_WAITOK); 164125603Skjc 1642114018Sharti EN_LOCK(sc); 1643115833Sharti bcopy(&sc->stats, ret, sizeof(sc->stats)); 1644115833Sharti EN_UNLOCK(sc); 164525603Skjc 1646115833Sharti error = SYSCTL_OUT(req, ret, sizeof(sc->stats)); 1647115833Sharti free(ret, M_TEMP); 164825603Skjc 1649114018Sharti return (error); 165025603Skjc} 165125603Skjc 1652114018Sharti/*********************************************************************/ 1653114018Sharti/* 1654114018Sharti * Interrupts 1655114018Sharti */ 165625603Skjc 165725603Skjc/* 1658114018Sharti * Transmit interrupt handler 1659114018Sharti * 1660114018Sharti * check for tx complete, if detected then this means that some space 1661114018Sharti * has come free on the card. we must account for it and arrange to 1662114018Sharti * kick the channel to life (in case it is stalled waiting on the card). 1663114018Sharti * 1664114018Sharti * LOCK: locked, needed 166525603Skjc */ 1666114018Shartistatic uint32_t 1667114018Shartien_intr_tx(struct en_softc *sc, uint32_t reg) 166837939Skjc{ 1669114018Sharti uint32_t kick; 1670114018Sharti uint32_t mask; 1671114018Sharti uint32_t val; 1672114018Sharti int chan; 167337939Skjc 1674114018Sharti kick = 0; /* bitmask of channels to kick */ 167537939Skjc 1676114018Sharti for (mask = 1, chan = 0; chan < EN_NTX; chan++, mask *= 2) { 1677114018Sharti if (!(reg & MID_TXCHAN(chan))) 1678114018Sharti continue; 167937939Skjc 1680114018Sharti kick = kick | mask; 168137939Skjc 1682114018Sharti /* current read pointer */ 1683114018Sharti val = en_read(sc, MIDX_READPTR(chan)); 1684114018Sharti /* as offset */ 1685114018Sharti val = (val * sizeof(uint32_t)) + sc->txslot[chan].start; 1686114018Sharti if (val > sc->txslot[chan].cur) 1687114018Sharti sc->txslot[chan].bfree = val - sc->txslot[chan].cur; 1688114018Sharti else 1689114018Sharti sc->txslot[chan].bfree = (val + (EN_TXSZ * 1024)) - 1690114018Sharti sc->txslot[chan].cur; 1691114018Sharti DBG(sc, INTR, ("tx%d: transmit done. %d bytes now free in " 1692114018Sharti "buffer", chan, sc->txslot[chan].bfree)); 1693114018Sharti } 1694114018Sharti return (kick); 1695114018Sharti} 169637939Skjc 1697114018Sharti/* 1698114018Sharti * TX DMA interrupt 1699114018Sharti * 1700114018Sharti * check for TX DMA complete, if detected then this means 1701114018Sharti * that some DTQs are now free. it also means some indma 1702114018Sharti * mbufs can be freed. if we needed DTQs, kick all channels. 1703114018Sharti * 1704114018Sharti * LOCK: locked, needed 1705114018Sharti */ 1706114018Shartistatic uint32_t 1707114018Shartien_intr_tx_dma(struct en_softc *sc) 1708114018Sharti{ 1709114018Sharti uint32_t kick = 0; 1710114018Sharti uint32_t val; 1711114018Sharti uint32_t idx; 1712114018Sharti uint32_t slot; 1713114018Sharti uint32_t dtq; 1714114018Sharti struct en_map *map; 1715114018Sharti struct mbuf *m; 171637939Skjc 1717114018Sharti val = en_read(sc, MID_DMA_RDTX); /* chip's current location */ 1718114018Sharti idx = MID_DTQ_A2REG(sc->dtq_chip); /* where we last saw chip */ 171937939Skjc 1720114018Sharti if (sc->need_dtqs) { 1721114018Sharti kick = MID_NTX_CH - 1; /* assume power of 2, kick all! */ 1722114018Sharti sc->need_dtqs = 0; /* recalculated in "kick" loop below */ 1723114018Sharti DBG(sc, INTR, ("cleared need DTQ condition")); 1724114018Sharti } 172537939Skjc 1726114018Sharti while (idx != val) { 1727114018Sharti sc->dtq_free++; 1728114018Sharti if ((dtq = sc->dtq[idx]) != 0) { 1729114018Sharti /* don't forget to zero it out when done */ 1730114018Sharti sc->dtq[idx] = 0; 1731114018Sharti slot = EN_DQ_SLOT(dtq); 173225603Skjc 1733114018Sharti _IF_DEQUEUE(&sc->txslot[slot].indma, m); 1734114018Sharti if (m == NULL) 1735114018Sharti panic("enintr: dtqsync"); 1736114018Sharti map = (void *)m->m_pkthdr.rcvif; 1737114018Sharti uma_zfree(sc->map_zone, map); 1738114018Sharti m_freem(m); 173925603Skjc 1740114018Sharti sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq); 1741114018Sharti DBG(sc, INTR, ("tx%d: free %d dma bytes, mbsize now " 1742114018Sharti "%d", slot, EN_DQ_LEN(dtq), 1743114018Sharti sc->txslot[slot].mbsize)); 1744114018Sharti } 1745114018Sharti EN_WRAPADD(0, MID_DTQ_N, idx, 1); 174625603Skjc } 1747114018Sharti sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */ 174825603Skjc 1749114018Sharti return (kick); 175025603Skjc} 175125603Skjc 1752114018Sharti/* 1753114018Sharti * Service interrupt 1754114018Sharti * 1755114018Sharti * LOCK: locked, needed 1756114018Sharti */ 1757114018Shartistatic int 1758114018Shartien_intr_service(struct en_softc *sc) 175925603Skjc{ 1760114018Sharti uint32_t chip; 1761114018Sharti uint32_t vci; 1762114018Sharti int need_softserv = 0; 1763118487Sharti struct en_vcc *vc; 176425603Skjc 1765114018Sharti chip = MID_SL_REG2A(en_read(sc, MID_SERV_WRITE)); 176625603Skjc 1767114018Sharti while (sc->hwslistp != chip) { 1768114018Sharti /* fetch and remove it from hardware service list */ 1769114018Sharti vci = en_read(sc, sc->hwslistp); 1770114018Sharti EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4); 177125603Skjc 1772118487Sharti if ((vc = sc->vccs[vci]) == NULL || 1773118487Sharti (vc->vcc.flags & ATMIO_FLAG_NORX)) { 1774118487Sharti DBG(sc, INTR, ("unexpected rx interrupt VCI %d", vci)); 1775114018Sharti en_write(sc, MID_VC(vci), MIDV_TRASH); /* rx off */ 1776114018Sharti continue; 1777114018Sharti } 177825603Skjc 1779114018Sharti /* remove from hwsl */ 1780118487Sharti en_write(sc, MID_VC(vci), vc->rxslot->mode); 1781114018Sharti EN_COUNT(sc->stats.hwpull); 178225603Skjc 1783114018Sharti DBG(sc, INTR, ("pulled VCI %d off hwslist", vci)); 178425603Skjc 1785114018Sharti /* add it to the software service list (if needed) */ 1786118487Sharti if ((vc->vflags & VCC_SWSL) == 0) { 1787114018Sharti EN_COUNT(sc->stats.swadd); 1788114018Sharti need_softserv = 1; 1789118487Sharti vc->vflags |= VCC_SWSL; 1790118487Sharti sc->swslist[sc->swsl_tail] = vci; 1791114018Sharti EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1); 1792114018Sharti sc->swsl_size++; 1793114018Sharti DBG(sc, INTR, ("added VCI %d to swslist", vci)); 1794114018Sharti } 1795114018Sharti } 1796114018Sharti return (need_softserv); 179725603Skjc} 179825603Skjc 179925603Skjc/* 1800118487Sharti * Handle a receive DMA completion 1801118487Sharti */ 1802118487Shartistatic void 1803118487Shartien_rx_drain(struct en_softc *sc, u_int drq) 1804118487Sharti{ 1805118487Sharti struct en_rxslot *slot; 1806118487Sharti struct en_vcc *vc; 1807118487Sharti struct mbuf *m; 1808118487Sharti struct atm_pseudohdr ah; 1809118487Sharti 1810118487Sharti slot = &sc->rxslot[EN_DQ_SLOT(drq)]; 1811118487Sharti 1812118487Sharti m = NULL; /* assume "JK" trash DMA */ 1813118487Sharti if (EN_DQ_LEN(drq) != 0) { 1814118487Sharti _IF_DEQUEUE(&slot->indma, m); 1815156951Sharti KASSERT(m != NULL, ("drqsync: %s: lost mbuf in slot %td!", 1816147256Sbrooks sc->ifp->if_xname, slot - sc->rxslot)); 1817118487Sharti uma_zfree(sc->map_zone, (struct en_map *)m->m_pkthdr.rcvif); 1818118487Sharti } 1819118487Sharti if ((vc = slot->vcc) == NULL) { 1820118487Sharti /* ups */ 1821118487Sharti if (m != NULL) 1822118487Sharti m_freem(m); 1823118487Sharti return; 1824118487Sharti } 1825118487Sharti 1826118487Sharti /* do something with this mbuf */ 1827118487Sharti if (vc->vflags & VCC_DRAIN) { 1828118487Sharti /* drain? */ 1829118487Sharti if (m != NULL) 1830118487Sharti m_freem(m); 1831118487Sharti if (_IF_QLEN(&slot->indma) == 0 && _IF_QLEN(&slot->q) == 0 && 1832118487Sharti (en_read(sc, MID_VC(vc->vcc.vci)) & MIDV_INSERVICE) == 0 && 1833118494Sharti (vc->vflags & VCC_SWSL) == 0) { 1834118494Sharti vc->vflags &= ~VCC_CLOSE_RX; 1835118548Sharti if (vc->vcc.flags & ATMIO_FLAG_ASYNC) 1836118494Sharti en_close_finish(sc, vc); 1837118494Sharti else 1838118494Sharti cv_signal(&sc->cv_close); 1839118494Sharti } 1840118487Sharti return; 1841118487Sharti } 1842118487Sharti 1843118487Sharti if (m != NULL) { 1844118487Sharti ATM_PH_FLAGS(&ah) = vc->vcc.flags; 1845118487Sharti ATM_PH_VPI(&ah) = 0; 1846118487Sharti ATM_PH_SETVCI(&ah, vc->vcc.vci); 1847118487Sharti 1848156951Sharti DBG(sc, INTR, ("rx%td: rxvci%d: atm_input, mbuf %p, len %d, " 1849118487Sharti "hand %p", slot - sc->rxslot, vc->vcc.vci, m, 1850118487Sharti EN_DQ_LEN(drq), vc->rxhand)); 1851118487Sharti 1852147256Sbrooks m->m_pkthdr.rcvif = sc->ifp; 1853147256Sbrooks sc->ifp->if_ipackets++; 1854118495Sharti 1855118495Sharti vc->ipackets++; 1856118495Sharti vc->ibytes += m->m_pkthdr.len; 1857118495Sharti 1858118487Sharti#ifdef EN_DEBUG 1859118487Sharti if (sc->debug & DBG_IPACKETS) 1860118487Sharti en_dump_packet(sc, m); 1861118487Sharti#endif 1862118487Sharti#ifdef ENABLE_BPF 1863147256Sbrooks BPF_MTAP(sc->ifp, m); 1864118487Sharti#endif 1865151771Sjhb EN_UNLOCK(sc); 1866147256Sbrooks atm_input(sc->ifp, &ah, m, vc->rxhand); 1867151771Sjhb EN_LOCK(sc); 1868118487Sharti } 1869118487Sharti} 1870118487Sharti 1871118487Sharti/* 1872114018Sharti * check for RX DMA complete, and pass the data "upstairs" 1873114018Sharti * 1874114018Sharti * LOCK: locked, needed 187525603Skjc */ 1876114018Shartistatic int 1877114018Shartien_intr_rx_dma(struct en_softc *sc) 1878114018Sharti{ 1879114018Sharti uint32_t val; 1880114018Sharti uint32_t idx; 1881114018Sharti uint32_t drq; 188225603Skjc 1883114018Sharti val = en_read(sc, MID_DMA_RDRX); /* chip's current location */ 1884114018Sharti idx = MID_DRQ_A2REG(sc->drq_chip); /* where we last saw chip */ 188525603Skjc 1886114018Sharti while (idx != val) { 1887114018Sharti sc->drq_free++; 1888114018Sharti if ((drq = sc->drq[idx]) != 0) { 1889114018Sharti /* don't forget to zero it out when done */ 1890114018Sharti sc->drq[idx] = 0; 1891118487Sharti en_rx_drain(sc, drq); 1892114018Sharti } 1893114018Sharti EN_WRAPADD(0, MID_DRQ_N, idx, 1); 1894114018Sharti } 1895114018Sharti sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */ 189625603Skjc 1897114018Sharti if (sc->need_drqs) { 1898114018Sharti /* true if we had a DRQ shortage */ 1899114018Sharti sc->need_drqs = 0; 1900114018Sharti DBG(sc, INTR, ("cleared need DRQ condition")); 1901114018Sharti return (1); 1902114018Sharti } else 1903114018Sharti return (0); 1904114018Sharti} 190525603Skjc 1906114018Sharti/* 1907114018Sharti * en_mget: get an mbuf chain that can hold totlen bytes and return it 1908114018Sharti * (for recv). For the actual allocation totlen is rounded up to a multiple 1909114018Sharti * of 4. We also ensure, that each mbuf has a multiple of 4 bytes. 1910114018Sharti * 1911114018Sharti * After this call the sum of all the m_len's in the chain will be totlen. 1912114018Sharti * This is called at interrupt time, so we can't wait here. 1913114018Sharti * 1914114018Sharti * LOCK: any, not needed 1915114018Sharti */ 1916114018Shartistatic struct mbuf * 1917114018Shartien_mget(struct en_softc *sc, u_int pktlen) 1918114018Sharti{ 1919114018Sharti struct mbuf *m, *tmp; 1920114018Sharti u_int totlen, pad; 192125603Skjc 1922114018Sharti totlen = roundup(pktlen, sizeof(uint32_t)); 1923114018Sharti pad = totlen - pktlen; 192425603Skjc 1925114018Sharti /* 1926114018Sharti * First get an mbuf with header. Keep space for a couple of 1927114018Sharti * words at the begin. 1928114018Sharti */ 1929114018Sharti /* called from interrupt context */ 1930248078Smarius MGETHDR(m, M_NOWAIT, MT_DATA); 1931114018Sharti if (m == NULL) 1932114018Sharti return (NULL); 193325603Skjc 1934114018Sharti m->m_pkthdr.rcvif = NULL; 1935114018Sharti m->m_pkthdr.len = pktlen; 1936114018Sharti m->m_len = EN_RX1BUF; 1937114018Sharti MH_ALIGN(m, EN_RX1BUF); 1938114018Sharti if (m->m_len >= totlen) { 1939114018Sharti m->m_len = totlen; 194025603Skjc 1941114018Sharti } else { 1942114018Sharti totlen -= m->m_len; 194325603Skjc 1944114018Sharti /* called from interrupt context */ 1945248078Smarius tmp = m_getm(m, totlen, M_NOWAIT, MT_DATA); 1946114018Sharti if (tmp == NULL) { 1947114018Sharti m_free(m); 1948114018Sharti return (NULL); 1949114018Sharti } 1950114018Sharti tmp = m->m_next; 1951114018Sharti /* m_getm could do this for us */ 1952114018Sharti while (tmp != NULL) { 1953114018Sharti tmp->m_len = min(MCLBYTES, totlen); 1954114018Sharti totlen -= tmp->m_len; 1955114018Sharti tmp = tmp->m_next; 1956114018Sharti } 1957114018Sharti } 195825603Skjc 1959114018Sharti return (m); 1960114018Sharti} 196125603Skjc 1962114018Sharti/* 1963114018Sharti * Argument for RX DMAMAP loader. 1964114018Sharti */ 1965114018Shartistruct rxarg { 1966114018Sharti struct en_softc *sc; 1967114018Sharti struct mbuf *m; 1968114018Sharti u_int pre_skip; /* number of bytes to skip at begin */ 1969114018Sharti u_int post_skip; /* number of bytes to skip at end */ 1970118487Sharti struct en_vcc *vc; /* vc we are receiving on */ 1971114018Sharti int wait; /* wait for DRQ entries */ 1972114018Sharti}; 197325603Skjc 1974114018Sharti/* 1975114018Sharti * Copy the segment table to the buffer for later use. And compute the 1976114018Sharti * number of dma queue entries we need. 1977114018Sharti * 1978114018Sharti * LOCK: locked, needed 1979114018Sharti */ 1980114018Shartistatic void 1981114018Shartien_rxdma_load(void *uarg, bus_dma_segment_t *segs, int nseg, 1982114018Sharti bus_size_t mapsize, int error) 1983114018Sharti{ 1984114018Sharti struct rxarg *rx = uarg; 1985114018Sharti struct en_softc *sc = rx->sc; 1986118487Sharti struct en_rxslot *slot = rx->vc->rxslot; 1987114018Sharti u_int free; /* number of free DRQ entries */ 1988114018Sharti uint32_t cur; /* current buffer offset */ 1989114018Sharti uint32_t drq; /* DRQ entry pointer */ 1990114018Sharti uint32_t last_drq; /* where we have written last */ 1991114018Sharti u_int needalign, cnt, count, bcode; 1992114018Sharti bus_addr_t addr; 1993114018Sharti bus_size_t rest; 1994114018Sharti int i; 199525603Skjc 1996114018Sharti if (error != 0) 1997114018Sharti return; 1998114018Sharti if (nseg > EN_MAX_DMASEG) 1999114018Sharti panic("too many DMA segments"); 200025603Skjc 2001114018Sharti rx->wait = 0; 200225603Skjc 2003114018Sharti free = sc->drq_free; 2004114018Sharti drq = sc->drq_us; 2005114018Sharti cur = slot->cur; 200625603Skjc 2007114018Sharti last_drq = 0; 200825603Skjc 2009114018Sharti /* 2010114018Sharti * Local macro to add an entry to the receive DMA area. If there 2011114018Sharti * are no entries left, return. Save the byte offset of the entry 2012114018Sharti * in last_drq for later use. 2013114018Sharti */ 2014114018Sharti#define PUT_DRQ_ENTRY(ENI, BCODE, COUNT, ADDR) \ 2015114018Sharti if (free == 0) { \ 2016114018Sharti EN_COUNT(sc->stats.rxdrqout); \ 2017114018Sharti rx->wait = 1; \ 2018114018Sharti return; \ 2019114018Sharti } \ 2020114018Sharti last_drq = drq; \ 2021114018Sharti en_write(sc, drq + 0, (ENI || !sc->is_adaptec) ? \ 2022118487Sharti MID_MK_RXQ_ENI(COUNT, rx->vc->vcc.vci, 0, BCODE) : \ 2023118487Sharti MID_MK_RXQ_ADP(COUNT, rx->vc->vcc.vci, 0, BCODE)); \ 2024114018Sharti en_write(sc, drq + 4, ADDR); \ 2025114018Sharti \ 2026114018Sharti EN_WRAPADD(MID_DRQOFF, MID_DRQEND, drq, 8); \ 2027114018Sharti free--; 202825603Skjc 2029114018Sharti /* 2030114018Sharti * Local macro to generate a DMA entry to DMA cnt bytes. Updates 2031114018Sharti * the current buffer byte offset accordingly. 2032114018Sharti */ 2033114018Sharti#define DO_DRQ(TYPE) do { \ 2034114018Sharti rest -= cnt; \ 2035114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, cnt); \ 2036114018Sharti DBG(sc, SERV, ("rx%td: "TYPE" %u bytes, %ju left, cur %#x", \ 2037114018Sharti slot - sc->rxslot, cnt, (uintmax_t)rest, cur)); \ 2038114018Sharti \ 2039114018Sharti PUT_DRQ_ENTRY(1, bcode, count, addr); \ 2040114018Sharti \ 2041114018Sharti addr += cnt; \ 2042114018Sharti } while (0) 204325603Skjc 2044114018Sharti /* 2045114018Sharti * Skip the RBD at the beginning 2046114018Sharti */ 2047114018Sharti if (rx->pre_skip > 0) { 2048114018Sharti /* update DMA address */ 2049114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, rx->pre_skip); 205025603Skjc 2051114018Sharti PUT_DRQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0); 2052114018Sharti } 205325603Skjc 2054114018Sharti for (i = 0; i < nseg; i++, segs++) { 2055114018Sharti addr = segs->ds_addr; 2056114018Sharti rest = segs->ds_len; 205725603Skjc 2058114018Sharti if (sc->is_adaptec) { 2059114018Sharti /* adaptec card - simple */ 206025603Skjc 2061114018Sharti /* advance the on-card buffer pointer */ 2062114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, rest); 2063114018Sharti DBG(sc, SERV, ("rx%td: adp %ju bytes %#jx " 2064114018Sharti "(cur now 0x%x)", slot - sc->rxslot, 2065114018Sharti (uintmax_t)rest, (uintmax_t)addr, cur)); 206625603Skjc 2067114018Sharti PUT_DRQ_ENTRY(0, 0, rest, addr); 206825603Skjc 2069114018Sharti continue; 2070114018Sharti } 207125603Skjc 2072114018Sharti /* 2073114018Sharti * do we need to do a DMA op to align to the maximum 2074114018Sharti * burst? Note, that we are alway 32-bit aligned. 2075114018Sharti */ 2076114018Sharti if (sc->alburst && 2077114018Sharti (needalign = (addr & sc->bestburstmask)) != 0) { 2078114018Sharti /* compute number of bytes, words and code */ 2079114018Sharti cnt = sc->bestburstlen - needalign; 2080114018Sharti if (cnt > rest) 2081114018Sharti cnt = rest; 2082114018Sharti count = cnt / sizeof(uint32_t); 2083114018Sharti if (sc->noalbursts) { 2084114018Sharti bcode = MIDDMA_WORD; 2085114018Sharti } else { 2086114018Sharti bcode = en_dmaplan[count].bcode; 2087114018Sharti count = cnt >> en_dmaplan[count].divshift; 2088114018Sharti } 2089114018Sharti DO_DRQ("al_dma"); 2090114018Sharti } 209137939Skjc 2092114018Sharti /* do we need to do a max-sized burst? */ 2093114018Sharti if (rest >= sc->bestburstlen) { 2094114018Sharti count = rest >> sc->bestburstshift; 2095114018Sharti cnt = count << sc->bestburstshift; 2096114018Sharti bcode = sc->bestburstcode; 2097114018Sharti DO_DRQ("best_dma"); 2098114018Sharti } 209937939Skjc 2100114018Sharti /* do we need to do a cleanup burst? */ 2101114018Sharti if (rest != 0) { 2102114018Sharti cnt = rest; 2103114018Sharti count = rest / sizeof(uint32_t); 2104114018Sharti if (sc->noalbursts) { 2105114018Sharti bcode = MIDDMA_WORD; 2106114018Sharti } else { 2107114018Sharti bcode = en_dmaplan[count].bcode; 2108114018Sharti count = cnt >> en_dmaplan[count].divshift; 2109114018Sharti } 2110114018Sharti DO_DRQ("clean_dma"); 2111114018Sharti } 2112114018Sharti } 211337939Skjc 2114114018Sharti /* 2115114018Sharti * Skip stuff at the end 2116114018Sharti */ 2117114018Sharti if (rx->post_skip > 0) { 2118114018Sharti /* update DMA address */ 2119114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, rx->post_skip); 212037939Skjc 2121114018Sharti PUT_DRQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0); 2122114018Sharti } 212325603Skjc 2124114018Sharti /* record the end for the interrupt routine */ 2125114018Sharti sc->drq[MID_DRQ_A2REG(last_drq)] = 2126114018Sharti EN_DQ_MK(slot - sc->rxslot, rx->m->m_pkthdr.len); 212725603Skjc 2128114018Sharti /* set the end flag in the last descriptor */ 2129114018Sharti en_write(sc, last_drq + 0, SETQ_END(sc, en_read(sc, last_drq + 0))); 213025603Skjc 2131114018Sharti#undef PUT_DRQ_ENTRY 2132114018Sharti#undef DO_DRQ 213325603Skjc 2134114018Sharti /* commit */ 2135114018Sharti slot->cur = cur; 2136114018Sharti sc->drq_free = free; 2137114018Sharti sc->drq_us = drq; 2138114018Sharti 2139114018Sharti /* signal to card */ 2140114018Sharti en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_us)); 214125603Skjc} 214225603Skjc 214325603Skjc/* 2144114018Sharti * en_service: handle a service interrupt 2145114018Sharti * 2146114018Sharti * Q: why do we need a software service list? 2147114018Sharti * 2148114018Sharti * A: if we remove a VCI from the hardware list and we find that we are 2149114018Sharti * out of DRQs we must defer processing until some DRQs become free. 2150114018Sharti * so we must remember to look at this RX VCI/slot later, but we can't 2151114018Sharti * put it back on the hardware service list (since that isn't allowed). 2152114018Sharti * so we instead save it on the software service list. it would be nice 2153114018Sharti * if we could peek at the VCI on top of the hwservice list without removing 2154114018Sharti * it, however this leads to a race condition: if we peek at it and 2155114018Sharti * decide we are done with it new data could come in before we have a 2156114018Sharti * chance to remove it from the hwslist. by the time we get it out of 2157114018Sharti * the list the interrupt for the new data will be lost. oops! 2158114018Sharti * 2159114018Sharti * LOCK: locked, needed 216025603Skjc */ 2161114018Shartistatic void 2162114018Shartien_service(struct en_softc *sc) 2163114018Sharti{ 2164114018Sharti struct mbuf *m, *lastm; 2165114018Sharti struct en_map *map; 2166114018Sharti struct rxarg rx; 2167114018Sharti uint32_t cur; 2168114018Sharti uint32_t dstart; /* data start (as reported by card) */ 2169114018Sharti uint32_t rbd; /* receive buffer descriptor */ 2170114018Sharti uint32_t pdu; /* AAL5 trailer */ 2171114018Sharti int mlen; 2172118487Sharti int error; 2173114018Sharti struct en_rxslot *slot; 2174118487Sharti struct en_vcc *vc; 217525603Skjc 2176114018Sharti rx.sc = sc; 217725603Skjc 2178114018Sharti next_vci: 2179114018Sharti if (sc->swsl_size == 0) { 2180114018Sharti DBG(sc, SERV, ("en_service done")); 2181114018Sharti return; 2182114018Sharti } 218325603Skjc 2184114018Sharti /* 2185118487Sharti * get vcc to service 2186114018Sharti */ 2187118487Sharti rx.vc = vc = sc->vccs[sc->swslist[sc->swsl_head]]; 2188118487Sharti slot = vc->rxslot; 2189118487Sharti KASSERT (slot->vcc->rxslot == slot, ("en_service: rx slot/vci sync")); 219025603Skjc 2191114018Sharti /* 2192114018Sharti * determine our mode and if we've got any work to do 2193114018Sharti */ 2194114018Sharti DBG(sc, SERV, ("rx%td: service vci=%d start/stop/cur=0x%x 0x%x " 2195118487Sharti "0x%x", slot - sc->rxslot, vc->vcc.vci, slot->start, 2196118487Sharti slot->stop, slot->cur)); 219725603Skjc 2198114018Sharti same_vci: 2199114018Sharti cur = slot->cur; 220025603Skjc 2201118487Sharti dstart = MIDV_DSTART(en_read(sc, MID_DST_RP(vc->vcc.vci))); 2202114018Sharti dstart = (dstart * sizeof(uint32_t)) + slot->start; 220325603Skjc 2204114018Sharti /* check to see if there is any data at all */ 2205114018Sharti if (dstart == cur) { 2206114018Sharti EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1); 2207114018Sharti /* remove from swslist */ 2208118487Sharti vc->vflags &= ~VCC_SWSL; 2209114018Sharti sc->swsl_size--; 2210114018Sharti DBG(sc, SERV, ("rx%td: remove vci %d from swslist", 2211118487Sharti slot - sc->rxslot, vc->vcc.vci)); 2212114018Sharti goto next_vci; 2213114018Sharti } 221425603Skjc 2215114018Sharti /* 2216114018Sharti * figure out how many bytes we need 2217114018Sharti * [mlen = # bytes to go in mbufs] 2218114018Sharti */ 2219114018Sharti rbd = en_read(sc, cur); 2220114018Sharti if (MID_RBD_ID(rbd) != MID_RBD_STDID) 2221114018Sharti panic("en_service: id mismatch"); 222225603Skjc 2223114018Sharti if (rbd & MID_RBD_T) { 2224114018Sharti mlen = 0; /* we've got trash */ 2225114018Sharti rx.pre_skip = MID_RBD_SIZE; 2226114018Sharti rx.post_skip = 0; 2227114018Sharti EN_COUNT(sc->stats.ttrash); 2228114018Sharti DBG(sc, SERV, ("RX overflow lost %d cells!", MID_RBD_CNT(rbd))); 222925603Skjc 2230118533Sharti } else if (vc->vcc.aal != ATMIO_AAL_5) { 2231114018Sharti /* 1 cell (ick!) */ 2232114018Sharti mlen = MID_CHDR_SIZE + MID_ATMDATASZ; 2233114018Sharti rx.pre_skip = MID_RBD_SIZE; 2234114018Sharti rx.post_skip = 0; 223525603Skjc 2236114018Sharti } else { 2237114018Sharti rx.pre_skip = MID_RBD_SIZE; 223825603Skjc 2239114018Sharti /* get PDU trailer in correct byte order */ 2240114018Sharti pdu = cur + MID_RBD_CNT(rbd) * MID_ATMDATASZ + 2241114018Sharti MID_RBD_SIZE - MID_PDU_SIZE; 2242114018Sharti if (pdu >= slot->stop) 2243114018Sharti pdu -= EN_RXSZ * 1024; 2244114018Sharti pdu = en_read(sc, pdu); 224525603Skjc 2246114018Sharti if (MID_RBD_CNT(rbd) * MID_ATMDATASZ < 2247114018Sharti MID_PDU_LEN(pdu)) { 2248162321Sglebius device_printf(sc->dev, "invalid AAL5 length\n"); 2249114018Sharti rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ; 2250114018Sharti mlen = 0; 2251147256Sbrooks sc->ifp->if_ierrors++; 225225603Skjc 2253114018Sharti } else if (rbd & MID_RBD_CRCERR) { 2254162321Sglebius device_printf(sc->dev, "CRC error\n"); 2255114018Sharti rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ; 2256114018Sharti mlen = 0; 2257147256Sbrooks sc->ifp->if_ierrors++; 225825603Skjc 2259114018Sharti } else { 2260114018Sharti mlen = MID_PDU_LEN(pdu); 2261114018Sharti rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ - mlen; 2262114018Sharti } 2263114018Sharti } 226425603Skjc 2265114018Sharti /* 2266114018Sharti * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all 2267114018Sharti * 2268114018Sharti * notes: 2269114018Sharti * 1. it is possible that we've already allocated an mbuf for this pkt 2270114018Sharti * but ran out of DRQs, in which case we saved the allocated mbuf 2271114018Sharti * on "q". 2272114018Sharti * 2. if we save an buf in "q" we store the "cur" (pointer) in the 2273114018Sharti * buf as an identity (that we can check later). 2274114018Sharti * 3. after this block of code, if m is still NULL then we ran out of 2275114018Sharti * mbufs 2276114018Sharti */ 2277114018Sharti _IF_DEQUEUE(&slot->q, m); 2278114018Sharti if (m != NULL) { 2279114018Sharti if (m->m_pkthdr.csum_data != cur) { 2280114018Sharti /* wasn't ours */ 2281114018Sharti DBG(sc, SERV, ("rx%td: q'ed buf %p not ours", 2282114018Sharti slot - sc->rxslot, m)); 2283114018Sharti _IF_PREPEND(&slot->q, m); 2284114018Sharti m = NULL; 2285114018Sharti EN_COUNT(sc->stats.rxqnotus); 2286114018Sharti } else { 2287114018Sharti EN_COUNT(sc->stats.rxqus); 2288114018Sharti DBG(sc, SERV, ("rx%td: recovered q'ed buf %p", 2289114018Sharti slot - sc->rxslot, m)); 2290114018Sharti } 2291114018Sharti } 2292114018Sharti if (mlen == 0 && m != NULL) { 2293114018Sharti /* should not happen */ 2294114018Sharti m_freem(m); 2295114018Sharti m = NULL; 2296114018Sharti } 229725603Skjc 2298114018Sharti if (mlen != 0 && m == NULL) { 2299114018Sharti m = en_mget(sc, mlen); 2300114018Sharti if (m == NULL) { 2301114018Sharti rx.post_skip += mlen; 2302114018Sharti mlen = 0; 2303114018Sharti EN_COUNT(sc->stats.rxmbufout); 2304114018Sharti DBG(sc, SERV, ("rx%td: out of mbufs", 2305114018Sharti slot - sc->rxslot)); 2306114018Sharti } else 2307114018Sharti rx.post_skip -= roundup(mlen, sizeof(uint32_t)) - mlen; 230825603Skjc 2309114018Sharti DBG(sc, SERV, ("rx%td: allocate buf %p, mlen=%d", 2310114018Sharti slot - sc->rxslot, m, mlen)); 2311114018Sharti } 231225603Skjc 2313114018Sharti DBG(sc, SERV, ("rx%td: VCI %d, rbuf %p, mlen %d, skip %u/%u", 2314118487Sharti slot - sc->rxslot, vc->vcc.vci, m, mlen, rx.pre_skip, 2315114018Sharti rx.post_skip)); 231625603Skjc 2317114018Sharti if (m != NULL) { 2318114018Sharti /* M_NOWAIT - called from interrupt context */ 2319114018Sharti map = uma_zalloc_arg(sc->map_zone, sc, M_NOWAIT); 2320132987Sgreen if (map == NULL) { 2321114018Sharti rx.post_skip += mlen; 2322114018Sharti m_freem(m); 2323114018Sharti DBG(sc, SERV, ("rx%td: out of maps", 2324114018Sharti slot - sc->rxslot)); 2325114018Sharti goto skip; 2326114018Sharti } 2327114018Sharti rx.m = m; 2328114018Sharti error = bus_dmamap_load_mbuf(sc->txtag, map->map, m, 2329117641Sharti en_rxdma_load, &rx, BUS_DMA_NOWAIT); 233025603Skjc 2331114018Sharti if (error != 0) { 2332162321Sglebius device_printf(sc->dev, "loading RX map failed " 2333114018Sharti "%d\n", error); 2334114018Sharti uma_zfree(sc->map_zone, map); 2335114018Sharti m_freem(m); 2336114018Sharti rx.post_skip += mlen; 2337114018Sharti goto skip; 233825603Skjc 2339114018Sharti } 2340114018Sharti map->flags |= ENMAP_LOADED; 234125603Skjc 2342114018Sharti if (rx.wait) { 2343114018Sharti /* out of DRQs - wait */ 2344114018Sharti uma_zfree(sc->map_zone, map); 234525603Skjc 2346114018Sharti m->m_pkthdr.csum_data = cur; 2347114018Sharti _IF_ENQUEUE(&slot->q, m); 2348114018Sharti EN_COUNT(sc->stats.rxdrqout); 234925603Skjc 2350114018Sharti sc->need_drqs = 1; /* flag condition */ 2351114018Sharti return; 235225603Skjc 2353114018Sharti } 2354114018Sharti (void)m_length(m, &lastm); 2355114018Sharti lastm->m_len -= roundup(mlen, sizeof(uint32_t)) - mlen; 235625603Skjc 2357114018Sharti m->m_pkthdr.rcvif = (void *)map; 2358114018Sharti _IF_ENQUEUE(&slot->indma, m); 235925603Skjc 2360114018Sharti /* get next packet in this slot */ 2361114018Sharti goto same_vci; 2362114018Sharti } 2363114018Sharti skip: 2364114018Sharti /* 2365114018Sharti * Here we end if we should drop the packet from the receive buffer. 2366114018Sharti * The number of bytes to drop is in fill. We can do this with on 2367114018Sharti * JK entry. If we don't even have that one - wait. 2368114018Sharti */ 2369114018Sharti if (sc->drq_free == 0) { 2370114018Sharti sc->need_drqs = 1; /* flag condition */ 2371114018Sharti return; 2372114018Sharti } 2373114018Sharti rx.post_skip += rx.pre_skip; 2374114018Sharti DBG(sc, SERV, ("rx%td: skipping %u", slot - sc->rxslot, rx.post_skip)); 237525603Skjc 2376114018Sharti /* advance buffer address */ 2377114018Sharti EN_WRAPADD(slot->start, slot->stop, cur, rx.post_skip); 237825603Skjc 2379114018Sharti /* write DRQ entry */ 2380114018Sharti if (sc->is_adaptec) 2381114018Sharti en_write(sc, sc->drq_us, 2382114018Sharti MID_MK_RXQ_ADP(WORD_IDX(slot->start, cur), 2383118487Sharti vc->vcc.vci, MID_DMA_END, MIDDMA_JK)); 2384114018Sharti else 2385114018Sharti en_write(sc, sc->drq_us, 2386114018Sharti MID_MK_RXQ_ENI(WORD_IDX(slot->start, cur), 2387118487Sharti vc->vcc.vci, MID_DMA_END, MIDDMA_JK)); 2388114018Sharti en_write(sc, sc->drq_us + 4, 0); 2389114018Sharti EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_us, 8); 2390114018Sharti sc->drq_free--; 239125603Skjc 2392114018Sharti /* signal to RX interrupt */ 2393114018Sharti sc->drq[MID_DRQ_A2REG(sc->drq_us)] = EN_DQ_MK(slot - sc->rxslot, 0); 2394114018Sharti slot->cur = cur; 239525603Skjc 2396114018Sharti /* signal to card */ 2397114018Sharti en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_us)); 239825603Skjc 2399114018Sharti goto same_vci; 240025603Skjc} 240125603Skjc 240225603Skjc/* 240325603Skjc * interrupt handler 2404114018Sharti * 2405114018Sharti * LOCK: unlocked, needed 240625603Skjc */ 2407114018Shartivoid 2408114018Shartien_intr(void *arg) 240925603Skjc{ 2410114018Sharti struct en_softc *sc = arg; 2411114018Sharti uint32_t reg, kick, mask; 2412114018Sharti int lcv, need_softserv; 241325603Skjc 2414114018Sharti EN_LOCK(sc); 241525603Skjc 2416114018Sharti reg = en_read(sc, MID_INTACK); 2417114018Sharti DBG(sc, INTR, ("interrupt=0x%b", reg, MID_INTBITS)); 241825603Skjc 2419114018Sharti if ((reg & MID_INT_ANY) == 0) { 2420114018Sharti EN_UNLOCK(sc); 2421114018Sharti return; 2422114018Sharti } 242325603Skjc 2424114018Sharti /* 2425114018Sharti * unexpected errors that need a reset 2426114018Sharti */ 2427114018Sharti if ((reg & (MID_INT_IDENT | MID_INT_LERR | MID_INT_DMA_ERR)) != 0) { 2428162321Sglebius device_printf(sc->dev, "unexpected interrupt=0x%b, " 2429114739Sharti "resetting\n", reg, MID_INTBITS); 243025603Skjc#ifdef EN_DEBUG 2431170013Srwatson panic("en: unexpected error"); 243225603Skjc#else 2433114018Sharti en_reset_ul(sc); 2434114018Sharti en_init(sc); 243525603Skjc#endif 2436114018Sharti EN_UNLOCK(sc); 2437114018Sharti return; 2438114018Sharti } 243925603Skjc 2440114018Sharti if (reg & MID_INT_SUNI) 2441116294Sharti utopia_intr(&sc->utopia); 244225603Skjc 2443114018Sharti kick = 0; 2444114018Sharti if (reg & MID_INT_TX) 2445114018Sharti kick |= en_intr_tx(sc, reg); 244625603Skjc 2447114018Sharti if (reg & MID_INT_DMA_TX) 2448114018Sharti kick |= en_intr_tx_dma(sc); 244925603Skjc 2450114018Sharti /* 2451114018Sharti * kick xmit channels as needed. 2452114018Sharti */ 2453114018Sharti if (kick) { 2454114018Sharti DBG(sc, INTR, ("tx kick mask = 0x%x", kick)); 2455114018Sharti for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) 2456114018Sharti if ((kick & mask) && _IF_QLEN(&sc->txslot[lcv].q) != 0) 2457114018Sharti en_txdma(sc, &sc->txslot[lcv]); 2458114018Sharti } 245925603Skjc 2460114018Sharti need_softserv = 0; 2461114018Sharti if (reg & MID_INT_DMA_RX) 2462114018Sharti need_softserv |= en_intr_rx_dma(sc); 246325603Skjc 2464114018Sharti if (reg & MID_INT_SERVICE) 2465114018Sharti need_softserv |= en_intr_service(sc); 246625603Skjc 2467114018Sharti if (need_softserv) 2468114018Sharti en_service(sc); 246925603Skjc 2470114018Sharti /* 2471114018Sharti * keep our stats 2472114018Sharti */ 2473114018Sharti if (reg & MID_INT_DMA_OVR) { 2474114018Sharti EN_COUNT(sc->stats.dmaovr); 2475114018Sharti DBG(sc, INTR, ("MID_INT_DMA_OVR")); 2476114018Sharti } 2477114018Sharti reg = en_read(sc, MID_STAT); 2478114018Sharti sc->stats.otrash += MID_OTRASH(reg); 2479114018Sharti sc->stats.vtrash += MID_VTRASH(reg); 248025603Skjc 2481114018Sharti EN_UNLOCK(sc); 2482114018Sharti} 248325603Skjc 2484116294Sharti/* 2485116294Sharti * Read at most n SUNI regs starting at reg into val 2486116294Sharti */ 2487116294Shartistatic int 2488116294Shartien_utopia_readregs(struct ifatm *ifatm, u_int reg, uint8_t *val, u_int *n) 2489116294Sharti{ 2490147256Sbrooks struct en_softc *sc = ifatm->ifp->if_softc; 2491116294Sharti u_int i; 2492116294Sharti 2493116294Sharti EN_CHECKLOCK(sc); 2494116294Sharti if (reg >= MID_NSUNI) 2495116294Sharti return (EINVAL); 2496116294Sharti if (reg + *n > MID_NSUNI) 2497116294Sharti *n = MID_NSUNI - reg; 2498116294Sharti 2499116294Sharti for (i = 0; i < *n; i++) 2500116294Sharti val[i] = en_read(sc, MID_SUNIOFF + 4 * (reg + i)); 2501116294Sharti 2502116294Sharti return (0); 2503116294Sharti} 2504116294Sharti 2505116294Sharti/* 2506116294Sharti * change the bits given by mask to them in val in register reg 2507116294Sharti */ 2508116294Shartistatic int 2509116294Shartien_utopia_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val) 2510116294Sharti{ 2511147256Sbrooks struct en_softc *sc = ifatm->ifp->if_softc; 2512116294Sharti uint32_t regval; 2513116294Sharti 2514116294Sharti EN_CHECKLOCK(sc); 2515116294Sharti if (reg >= MID_NSUNI) 2516116294Sharti return (EINVAL); 2517116294Sharti regval = en_read(sc, MID_SUNIOFF + 4 * reg); 2518116294Sharti regval = (regval & ~mask) | (val & mask); 2519116294Sharti en_write(sc, MID_SUNIOFF + 4 * reg, regval); 2520116294Sharti return (0); 2521116294Sharti} 2522116294Sharti 2523116294Shartistatic const struct utopia_methods en_utopia_methods = { 2524116294Sharti en_utopia_readregs, 2525116294Sharti en_utopia_writereg 2526116294Sharti}; 2527116294Sharti 2528114018Sharti/*********************************************************************/ 2529114018Sharti/* 2530114018Sharti * Probing the DMA brokeness of the card 2531114018Sharti */ 253225603Skjc 2533114018Sharti/* 2534114018Sharti * Physical address load helper function for DMA probe 2535114018Sharti * 2536114018Sharti * LOCK: unlocked, not needed 2537114018Sharti */ 2538114018Shartistatic void 2539114018Shartien_dmaprobe_load(void *uarg, bus_dma_segment_t *segs, int nseg, int error) 2540114018Sharti{ 2541114018Sharti if (error == 0) 2542114018Sharti *(bus_addr_t *)uarg = segs[0].ds_addr; 2543114018Sharti} 254425603Skjc 2545114018Sharti/* 2546114018Sharti * en_dmaprobe: helper function for en_attach. 2547114018Sharti * 2548114018Sharti * see how the card handles DMA by running a few DMA tests. we need 2549114018Sharti * to figure out the largest number of bytes we can DMA in one burst 2550114018Sharti * ("bestburstlen"), and if the starting address for a burst needs to 2551114018Sharti * be aligned on any sort of boundary or not ("alburst"). 2552114018Sharti * 2553114018Sharti * Things turn out more complex than that, because on my (harti) brand 2554114018Sharti * new motherboard (2.4GHz) we can do 64byte aligned DMAs, but everything 2555114018Sharti * we more than 4 bytes fails (with an RX DMA timeout) for physical 2556114018Sharti * addresses that end with 0xc. Therefor we search not only the largest 2557114018Sharti * burst that is supported (hopefully 64) but also check what is the largerst 2558114018Sharti * unaligned supported size. If that appears to be lesser than 4 words, 2559114018Sharti * set the noalbursts flag. That will be set only if also alburst is set. 2560114018Sharti */ 256146695Skjc 2562114018Sharti/* 2563114018Sharti * en_dmaprobe_doit: do actual testing for the DMA test. 2564114018Sharti * Cycle through all bursts sizes from 8 up to 64 and try whether it works. 2565114018Sharti * Return the largest one that works. 2566114018Sharti * 2567114018Sharti * LOCK: unlocked, not needed 2568114018Sharti */ 2569114018Shartistatic int 2570114018Shartien_dmaprobe_doit(struct en_softc *sc, uint8_t *sp, bus_addr_t psp) 2571114018Sharti{ 2572114018Sharti uint8_t *dp = sp + MIDDMA_MAXBURST; 2573114018Sharti bus_addr_t pdp = psp + MIDDMA_MAXBURST; 2574114018Sharti int lcv, retval = 4, cnt; 2575114018Sharti uint32_t reg, bcode, midvloc; 257646695Skjc 2577114018Sharti if (sc->en_busreset) 2578114018Sharti sc->en_busreset(sc); 2579114018Sharti en_write(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 258037939Skjc 2581114018Sharti /* 2582114018Sharti * set up a 1k buffer at MID_BUFOFF 2583114018Sharti */ 2584114018Sharti midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(uint32_t)) 2585114018Sharti >> MIDV_LOCTOPSHFT; 2586114018Sharti en_write(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc)); 2587114018Sharti en_write(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT) 2588114018Sharti | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH); 2589114018Sharti en_write(sc, MID_DST_RP(0), 0); 2590114018Sharti en_write(sc, MID_WP_ST_CNT(0), 0); 259125603Skjc 2592114018Sharti /* set up sample data */ 2593114018Sharti for (lcv = 0 ; lcv < MIDDMA_MAXBURST; lcv++) 2594114018Sharti sp[lcv] = lcv + 1; 259525603Skjc 2596114018Sharti /* enable DMA (only) */ 2597114018Sharti en_write(sc, MID_MAST_CSR, MID_MCSR_ENDMA); 259825603Skjc 2599114018Sharti sc->drq_chip = MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX)); 2600114018Sharti sc->dtq_chip = MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX)); 260125603Skjc 2602114018Sharti /* 2603114018Sharti * try it now . . . DMA it out, then DMA it back in and compare 2604114018Sharti * 2605114018Sharti * note: in order to get the dma stuff to reverse directions it wants 2606114018Sharti * the "end" flag set! since we are not dma'ing valid data we may 2607114018Sharti * get an ident mismatch interrupt (which we will ignore). 2608114018Sharti */ 2609114018Sharti DBG(sc, DMA, ("test sp=%p/%#lx, dp=%p/%#lx", 2610114018Sharti sp, (u_long)psp, dp, (u_long)pdp)); 2611114018Sharti for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) { 2612114018Sharti DBG(sc, DMA, ("test lcv=%d", lcv)); 261325603Skjc 2614114018Sharti /* zero SRAM and dest buffer */ 2615114018Sharti bus_space_set_region_4(sc->en_memt, sc->en_base, 2616114018Sharti MID_BUFOFF, 0, 1024 / 4); 2617114018Sharti bzero(dp, MIDDMA_MAXBURST); 261825603Skjc 2619114018Sharti bcode = en_sz2b(lcv); 262025603Skjc 2621114018Sharti /* build lcv-byte-DMA x NBURSTS */ 2622114018Sharti if (sc->is_adaptec) 2623114018Sharti en_write(sc, sc->dtq_chip, 2624114018Sharti MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0)); 2625114018Sharti else 2626114018Sharti en_write(sc, sc->dtq_chip, 2627114018Sharti MID_MK_TXQ_ENI(1, 0, MID_DMA_END, bcode)); 2628114018Sharti en_write(sc, sc->dtq_chip + 4, psp); 2629114018Sharti EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8); 2630114018Sharti en_write(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip)); 263125603Skjc 2632114018Sharti cnt = 1000; 2633114018Sharti while ((reg = en_readx(sc, MID_DMA_RDTX)) != 2634114018Sharti MID_DTQ_A2REG(sc->dtq_chip)) { 2635114018Sharti DELAY(1); 2636114018Sharti if (--cnt == 0) { 2637114018Sharti DBG(sc, DMA, ("unexpected timeout in tx " 2638114018Sharti "DMA test\n alignment=0x%lx, burst size=%d" 2639114018Sharti ", dma addr reg=%#x, rdtx=%#x, stat=%#x\n", 2640114018Sharti (u_long)sp & 63, lcv, 2641114018Sharti en_read(sc, MID_DMA_ADDR), reg, 2642114018Sharti en_read(sc, MID_INTSTAT))); 2643114018Sharti return (retval); 2644114018Sharti } 2645114018Sharti } 264625603Skjc 2647114018Sharti reg = en_read(sc, MID_INTACK); 2648114018Sharti if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) { 2649114018Sharti DBG(sc, DMA, ("unexpected status in tx DMA test: %#x\n", 2650114018Sharti reg)); 2651114018Sharti return (retval); 2652114018Sharti } 2653114018Sharti /* re-enable DMA (only) */ 2654114018Sharti en_write(sc, MID_MAST_CSR, MID_MCSR_ENDMA); 265525603Skjc 2656114018Sharti /* "return to sender..." address is known ... */ 265725603Skjc 2658114018Sharti /* build lcv-byte-DMA x NBURSTS */ 2659114018Sharti if (sc->is_adaptec) 2660114018Sharti en_write(sc, sc->drq_chip, 2661114018Sharti MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0)); 2662114018Sharti else 2663114018Sharti en_write(sc, sc->drq_chip, 2664114018Sharti MID_MK_RXQ_ENI(1, 0, MID_DMA_END, bcode)); 2665114018Sharti en_write(sc, sc->drq_chip + 4, pdp); 2666114018Sharti EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8); 2667114018Sharti en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip)); 2668114018Sharti cnt = 1000; 2669114018Sharti while ((reg = en_readx(sc, MID_DMA_RDRX)) != 2670114018Sharti MID_DRQ_A2REG(sc->drq_chip)) { 2671114018Sharti DELAY(1); 2672114018Sharti cnt--; 2673114018Sharti if (--cnt == 0) { 2674114018Sharti DBG(sc, DMA, ("unexpected timeout in rx " 2675114018Sharti "DMA test, rdrx=%#x\n", reg)); 2676114018Sharti return (retval); 2677114018Sharti } 2678114018Sharti } 2679114018Sharti reg = en_read(sc, MID_INTACK); 2680114018Sharti if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) { 2681114018Sharti DBG(sc, DMA, ("unexpected status in rx DMA " 2682114018Sharti "test: 0x%x\n", reg)); 2683114018Sharti return (retval); 2684114018Sharti } 2685114018Sharti if (bcmp(sp, dp, lcv)) { 2686114018Sharti DBG(sc, DMA, ("DMA test failed! lcv=%d, sp=%p, " 2687114018Sharti "dp=%p", lcv, sp, dp)); 2688114018Sharti return (retval); 2689114018Sharti } 269025603Skjc 2691114018Sharti retval = lcv; 2692114018Sharti } 2693114018Sharti return (retval); /* studly 64 byte DMA present! oh baby!! */ 269425603Skjc} 269525603Skjc 269625603Skjc/* 2697114018Sharti * Find the best DMA parameters 269825603Skjc * 2699114018Sharti * LOCK: unlocked, not needed 270025603Skjc */ 2701114018Shartistatic void 2702114018Shartien_dmaprobe(struct en_softc *sc) 2703114018Sharti{ 2704114018Sharti bus_dma_tag_t tag; 2705114018Sharti bus_dmamap_t map; 2706114018Sharti int err; 2707114018Sharti void *buffer; 2708114018Sharti int bestalgn, lcv, try, bestnoalgn; 2709114018Sharti bus_addr_t phys; 2710114018Sharti uint8_t *addr; 271125603Skjc 2712114018Sharti sc->alburst = 0; 2713114018Sharti sc->noalbursts = 0; 271425603Skjc 2715114018Sharti /* 2716114018Sharti * Allocate some DMA-able memory. 2717114018Sharti * We need 3 times the max burst size aligned to the max burst size. 2718114018Sharti */ 2719233024Sscottl err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), MIDDMA_MAXBURST, 0, 2720114018Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2721117641Sharti 3 * MIDDMA_MAXBURST, 1, 3 * MIDDMA_MAXBURST, 0, 2722117641Sharti NULL, NULL, &tag); 2723114018Sharti if (err) 2724114018Sharti panic("%s: cannot create test DMA tag %d", __func__, err); 272525603Skjc 2726114018Sharti err = bus_dmamem_alloc(tag, &buffer, 0, &map); 2727114018Sharti if (err) 2728114018Sharti panic("%s: cannot allocate test DMA memory %d", __func__, err); 272925603Skjc 2730114018Sharti err = bus_dmamap_load(tag, map, buffer, 3 * MIDDMA_MAXBURST, 2731117641Sharti en_dmaprobe_load, &phys, BUS_DMA_NOWAIT); 2732114018Sharti if (err) 2733114018Sharti panic("%s: cannot load test DMA map %d", __func__, err); 2734114018Sharti addr = buffer; 2735114018Sharti DBG(sc, DMA, ("phys=%#lx addr=%p", (u_long)phys, addr)); 273625603Skjc 2737114018Sharti /* 2738114018Sharti * Now get the best burst size of the aligned case. 2739114018Sharti */ 2740114018Sharti bestalgn = bestnoalgn = en_dmaprobe_doit(sc, addr, phys); 274125603Skjc 2742114018Sharti /* 2743114018Sharti * Now try unaligned. 2744114018Sharti */ 2745114018Sharti for (lcv = 4; lcv < MIDDMA_MAXBURST; lcv += 4) { 2746114018Sharti try = en_dmaprobe_doit(sc, addr + lcv, phys + lcv); 274725603Skjc 2748114018Sharti if (try < bestnoalgn) 2749114018Sharti bestnoalgn = try; 2750114018Sharti } 275125603Skjc 2752114018Sharti if (bestnoalgn < bestalgn) { 2753114018Sharti sc->alburst = 1; 2754114018Sharti if (bestnoalgn < 32) 2755114018Sharti sc->noalbursts = 1; 2756114018Sharti } 275725603Skjc 2758114018Sharti sc->bestburstlen = bestalgn; 2759114018Sharti sc->bestburstshift = en_log2(bestalgn); 2760114018Sharti sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */ 2761114018Sharti sc->bestburstcode = en_sz2b(bestalgn); 276225603Skjc 2763114018Sharti /* 2764114018Sharti * Reset the chip before freeing the buffer. It may still be trying 2765114018Sharti * to DMA. 2766114018Sharti */ 2767114018Sharti if (sc->en_busreset) 2768114018Sharti sc->en_busreset(sc); 2769114018Sharti en_write(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 277025603Skjc 2771114018Sharti DELAY(10000); /* may still do DMA */ 2772114018Sharti 2773114018Sharti /* 2774114018Sharti * Free the DMA stuff 2775114018Sharti */ 2776114018Sharti bus_dmamap_unload(tag, map); 2777114018Sharti bus_dmamem_free(tag, buffer, map); 2778114018Sharti bus_dma_tag_destroy(tag); 2779114018Sharti} 2780114018Sharti 2781114018Sharti/*********************************************************************/ 2782114018Sharti/* 2783114018Sharti * Attach/detach. 2784114018Sharti */ 2785114018Sharti 2786114018Sharti/* 2787114018Sharti * Attach to the card. 2788114018Sharti * 2789114018Sharti * LOCK: unlocked, not needed (but initialized) 2790114018Sharti */ 2791114018Shartiint 2792114018Shartien_attach(struct en_softc *sc) 2793114018Sharti{ 2794147256Sbrooks struct ifnet *ifp = sc->ifp; 2795114018Sharti int sz; 2796114018Sharti uint32_t reg, lcv, check, ptr, sav, midvloc; 2797114018Sharti 279825603Skjc#ifdef EN_DEBUG 2799114018Sharti sc->debug = EN_DEBUG; 280025603Skjc#endif 2801147256Sbrooks 2802114018Sharti /* 2803114018Sharti * Probe card to determine memory size. 2804114018Sharti * 2805114018Sharti * The stupid ENI card always reports to PCI that it needs 4MB of 2806114018Sharti * space (2MB regs and 2MB RAM). If it has less than 2MB RAM the 2807114018Sharti * addresses wrap in the RAM address space (i.e. on a 512KB card 2808114018Sharti * addresses 0x3ffffc, 0x37fffc, and 0x2ffffc are aliases for 2809114018Sharti * 0x27fffc [note that RAM starts at offset 0x200000]). 2810114018Sharti */ 281125603Skjc 2812114018Sharti /* reset card before touching RAM */ 2813114018Sharti if (sc->en_busreset) 2814114018Sharti sc->en_busreset(sc); 2815114018Sharti en_write(sc, MID_RESID, 0x0); 281625603Skjc 2817114018Sharti for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) { 2818114018Sharti en_write(sc, lcv, lcv); /* data[address] = address */ 2819114018Sharti for (check = MID_PROBEOFF; check < lcv ;check += MID_PROBSIZE) { 2820114018Sharti reg = en_read(sc, check); 2821114018Sharti if (reg != check) 2822114018Sharti /* found an alias! - quit */ 2823114018Sharti goto done_probe; 2824114018Sharti } 2825114018Sharti } 2826114018Sharti done_probe: 2827114018Sharti lcv -= MID_PROBSIZE; /* take one step back */ 2828114018Sharti sc->en_obmemsz = (lcv + 4) - MID_RAMOFF; 282925603Skjc 2830114018Sharti /* 2831114018Sharti * determine the largest DMA burst supported 2832114018Sharti */ 2833114018Sharti en_dmaprobe(sc); 283425603Skjc 2835114018Sharti /* 2836114018Sharti * "hello world" 2837114018Sharti */ 283825603Skjc 2839114018Sharti /* reset */ 2840114018Sharti if (sc->en_busreset) 2841114018Sharti sc->en_busreset(sc); 2842114018Sharti en_write(sc, MID_RESID, 0x0); /* reset */ 284325603Skjc 2844114018Sharti /* zero memory */ 2845114018Sharti bus_space_set_region_4(sc->en_memt, sc->en_base, 2846114018Sharti MID_RAMOFF, 0, sc->en_obmemsz / 4); 284725603Skjc 2848114018Sharti reg = en_read(sc, MID_RESID); 284946695Skjc 2850162321Sglebius device_printf(sc->dev, "ATM midway v%d, board IDs %d.%d, %s%s%s, " 2851114018Sharti "%ldKB on-board RAM\n", MID_VER(reg), MID_MID(reg), MID_DID(reg), 2852114018Sharti (MID_IS_SABRE(reg)) ? "sabre controller, " : "", 2853114018Sharti (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia", 2854114018Sharti (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "", 2855114018Sharti (long)sc->en_obmemsz / 1024); 285646695Skjc 2857114739Sharti /* 2858114739Sharti * fill in common ATM interface stuff 2859114739Sharti */ 2860147256Sbrooks IFP2IFATM(sc->ifp)->mib.hw_version = (MID_VER(reg) << 16) | 2861114739Sharti (MID_MID(reg) << 8) | MID_DID(reg); 2862114739Sharti if (MID_DID(reg) & 0x4) 2863147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_155; 2864114739Sharti else 2865147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155; 2866114739Sharti 2867147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M; 2868147256Sbrooks IFP2IFATM(sc->ifp)->mib.vpi_bits = 0; 2869147256Sbrooks IFP2IFATM(sc->ifp)->mib.vci_bits = MID_VCI_BITS; 2870147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vccs = MID_N_VC; 2871147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vpcs = 0; 2872114739Sharti 2873114018Sharti if (sc->is_adaptec) { 2874147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_ADP155P; 2875114018Sharti if (sc->bestburstlen == 64 && sc->alburst == 0) 2876162321Sglebius device_printf(sc->dev, 2877114739Sharti "passed 64 byte DMA test\n"); 2878114018Sharti else 2879162321Sglebius device_printf(sc->dev, "FAILED DMA TEST: " 2880114739Sharti "burst=%d, alburst=%d\n", sc->bestburstlen, 2881114739Sharti sc->alburst); 2882114018Sharti } else { 2883147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_ENI155P; 2884162321Sglebius device_printf(sc->dev, "maximum DMA burst length = %d " 2885114739Sharti "bytes%s\n", sc->bestburstlen, sc->alburst ? 2886114739Sharti sc->noalbursts ? " (no large bursts)" : " (must align)" : 2887114739Sharti ""); 288846695Skjc } 288946695Skjc 2890114018Sharti /* 2891114018Sharti * link into network subsystem and prepare card 2892114018Sharti */ 2893147256Sbrooks sc->ifp->if_softc = sc; 2894114018Sharti ifp->if_flags = IFF_SIMPLEX; 2895114018Sharti ifp->if_ioctl = en_ioctl; 2896114018Sharti ifp->if_start = en_start; 289746695Skjc 2898115833Sharti mtx_init(&sc->en_mtx, device_get_nameunit(sc->dev), 2899115833Sharti MTX_NETWORK_LOCK, MTX_DEF); 2900118494Sharti cv_init(&sc->cv_close, "VC close"); 2901115833Sharti 2902114018Sharti /* 2903114018Sharti * Make the sysctl tree 2904114018Sharti */ 2905114018Sharti sysctl_ctx_init(&sc->sysctl_ctx); 290625603Skjc 2907114018Sharti if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 2908114201Sharti SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO, 2909114018Sharti device_get_nameunit(sc->dev), CTLFLAG_RD, 0, "")) == NULL) 2910114018Sharti goto fail; 291125603Skjc 2912114018Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2913217556Smdf OID_AUTO, "istats", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, 2914217556Smdf en_sysctl_istats, "S", "internal statistics") == NULL) 2915114018Sharti goto fail; 291625603Skjc 291725603Skjc#ifdef EN_DEBUG 2918114018Sharti if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2919114018Sharti OID_AUTO, "debug", CTLFLAG_RW , &sc->debug, 0, "") == NULL) 2920114018Sharti goto fail; 292125603Skjc#endif 292225603Skjc 2923147256Sbrooks IFP2IFATM(sc->ifp)->phy = &sc->utopia; 2924147256Sbrooks utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->en_mtx, 2925116294Sharti &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2926116294Sharti &en_utopia_methods); 2927116294Sharti utopia_init_media(&sc->utopia); 2928116294Sharti 2929248078Smarius MGET(sc->padbuf, M_WAITOK, MT_DATA); 2930114018Sharti bzero(sc->padbuf->m_data, MLEN); 293125603Skjc 2932233024Sscottl if (bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 2933114018Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2934117641Sharti EN_TXSZ * 1024, EN_MAX_DMASEG, EN_TXSZ * 1024, 0, 2935117641Sharti NULL, NULL, &sc->txtag)) 2936114018Sharti goto fail; 293725603Skjc 2938114018Sharti sc->map_zone = uma_zcreate("en dma maps", sizeof(struct en_map), 2939114018Sharti en_map_ctor, en_map_dtor, NULL, en_map_fini, UMA_ALIGN_PTR, 2940114018Sharti UMA_ZONE_ZINIT); 2941114018Sharti if (sc->map_zone == NULL) 2942114018Sharti goto fail; 2943114018Sharti uma_zone_set_max(sc->map_zone, EN_MAX_MAPS); 294425603Skjc 2945114018Sharti /* 2946114018Sharti * init softc 2947114018Sharti */ 2948118487Sharti sc->vccs = malloc(MID_N_VC * sizeof(sc->vccs[0]), 2949118487Sharti M_DEVBUF, M_ZERO | M_WAITOK); 295025603Skjc 2951114018Sharti sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF); 2952114018Sharti ptr = sav = MID_BUFOFF; 2953114018Sharti ptr = roundup(ptr, EN_TXSZ * 1024); /* align */ 2954114018Sharti sz = sz - (ptr - sav); 2955114018Sharti if (EN_TXSZ*1024 * EN_NTX > sz) { 2956162321Sglebius device_printf(sc->dev, "EN_NTX/EN_TXSZ too big\n"); 2957114018Sharti goto fail; 2958114018Sharti } 2959114018Sharti for (lcv = 0 ;lcv < EN_NTX ;lcv++) { 2960114018Sharti sc->txslot[lcv].mbsize = 0; 2961114018Sharti sc->txslot[lcv].start = ptr; 2962114018Sharti ptr += (EN_TXSZ * 1024); 2963114018Sharti sz -= (EN_TXSZ * 1024); 2964114018Sharti sc->txslot[lcv].stop = ptr; 2965114018Sharti sc->txslot[lcv].nref = 0; 2966114018Sharti DBG(sc, INIT, ("tx%d: start 0x%x, stop 0x%x", lcv, 2967114018Sharti sc->txslot[lcv].start, sc->txslot[lcv].stop)); 2968114018Sharti } 296925603Skjc 2970114018Sharti sav = ptr; 2971114018Sharti ptr = roundup(ptr, EN_RXSZ * 1024); /* align */ 2972114018Sharti sz = sz - (ptr - sav); 2973114018Sharti sc->en_nrx = sz / (EN_RXSZ * 1024); 2974114018Sharti if (sc->en_nrx <= 0) { 2975162321Sglebius device_printf(sc->dev, "EN_NTX/EN_TXSZ/EN_RXSZ too big\n"); 2976114018Sharti goto fail; 2977114018Sharti } 297825603Skjc 2979114018Sharti /* 2980114018Sharti * ensure that there is always one VC slot on the service list free 2981114018Sharti * so that we can tell the difference between a full and empty list. 2982114018Sharti */ 2983114018Sharti if (sc->en_nrx >= MID_N_VC) 2984114018Sharti sc->en_nrx = MID_N_VC - 1; 298525603Skjc 2986114018Sharti for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) { 2987118487Sharti sc->rxslot[lcv].vcc = NULL; 2988114018Sharti midvloc = sc->rxslot[lcv].start = ptr; 2989114018Sharti ptr += (EN_RXSZ * 1024); 2990114018Sharti sz -= (EN_RXSZ * 1024); 2991114018Sharti sc->rxslot[lcv].stop = ptr; 2992114018Sharti midvloc = midvloc - MID_RAMOFF; 2993114018Sharti /* mask, cvt to words */ 2994114018Sharti midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2; 2995114018Sharti /* we only want the top 11 bits */ 2996114018Sharti midvloc = midvloc >> MIDV_LOCTOPSHFT; 2997114018Sharti midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT; 2998114018Sharti sc->rxslot[lcv].mode = midvloc | 2999114018Sharti (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH; 300025603Skjc 3001114018Sharti DBG(sc, INIT, ("rx%d: start 0x%x, stop 0x%x, mode 0x%x", lcv, 3002114018Sharti sc->rxslot[lcv].start, sc->rxslot[lcv].stop, 3003114018Sharti sc->rxslot[lcv].mode)); 3004114018Sharti } 300525603Skjc 3006162321Sglebius device_printf(sc->dev, "%d %dKB receive buffers, %d %dKB transmit " 3007114018Sharti "buffers\n", sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ); 3008162321Sglebius device_printf(sc->dev, "end station identifier (mac address) " 3009147256Sbrooks "%6D\n", IFP2IFATM(sc->ifp)->mib.esi, ":"); 301025603Skjc 3011114018Sharti /* 3012116294Sharti * Start SUNI stuff. This will call our readregs/writeregs 3013116294Sharti * functions and these assume the lock to be held so we must get it 3014116294Sharti * here. 3015116294Sharti */ 3016116294Sharti EN_LOCK(sc); 3017116294Sharti utopia_start(&sc->utopia); 3018116294Sharti utopia_reset(&sc->utopia); 3019116294Sharti EN_UNLOCK(sc); 3020116294Sharti 3021116294Sharti /* 3022114018Sharti * final commit 3023114018Sharti */ 3024114018Sharti atm_ifattach(ifp); 302525603Skjc 3026114018Sharti#ifdef ENABLE_BPF 3027114018Sharti bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc)); 302825603Skjc#endif 302925603Skjc 3030114018Sharti return (0); 303125603Skjc 3032114018Sharti fail: 3033114018Sharti en_destroy(sc); 3034114018Sharti return (-1); 3035114018Sharti} 303625603Skjc 3037114018Sharti/* 3038114018Sharti * Free all internal resources. No access to bus resources here. 3039114018Sharti * No locking required here (interrupt is already disabled). 3040114018Sharti * 3041116294Sharti * LOCK: unlocked, needed (but destroyed) 3042114018Sharti */ 3043114018Shartivoid 3044114018Shartien_destroy(struct en_softc *sc) 3045114018Sharti{ 3046118487Sharti u_int i; 3047116294Sharti 3048116294Sharti if (sc->utopia.state & UTP_ST_ATTACHED) { 3049116294Sharti /* these assume the lock to be held */ 3050116294Sharti EN_LOCK(sc); 3051116294Sharti utopia_stop(&sc->utopia); 3052116294Sharti utopia_detach(&sc->utopia); 3053116294Sharti EN_UNLOCK(sc); 3054116294Sharti } 3055116294Sharti 3056118487Sharti if (sc->vccs != NULL) { 3057118487Sharti /* get rid of sticky VCCs */ 3058118487Sharti for (i = 0; i < MID_N_VC; i++) 3059118487Sharti if (sc->vccs[i] != NULL) 3060118487Sharti uma_zfree(en_vcc_zone, sc->vccs[i]); 3061118487Sharti free(sc->vccs, M_DEVBUF); 3062118487Sharti } 3063118487Sharti 3064114018Sharti if (sc->padbuf != NULL) 3065114018Sharti m_free(sc->padbuf); 306625603Skjc 3067114018Sharti /* 3068114018Sharti * Destroy the map zone before the tag (the fini function will 3069114018Sharti * destroy the DMA maps using the tag) 3070114018Sharti */ 3071114018Sharti if (sc->map_zone != NULL) 3072114018Sharti uma_zdestroy(sc->map_zone); 307325603Skjc 3074114018Sharti if (sc->txtag != NULL) 3075114018Sharti bus_dma_tag_destroy(sc->txtag); 307625603Skjc 3077114018Sharti (void)sysctl_ctx_free(&sc->sysctl_ctx); 307825603Skjc 3079118494Sharti cv_destroy(&sc->cv_close); 3080114018Sharti mtx_destroy(&sc->en_mtx); 308125603Skjc} 308225603Skjc 3083118487Sharti/* 3084118487Sharti * Module loaded/unloaded 3085118487Sharti */ 3086118487Shartiint 3087118487Shartien_modevent(module_t mod __unused, int event, void *arg __unused) 3088118487Sharti{ 3089118487Sharti 3090118487Sharti switch (event) { 3091118487Sharti 3092118487Sharti case MOD_LOAD: 3093118487Sharti en_vcc_zone = uma_zcreate("EN vccs", sizeof(struct en_vcc), 3094118487Sharti NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3095118487Sharti if (en_vcc_zone == NULL) 3096118487Sharti return (ENOMEM); 3097118487Sharti break; 3098118487Sharti 3099118487Sharti case MOD_UNLOAD: 3100118487Sharti uma_zdestroy(en_vcc_zone); 3101118487Sharti break; 3102118487Sharti } 3103118487Sharti return (0); 3104118487Sharti} 3105118487Sharti 3106114018Sharti/*********************************************************************/ 3107114018Sharti/* 3108114018Sharti * Debugging support 3109114018Sharti */ 311025603Skjc 311125603Skjc#ifdef EN_DDBHOOK 311225603Skjc/* 311325603Skjc * functions we can call from ddb 311425603Skjc */ 311525603Skjc 311625603Skjc/* 311725603Skjc * en_dump: dump the state 311825603Skjc */ 311925603Skjc#define END_SWSL 0x00000040 /* swsl state */ 312025603Skjc#define END_DRQ 0x00000020 /* drq state */ 312125603Skjc#define END_DTQ 0x00000010 /* dtq state */ 312225603Skjc#define END_RX 0x00000008 /* rx state */ 312325603Skjc#define END_TX 0x00000004 /* tx state */ 312425603Skjc#define END_MREGS 0x00000002 /* registers */ 312525603Skjc#define END_STATS 0x00000001 /* dump stats */ 312625603Skjc 312725603Skjc#define END_BITS "\20\7SWSL\6DRQ\5DTQ\4RX\3TX\2MREGS\1STATS" 312825603Skjc 3129114018Shartistatic void 3130114018Shartien_dump_stats(const struct en_stats *s) 3131114018Sharti{ 3132114018Sharti printf("en_stats:\n"); 3133114018Sharti printf("\t%d/%d mfix (%d failed)\n", s->mfixaddr, s->mfixlen, 3134114018Sharti s->mfixfail); 3135114018Sharti printf("\t%d rx dma overflow interrupts\n", s->dmaovr); 3136114018Sharti printf("\t%d times out of TX space and stalled\n", s->txoutspace); 3137114018Sharti printf("\t%d times out of DTQs\n", s->txdtqout); 3138114018Sharti printf("\t%d times launched a packet\n", s->launch); 3139114018Sharti printf("\t%d times pulled the hw service list\n", s->hwpull); 3140114018Sharti printf("\t%d times pushed a vci on the sw service list\n", s->swadd); 3141114018Sharti printf("\t%d times RX pulled an mbuf from Q that wasn't ours\n", 3142114018Sharti s->rxqnotus); 3143114018Sharti printf("\t%d times RX pulled a good mbuf from Q\n", s->rxqus); 3144114018Sharti printf("\t%d times ran out of DRQs\n", s->rxdrqout); 3145114018Sharti printf("\t%d transmit packets dropped due to mbsize\n", s->txmbovr); 3146114018Sharti printf("\t%d cells trashed due to turned off rxvc\n", s->vtrash); 3147114018Sharti printf("\t%d cells trashed due to totally full buffer\n", s->otrash); 3148114018Sharti printf("\t%d cells trashed due almost full buffer\n", s->ttrash); 3149114018Sharti printf("\t%d rx mbuf allocation failures\n", s->rxmbufout); 3150114018Sharti printf("\t%d times out of tx maps\n", s->txnomap); 3151114018Sharti#ifdef NATM 3152114018Sharti#ifdef NATM_STAT 3153114018Sharti printf("\tnatmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n", 3154114018Sharti natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes); 3155114018Sharti#endif 3156114018Sharti#endif 3157114018Sharti} 315825603Skjc 3159114018Shartistatic void 3160114018Shartien_dump_mregs(struct en_softc *sc) 3161114018Sharti{ 3162114018Sharti u_int cnt; 316325603Skjc 3164114018Sharti printf("mregs:\n"); 3165114018Sharti printf("resid = 0x%x\n", en_read(sc, MID_RESID)); 3166114018Sharti printf("interrupt status = 0x%b\n", 3167114018Sharti (int)en_read(sc, MID_INTSTAT), MID_INTBITS); 3168114018Sharti printf("interrupt enable = 0x%b\n", 3169114018Sharti (int)en_read(sc, MID_INTENA), MID_INTBITS); 3170114018Sharti printf("mcsr = 0x%b\n", (int)en_read(sc, MID_MAST_CSR), MID_MCSRBITS); 3171114018Sharti printf("serv_write = [chip=%u] [us=%u]\n", en_read(sc, MID_SERV_WRITE), 3172114018Sharti MID_SL_A2REG(sc->hwslistp)); 3173114018Sharti printf("dma addr = 0x%x\n", en_read(sc, MID_DMA_ADDR)); 3174114018Sharti printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3175114018Sharti MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX)), 3176114018Sharti MID_DRQ_REG2A(en_read(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us); 3177114018Sharti printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3178114018Sharti MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX)), 3179114018Sharti MID_DTQ_REG2A(en_read(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us); 3180114018Sharti 3181114018Sharti printf(" unusal txspeeds:"); 3182114018Sharti for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3183118487Sharti if (sc->vccs[cnt]->txspeed) 3184118487Sharti printf(" vci%d=0x%x", cnt, sc->vccs[cnt]->txspeed); 3185114018Sharti printf("\n"); 3186114018Sharti 3187114018Sharti printf(" rxvc slot mappings:"); 3188114018Sharti for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3189118487Sharti if (sc->vccs[cnt]->rxslot != NULL) 3190156951Sharti printf(" %d->%td", cnt, 3191118487Sharti sc->vccs[cnt]->rxslot - sc->rxslot); 3192114018Sharti printf("\n"); 3193114018Sharti} 3194114018Sharti 3195114018Shartistatic void 3196114018Shartien_dump_tx(struct en_softc *sc) 319725603Skjc{ 3198114018Sharti u_int slot; 319925603Skjc 3200114018Sharti printf("tx:\n"); 3201114018Sharti for (slot = 0 ; slot < EN_NTX; slot++) { 3202114018Sharti printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d] ", slot, 3203114018Sharti sc->txslot[slot].start, sc->txslot[slot].stop, 3204114018Sharti sc->txslot[slot].cur, 3205114018Sharti (sc->txslot[slot].cur - sc->txslot[slot].start) / 4); 3206114018Sharti printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize, 3207114018Sharti sc->txslot[slot].bfree); 3208114018Sharti printf("txhw: base_address=0x%x, size=%u, read=%u, " 3209114018Sharti "descstart=%u\n", 3210114018Sharti (u_int)MIDX_BASE(en_read(sc, MIDX_PLACE(slot))), 3211114018Sharti MIDX_SZ(en_read(sc, MIDX_PLACE(slot))), 3212114018Sharti en_read(sc, MIDX_READPTR(slot)), 3213114018Sharti en_read(sc, MIDX_DESCSTART(slot))); 3214114018Sharti } 3215114018Sharti} 321625603Skjc 3217114018Shartistatic void 3218114018Shartien_dump_rx(struct en_softc *sc) 3219114018Sharti{ 3220118487Sharti struct en_rxslot *slot; 322125603Skjc 3222114018Sharti printf(" recv slots:\n"); 3223118487Sharti for (slot = sc->rxslot ; slot < &sc->rxslot[sc->en_nrx]; slot++) { 3224156951Sharti printf("rx%td: start/stop/cur=0x%x/0x%x/0x%x mode=0x%x ", 3225118487Sharti slot - sc->rxslot, slot->start, slot->stop, slot->cur, 3226118487Sharti slot->mode); 3227118487Sharti if (slot->vcc != NULL) { 3228118487Sharti printf("vci=%u\n", slot->vcc->vcc.vci); 3229118487Sharti printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n", 3230118487Sharti en_read(sc, MID_VC(slot->vcc->vcc.vci)), 3231118487Sharti en_read(sc, MID_DST_RP(slot->vcc->vcc.vci)), 3232118487Sharti en_read(sc, MID_WP_ST_CNT(slot->vcc->vcc.vci))); 3233118487Sharti } 3234114018Sharti } 3235114018Sharti} 323625603Skjc 3237114018Sharti/* 3238114018Sharti * This is only correct for non-adaptec adapters 3239114018Sharti */ 3240114018Shartistatic void 3241114018Shartien_dump_dtqs(struct en_softc *sc) 3242114018Sharti{ 3243114018Sharti uint32_t ptr, reg; 324425603Skjc 3245114018Sharti printf(" dtq [need_dtqs=%d,dtq_free=%d]:\n", sc->need_dtqs, 3246114018Sharti sc->dtq_free); 3247114018Sharti ptr = sc->dtq_chip; 3248114018Sharti while (ptr != sc->dtq_us) { 3249114018Sharti reg = en_read(sc, ptr); 3250114018Sharti printf("\t0x%x=[%#x cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3251114018Sharti sc->dtq[MID_DTQ_A2REG(ptr)], reg, MID_DMA_CNT(reg), 3252114018Sharti MID_DMA_TXCHAN(reg), (reg & MID_DMA_END) != 0, 3253114018Sharti MID_DMA_TYPE(reg), en_read(sc, ptr + 4)); 3254114018Sharti EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8); 3255114018Sharti } 3256114018Sharti} 325725603Skjc 3258114018Shartistatic void 3259114018Shartien_dump_drqs(struct en_softc *sc) 3260114018Sharti{ 3261114018Sharti uint32_t ptr, reg; 326225603Skjc 3263114018Sharti printf(" drq [need_drqs=%d,drq_free=%d]:\n", sc->need_drqs, 3264114018Sharti sc->drq_free); 3265114018Sharti ptr = sc->drq_chip; 3266114018Sharti while (ptr != sc->drq_us) { 3267114018Sharti reg = en_read(sc, ptr); 3268114018Sharti printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3269114018Sharti sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg), 3270114018Sharti MID_DMA_RXVCI(reg), (reg & MID_DMA_END) != 0, 3271114018Sharti MID_DMA_TYPE(reg), en_read(sc, ptr + 4)); 3272114018Sharti EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8); 3273114018Sharti } 3274114018Sharti} 327525603Skjc 3276114018Sharti/* Do not staticize - meant for calling from DDB! */ 3277114018Shartiint 3278114018Shartien_dump(int unit, int level) 3279114018Sharti{ 3280114018Sharti struct en_softc *sc; 3281114018Sharti int lcv, cnt; 3282114018Sharti devclass_t dc; 3283114018Sharti int maxunit; 328425603Skjc 3285114018Sharti dc = devclass_find("en"); 3286114018Sharti if (dc == NULL) { 3287114018Sharti printf("%s: can't find devclass!\n", __func__); 3288114018Sharti return (0); 3289114018Sharti } 3290114018Sharti maxunit = devclass_get_maxunit(dc); 3291114018Sharti for (lcv = 0 ; lcv < maxunit ; lcv++) { 3292114018Sharti sc = devclass_get_softc(dc, lcv); 3293114018Sharti if (sc == NULL) 3294114018Sharti continue; 3295114018Sharti if (unit != -1 && unit != lcv) 3296114018Sharti continue; 329725603Skjc 3298162321Sglebius device_printf(sc->dev, "dumping device at level 0x%b\n", 3299114018Sharti level, END_BITS); 330025603Skjc 3301114018Sharti if (sc->dtq_us == 0) { 3302114018Sharti printf("<hasn't been en_init'd yet>\n"); 3303114018Sharti continue; 3304114018Sharti } 330525603Skjc 3306114018Sharti if (level & END_STATS) 3307114018Sharti en_dump_stats(&sc->stats); 3308114018Sharti if (level & END_MREGS) 3309114018Sharti en_dump_mregs(sc); 3310114018Sharti if (level & END_TX) 3311114018Sharti en_dump_tx(sc); 3312114018Sharti if (level & END_RX) 3313114018Sharti en_dump_rx(sc); 3314114018Sharti if (level & END_DTQ) 3315114018Sharti en_dump_dtqs(sc); 3316114018Sharti if (level & END_DRQ) 3317114018Sharti en_dump_drqs(sc); 331825603Skjc 3319114018Sharti if (level & END_SWSL) { 3320114018Sharti printf(" swslist [size=%d]: ", sc->swsl_size); 3321114018Sharti for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ; 3322114018Sharti cnt = (cnt + 1) % MID_SL_N) 3323114018Sharti printf("0x%x ", sc->swslist[cnt]); 3324114018Sharti printf("\n"); 3325114018Sharti } 3326114018Sharti } 3327114018Sharti return (0); 332825603Skjc} 332925603Skjc 333025603Skjc/* 333125603Skjc * en_dumpmem: dump the memory 3332114018Sharti * 3333114018Sharti * Do not staticize - meant for calling from DDB! 333425603Skjc */ 3335114018Shartiint 3336114018Shartien_dumpmem(int unit, int addr, int len) 333725603Skjc{ 3338114018Sharti struct en_softc *sc; 3339114018Sharti uint32_t reg; 3340114018Sharti devclass_t dc; 334125603Skjc 3342114018Sharti dc = devclass_find("en"); 3343114018Sharti if (dc == NULL) { 3344114018Sharti printf("%s: can't find devclass\n", __func__); 3345114018Sharti return (0); 3346114018Sharti } 3347114018Sharti sc = devclass_get_softc(dc, unit); 3348114018Sharti if (sc == NULL) { 3349114018Sharti printf("%s: invalid unit number: %d\n", __func__, unit); 3350114018Sharti return (0); 3351114018Sharti } 335268432Skjc 3353114018Sharti addr = addr & ~3; 3354114018Sharti if (addr < MID_RAMOFF || addr + len * 4 > MID_MAXOFF || len <= 0) { 3355114018Sharti printf("invalid addr/len number: %d, %d\n", addr, len); 3356114018Sharti return (0); 3357114018Sharti } 3358114018Sharti printf("dumping %d words starting at offset 0x%x\n", len, addr); 3359114018Sharti while (len--) { 3360114018Sharti reg = en_read(sc, addr); 3361114018Sharti printf("mem[0x%x] = 0x%x\n", addr, reg); 3362114018Sharti addr += 4; 3363114018Sharti } 3364114018Sharti return (0); 336525603Skjc} 336625603Skjc#endif 3367