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