1139749Simp/*-
2116735Sharti * Copyright (c) 2001-2003
3116735Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4116735Sharti * 	All rights reserved.
5116735Sharti *
6116735Sharti * Redistribution and use in source and binary forms, with or without
7116735Sharti * modification, are permitted provided that the following conditions
8116735Sharti * are met:
9116735Sharti * 1. Redistributions of source code must retain the above copyright
10116735Sharti *    notice, this list of conditions and the following disclaimer.
11116735Sharti * 2. Redistributions in binary form must reproduce the above copyright
12116735Sharti *    notice, this list of conditions and the following disclaimer in the
13116735Sharti *    documentation and/or other materials provided with the distribution.
14116735Sharti *
15116735Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116735Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116735Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116735Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116735Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116735Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116735Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116735Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116735Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116735Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116735Sharti * SUCH DAMAGE.
26116735Sharti *
27116735Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28116735Sharti *
29116735Sharti * Fore PCA200E driver for NATM
30116735Sharti */
31119418Sobrien
32116735Sharti#include <sys/cdefs.h>
33116735Sharti__FBSDID("$FreeBSD$");
34116735Sharti
35116735Sharti#include "opt_inet.h"
36116735Sharti#include "opt_natm.h"
37116735Sharti
38116735Sharti#include <sys/types.h>
39116735Sharti#include <sys/param.h>
40116735Sharti#include <sys/systm.h>
41116735Sharti#include <sys/malloc.h>
42116735Sharti#include <sys/kernel.h>
43116735Sharti#include <sys/bus.h>
44116735Sharti#include <sys/errno.h>
45116735Sharti#include <sys/conf.h>
46116735Sharti#include <sys/module.h>
47116735Sharti#include <sys/queue.h>
48116735Sharti#include <sys/syslog.h>
49116735Sharti#include <sys/endian.h>
50116735Sharti#include <sys/sysctl.h>
51116735Sharti#include <sys/condvar.h>
52118208Sharti#include <vm/uma.h>
53116735Sharti
54116735Sharti#include <sys/sockio.h>
55116735Sharti#include <sys/mbuf.h>
56116735Sharti#include <sys/socket.h>
57116735Sharti
58116735Sharti#include <net/if.h>
59116735Sharti#include <net/if_media.h>
60147256Sbrooks#include <net/if_types.h>
61116735Sharti#include <net/if_atm.h>
62116735Sharti#include <net/route.h>
63147525Sharti#ifdef ENABLE_BPF
64147525Sharti#include <net/bpf.h>
65147525Sharti#endif
66116735Sharti#ifdef INET
67116735Sharti#include <netinet/in.h>
68116735Sharti#include <netinet/if_atm.h>
69116735Sharti#endif
70116735Sharti
71116735Sharti#include <machine/bus.h>
72116735Sharti#include <machine/resource.h>
73116735Sharti#include <sys/bus.h>
74116735Sharti#include <sys/rman.h>
75119277Simp#include <dev/pci/pcireg.h>
76119277Simp#include <dev/pci/pcivar.h>
77116735Sharti
78116735Sharti#include <dev/utopia/utopia.h>
79116735Sharti
80116735Sharti#include <dev/fatm/if_fatmreg.h>
81116735Sharti#include <dev/fatm/if_fatmvar.h>
82116735Sharti
83116735Sharti#include <dev/fatm/firmware.h>
84116735Sharti
85116735Shartidevclass_t fatm_devclass;
86116735Sharti
87116735Shartistatic const struct {
88116735Sharti	uint16_t	vid;
89116735Sharti	uint16_t	did;
90116735Sharti	const char	*name;
91116735Sharti} fatm_devs[] = {
92116735Sharti	{ 0x1127, 0x300,
93116735Sharti	  "FORE PCA200E" },
94116735Sharti	{ 0, 0, NULL }
95116735Sharti};
96116735Sharti
97116735Shartistatic const struct rate {
98116735Sharti	uint32_t	ratio;
99116735Sharti	uint32_t	cell_rate;
100116735Sharti} rate_table[] = {
101116735Sharti#include <dev/fatm/if_fatm_rate.h>
102116735Sharti};
103116735Sharti#define RATE_TABLE_SIZE (sizeof(rate_table) / sizeof(rate_table[0]))
104116735Sharti
105116735ShartiSYSCTL_DECL(_hw_atm);
106116735Sharti
107116735ShartiMODULE_DEPEND(fatm, utopia, 1, 1, 1);
108116735Sharti
109116735Shartistatic int	fatm_utopia_readregs(struct ifatm *, u_int, uint8_t *, u_int *);
110116735Shartistatic int	fatm_utopia_writereg(struct ifatm *, u_int, u_int, u_int);
111116735Sharti
112116735Shartistatic const struct utopia_methods fatm_utopia_methods = {
113116735Sharti	fatm_utopia_readregs,
114116735Sharti	fatm_utopia_writereg
115116735Sharti};
116116735Sharti
117116735Sharti#define VC_OK(SC, VPI, VCI)						\
118147256Sbrooks	(((VPI) & ~((1 << IFP2IFATM((SC)->ifp)->mib.vpi_bits) - 1)) == 0 &&	\
119147256Sbrooks	 (VCI) != 0 && ((VCI) & ~((1 << IFP2IFATM((SC)->ifp)->mib.vci_bits) - 1)) == 0)
120116735Sharti
121118596Shartistatic int fatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc);
122118596Sharti
123116735Sharti/*
124116735Sharti * Probing is easy: step trough the list of known vendor and device
125116735Sharti * ids and compare. If one is found - it's our.
126116735Sharti */
127116735Shartistatic int
128116735Shartifatm_probe(device_t dev)
129116735Sharti{
130116735Sharti	int i;
131116735Sharti
132116735Sharti	for (i = 0; fatm_devs[i].name; i++)
133116735Sharti		if (pci_get_vendor(dev) == fatm_devs[i].vid &&
134116735Sharti		    pci_get_device(dev) == fatm_devs[i].did) {
135116735Sharti			device_set_desc(dev, fatm_devs[i].name);
136143161Simp			return (BUS_PROBE_DEFAULT);
137116735Sharti		}
138116735Sharti	return (ENXIO);
139116735Sharti}
140116735Sharti
141116735Sharti/*
142116735Sharti * Function called at completion of a SUNI writeregs/readregs command.
143116735Sharti * This is called from the interrupt handler while holding the softc lock.
144116735Sharti * We use the queue entry as the randevouze point.
145116735Sharti */
146116735Shartistatic void
147116735Shartifatm_utopia_writeregs_complete(struct fatm_softc *sc, struct cmdqueue *q)
148116735Sharti{
149116735Sharti
150116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
151116735Sharti	if(H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
152116735Sharti		sc->istats.suni_reg_errors++;
153116735Sharti		q->error = EIO;
154116735Sharti	}
155116735Sharti	wakeup(q);
156116735Sharti}
157116735Sharti
158116735Sharti/*
159116735Sharti * Write a SUNI register. The bits that are 1 in mask are written from val
160116735Sharti * into register reg. We wait for the command to complete by sleeping on
161116735Sharti * the register memory.
162116735Sharti *
163116735Sharti * We assume, that we already hold the softc mutex.
164116735Sharti */
165116735Shartistatic int
166116735Shartifatm_utopia_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val)
167116735Sharti{
168116735Sharti	int error;
169116735Sharti	struct cmdqueue *q;
170116735Sharti	struct fatm_softc *sc;
171116735Sharti
172147256Sbrooks	sc = ifatm->ifp->if_softc;
173116735Sharti	FATM_CHECKLOCK(sc);
174148887Srwatson	if (!(ifatm->ifp->if_drv_flags & IFF_DRV_RUNNING))
175116735Sharti		return (EIO);
176116735Sharti
177116735Sharti	/* get queue element and fill it */
178116735Sharti	q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
179116735Sharti
180116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
181116735Sharti	if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
182116735Sharti		sc->istats.cmd_queue_full++;
183116735Sharti		return (EIO);
184116735Sharti	}
185116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
186116735Sharti
187116735Sharti	q->error = 0;
188116735Sharti	q->cb = fatm_utopia_writeregs_complete;
189116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
190116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
191116735Sharti
192116735Sharti	WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, 0);
193116735Sharti	BARRIER_W(sc);
194116735Sharti	WRITE4(sc, q->q.card + FATMOC_OP,
195116735Sharti	    FATM_MAKE_SETOC3(reg, val, mask) | FATM_OP_INTERRUPT_SEL);
196116735Sharti	BARRIER_W(sc);
197116735Sharti
198116735Sharti	/*
199116735Sharti	 * Wait for the command to complete
200116735Sharti	 */
201116735Sharti	error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_setreg", hz);
202116735Sharti
203116735Sharti	switch(error) {
204116735Sharti
205116735Sharti	  case EWOULDBLOCK:
206116735Sharti		error = EIO;
207116735Sharti		break;
208116735Sharti
209116735Sharti	  case ERESTART:
210116735Sharti		error = EINTR;
211116735Sharti		break;
212116735Sharti
213116735Sharti	  case 0:
214116735Sharti		error = q->error;
215116735Sharti		break;
216116735Sharti	}
217116735Sharti
218116735Sharti	return (error);
219116735Sharti}
220116735Sharti
221116735Sharti/*
222116735Sharti * Function called at completion of a SUNI readregs command.
223116735Sharti * This is called from the interrupt handler while holding the softc lock.
224116735Sharti * We use reg_mem as the randevouze point.
225116735Sharti */
226116735Shartistatic void
227116735Shartifatm_utopia_readregs_complete(struct fatm_softc *sc, struct cmdqueue *q)
228116735Sharti{
229116735Sharti
230116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
231116735Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
232116735Sharti		sc->istats.suni_reg_errors++;
233116735Sharti		q->error = EIO;
234116735Sharti	}
235116735Sharti	wakeup(&sc->reg_mem);
236116735Sharti}
237116735Sharti
238116735Sharti/*
239116735Sharti * Read SUNI registers
240116735Sharti *
241116735Sharti * We use a preallocated buffer to read the registers. Therefor we need
242116735Sharti * to protect against multiple threads trying to read registers. We do this
243116735Sharti * with a condition variable and a flag. We wait for the command to complete by sleeping on
244116735Sharti * the register memory.
245116735Sharti *
246116735Sharti * We assume, that we already hold the softc mutex.
247116735Sharti */
248116735Shartistatic int
249116735Shartifatm_utopia_readregs_internal(struct fatm_softc *sc)
250116735Sharti{
251116735Sharti	int error, i;
252116735Sharti	uint32_t *ptr;
253116735Sharti	struct cmdqueue *q;
254116735Sharti
255116735Sharti	/* get the buffer */
256116735Sharti	for (;;) {
257148887Srwatson		if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
258116735Sharti			return (EIO);
259116735Sharti		if (!(sc->flags & FATM_REGS_INUSE))
260116735Sharti			break;
261116735Sharti		cv_wait(&sc->cv_regs, &sc->mtx);
262116735Sharti	}
263116735Sharti	sc->flags |= FATM_REGS_INUSE;
264116735Sharti
265116735Sharti	q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
266116735Sharti
267116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
268116735Sharti	if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
269116735Sharti		sc->istats.cmd_queue_full++;
270116735Sharti		return (EIO);
271116735Sharti	}
272116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
273116735Sharti
274116735Sharti	q->error = 0;
275116735Sharti	q->cb = fatm_utopia_readregs_complete;
276116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
277116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
278116735Sharti
279116735Sharti	bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map, BUS_DMASYNC_PREREAD);
280116735Sharti
281116735Sharti	WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, sc->reg_mem.paddr);
282116735Sharti	BARRIER_W(sc);
283116735Sharti	WRITE4(sc, q->q.card + FATMOC_OP,
284116735Sharti	    FATM_OP_OC3_GET_REG | FATM_OP_INTERRUPT_SEL);
285116735Sharti	BARRIER_W(sc);
286116735Sharti
287116735Sharti	/*
288116735Sharti	 * Wait for the command to complete
289116735Sharti	 */
290116735Sharti	error = msleep(&sc->reg_mem, &sc->mtx, PZERO | PCATCH,
291116735Sharti	    "fatm_getreg", hz);
292116735Sharti
293116735Sharti	switch(error) {
294116735Sharti
295116735Sharti	  case EWOULDBLOCK:
296116735Sharti		error = EIO;
297116735Sharti		break;
298116735Sharti
299116735Sharti	  case ERESTART:
300116735Sharti		error = EINTR;
301116735Sharti		break;
302116735Sharti
303116735Sharti	  case 0:
304116735Sharti		bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map,
305116735Sharti		    BUS_DMASYNC_POSTREAD);
306116735Sharti		error = q->error;
307116735Sharti		break;
308116735Sharti	}
309116735Sharti
310116735Sharti	if (error != 0) {
311116735Sharti		/* declare buffer to be free */
312116735Sharti		sc->flags &= ~FATM_REGS_INUSE;
313116735Sharti		cv_signal(&sc->cv_regs);
314116735Sharti		return (error);
315116735Sharti	}
316116735Sharti
317116735Sharti	/* swap if needed */
318116735Sharti	ptr = (uint32_t *)sc->reg_mem.mem;
319116735Sharti	for (i = 0; i < FATM_NREGS; i++)
320116735Sharti		ptr[i] = le32toh(ptr[i]) & 0xff;
321116735Sharti
322116735Sharti	return (0);
323116735Sharti}
324116735Sharti
325116735Sharti/*
326116735Sharti * Read SUNI registers for the SUNI module.
327116735Sharti *
328116735Sharti * We assume, that we already hold the mutex.
329116735Sharti */
330116735Shartistatic int
331116735Shartifatm_utopia_readregs(struct ifatm *ifatm, u_int reg, uint8_t *valp, u_int *np)
332116735Sharti{
333116735Sharti	int err;
334116735Sharti	int i;
335116735Sharti	struct fatm_softc *sc;
336116735Sharti
337116735Sharti	if (reg >= FATM_NREGS)
338116735Sharti		return (EINVAL);
339116735Sharti	if (reg + *np > FATM_NREGS)
340116735Sharti		*np = FATM_NREGS - reg;
341147256Sbrooks	sc = ifatm->ifp->if_softc;
342116735Sharti	FATM_CHECKLOCK(sc);
343116735Sharti
344116735Sharti	err = fatm_utopia_readregs_internal(sc);
345116735Sharti	if (err != 0)
346116735Sharti		return (err);
347116735Sharti
348116735Sharti	for (i = 0; i < *np; i++)
349116735Sharti		valp[i] = ((uint32_t *)sc->reg_mem.mem)[reg + i];
350116735Sharti
351116735Sharti	/* declare buffer to be free */
352116735Sharti	sc->flags &= ~FATM_REGS_INUSE;
353116735Sharti	cv_signal(&sc->cv_regs);
354116735Sharti
355116735Sharti	return (0);
356116735Sharti}
357116735Sharti
358116735Sharti/*
359116735Sharti * Check whether the hard is beating. We remember the last heart beat and
360116735Sharti * compare it to the current one. If it appears stuck for 10 times, we have
361116735Sharti * a problem.
362116735Sharti *
363116735Sharti * Assume we hold the lock.
364116735Sharti */
365116735Shartistatic void
366116735Shartifatm_check_heartbeat(struct fatm_softc *sc)
367116735Sharti{
368116735Sharti	uint32_t h;
369116735Sharti
370116735Sharti	FATM_CHECKLOCK(sc);
371116735Sharti
372116735Sharti	h = READ4(sc, FATMO_HEARTBEAT);
373116735Sharti	DBG(sc, BEAT, ("heartbeat %08x", h));
374116735Sharti
375116735Sharti	if (sc->stop_cnt == 10)
376116735Sharti		return;
377116735Sharti
378116735Sharti	if (h == sc->heartbeat) {
379116735Sharti		if (++sc->stop_cnt == 10) {
380116735Sharti			log(LOG_ERR, "i960 stopped???\n");
381116735Sharti			WRITE4(sc, FATMO_HIMR, 1);
382116735Sharti		}
383116735Sharti		return;
384116735Sharti	}
385116735Sharti
386116735Sharti	sc->stop_cnt = 0;
387116735Sharti	sc->heartbeat = h;
388116735Sharti}
389116735Sharti
390116735Sharti/*
391116735Sharti * Ensure that the heart is still beating.
392116735Sharti */
393116735Shartistatic void
394199559Sjhbfatm_watchdog(void *arg)
395116735Sharti{
396199559Sjhb	struct fatm_softc *sc;
397116735Sharti
398199559Sjhb	sc = arg;
399199559Sjhb	FATM_CHECKLOCK(sc);
400199559Sjhb	fatm_check_heartbeat(sc);
401199559Sjhb	callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc);
402116735Sharti}
403116735Sharti
404116735Sharti/*
405116735Sharti * Hard reset the i960 on the board. This is done by initializing registers,
406116735Sharti * clearing interrupts and waiting for the selftest to finish. Not sure,
407116735Sharti * whether all these barriers are actually needed.
408116735Sharti *
409116735Sharti * Assumes that we hold the lock.
410116735Sharti */
411116735Shartistatic int
412116735Shartifatm_reset(struct fatm_softc *sc)
413116735Sharti{
414116735Sharti	int w;
415116735Sharti	uint32_t val;
416116735Sharti
417116735Sharti	FATM_CHECKLOCK(sc);
418116735Sharti
419116735Sharti	WRITE4(sc, FATMO_APP_BASE, FATMO_COMMON_ORIGIN);
420116735Sharti	BARRIER_W(sc);
421116735Sharti
422116735Sharti	WRITE4(sc, FATMO_UART_TO_960, XMIT_READY);
423116735Sharti	BARRIER_W(sc);
424116735Sharti
425116735Sharti	WRITE4(sc, FATMO_UART_TO_HOST, XMIT_READY);
426116735Sharti	BARRIER_W(sc);
427116735Sharti
428116735Sharti	WRITE4(sc, FATMO_BOOT_STATUS, COLD_START);
429116735Sharti	BARRIER_W(sc);
430116735Sharti
431116735Sharti	WRITE1(sc, FATMO_HCR, FATM_HCR_RESET);
432116735Sharti	BARRIER_W(sc);
433116735Sharti
434116735Sharti	DELAY(1000);
435116735Sharti
436116735Sharti	WRITE1(sc, FATMO_HCR, 0);
437116735Sharti	BARRIER_RW(sc);
438116735Sharti
439116735Sharti	DELAY(1000);
440116735Sharti
441116735Sharti	for (w = 100; w; w--) {
442116735Sharti		BARRIER_R(sc);
443116735Sharti		val = READ4(sc, FATMO_BOOT_STATUS);
444116735Sharti		switch (val) {
445116735Sharti		  case SELF_TEST_OK:
446116735Sharti			return (0);
447116735Sharti		  case SELF_TEST_FAIL:
448116735Sharti			return (EIO);
449116735Sharti		}
450116735Sharti		DELAY(1000);
451116735Sharti	}
452116735Sharti	return (EIO);
453116735Sharti}
454116735Sharti
455116735Sharti/*
456116735Sharti * Stop the card. Must be called WITH the lock held
457118596Sharti * Reset, free transmit and receive buffers. Wakeup everybody who may sleep.
458116735Sharti */
459116735Shartistatic void
460116735Shartifatm_stop(struct fatm_softc *sc)
461116735Sharti{
462116735Sharti	int i;
463116735Sharti	struct cmdqueue *q;
464116735Sharti	struct rbuf *rb;
465116735Sharti	struct txqueue *tx;
466116735Sharti	uint32_t stat;
467116735Sharti
468116735Sharti	FATM_CHECKLOCK(sc);
469116735Sharti
470116735Sharti	/* Stop the board */
471116735Sharti	utopia_stop(&sc->utopia);
472116735Sharti	(void)fatm_reset(sc);
473116735Sharti
474116735Sharti	/* stop watchdog */
475199559Sjhb	callout_stop(&sc->watchdog_timer);
476116735Sharti
477148887Srwatson	if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) {
478148887Srwatson		sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
479147256Sbrooks		ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
480118168Sharti		    sc->utopia.carrier == UTP_CARR_OK);
481116735Sharti
482116735Sharti		/*
483116735Sharti		 * Collect transmit mbufs, partial receive mbufs and
484116735Sharti		 * supplied mbufs
485116735Sharti		 */
486116735Sharti		for (i = 0; i < FATM_TX_QLEN; i++) {
487116735Sharti			tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
488116735Sharti			if (tx->m) {
489116735Sharti				bus_dmamap_unload(sc->tx_tag, tx->map);
490116735Sharti				m_freem(tx->m);
491116735Sharti				tx->m = NULL;
492116735Sharti			}
493116735Sharti		}
494116735Sharti
495116735Sharti		/* Collect supplied mbufs */
496116735Sharti		while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) {
497116735Sharti			LIST_REMOVE(rb, link);
498116735Sharti			bus_dmamap_unload(sc->rbuf_tag, rb->map);
499116735Sharti			m_free(rb->m);
500116735Sharti			rb->m = NULL;
501116735Sharti			LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
502116735Sharti		}
503116735Sharti
504116735Sharti		/* Unwait any waiters */
505116735Sharti		wakeup(&sc->sadi_mem);
506116735Sharti
507116735Sharti		/* wakeup all threads waiting for STAT or REG buffers */
508116735Sharti		cv_broadcast(&sc->cv_stat);
509116735Sharti		cv_broadcast(&sc->cv_regs);
510116735Sharti
511116735Sharti		sc->flags &= ~(FATM_STAT_INUSE | FATM_REGS_INUSE);
512116735Sharti
513116735Sharti		/* wakeup all threads waiting on commands */
514116735Sharti		for (i = 0; i < FATM_CMD_QLEN; i++) {
515116735Sharti			q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, i);
516116735Sharti
517116735Sharti			H_SYNCSTAT_POSTREAD(sc, q->q.statp);
518116735Sharti			if ((stat = H_GETSTAT(q->q.statp)) != FATM_STAT_FREE) {
519116735Sharti				H_SETSTAT(q->q.statp, stat | FATM_STAT_ERROR);
520116735Sharti				H_SYNCSTAT_PREWRITE(sc, q->q.statp);
521116735Sharti				wakeup(q);
522116735Sharti			}
523116735Sharti		}
524116735Sharti		utopia_reset_media(&sc->utopia);
525116735Sharti	}
526116735Sharti	sc->small_cnt = sc->large_cnt = 0;
527116735Sharti
528116735Sharti	/* Reset vcc info */
529118208Sharti	if (sc->vccs != NULL) {
530118596Sharti		sc->open_vccs = 0;
531118596Sharti		for (i = 0; i < FORE_MAX_VCC + 1; i++) {
532118208Sharti			if (sc->vccs[i] != NULL) {
533118596Sharti				if ((sc->vccs[i]->vflags & (FATM_VCC_OPEN |
534118596Sharti				    FATM_VCC_TRY_OPEN)) == 0) {
535118596Sharti					uma_zfree(sc->vcc_zone, sc->vccs[i]);
536118596Sharti					sc->vccs[i] = NULL;
537118596Sharti				} else {
538118596Sharti					sc->vccs[i]->vflags = 0;
539118596Sharti					sc->open_vccs++;
540118596Sharti				}
541118208Sharti			}
542118596Sharti		}
543118208Sharti	}
544116735Sharti
545116735Sharti}
546116735Sharti
547116735Sharti/*
548116735Sharti * Load the firmware into the board and save the entry point.
549116735Sharti */
550116735Shartistatic uint32_t
551116735Shartifirmware_load(struct fatm_softc *sc)
552116735Sharti{
553116735Sharti	struct firmware *fw = (struct firmware *)firmware;
554116735Sharti
555116735Sharti	DBG(sc, INIT, ("loading - entry=%x", fw->entry));
556116735Sharti	bus_space_write_region_4(sc->memt, sc->memh, fw->offset, firmware,
557116735Sharti	    sizeof(firmware) / sizeof(firmware[0]));
558116735Sharti	BARRIER_RW(sc);
559116735Sharti
560116735Sharti	return (fw->entry);
561116735Sharti}
562116735Sharti
563116735Sharti/*
564116735Sharti * Read a character from the virtual UART. The availability of a character
565116735Sharti * is signaled by a non-null value of the 32 bit register. The eating of
566116735Sharti * the character by us is signalled to the card by setting that register
567116735Sharti * to zero.
568116735Sharti */
569116735Shartistatic int
570116735Shartirx_getc(struct fatm_softc *sc)
571116735Sharti{
572116735Sharti	int w = 50;
573116735Sharti	int c;
574116735Sharti
575116735Sharti	while (w--) {
576116735Sharti		c = READ4(sc, FATMO_UART_TO_HOST);
577116735Sharti		BARRIER_RW(sc);
578116735Sharti		if (c != 0) {
579116735Sharti			WRITE4(sc, FATMO_UART_TO_HOST, 0);
580116735Sharti			DBGC(sc, UART, ("%c", c & 0xff));
581116735Sharti			return (c & 0xff);
582116735Sharti		}
583116735Sharti		DELAY(1000);
584116735Sharti	}
585116735Sharti	return (-1);
586116735Sharti}
587116735Sharti
588116735Sharti/*
589116735Sharti * Eat up characters from the board and stuff them in the bit-bucket.
590116735Sharti */
591116735Shartistatic void
592116735Shartirx_flush(struct fatm_softc *sc)
593116735Sharti{
594116735Sharti	int w = 10000;
595116735Sharti
596116735Sharti	while (w-- && rx_getc(sc) >= 0)
597116735Sharti		;
598116735Sharti}
599116735Sharti
600116735Sharti/*
601116735Sharti * Write a character to the card. The UART is available if the register
602116735Sharti * is zero.
603116735Sharti */
604116735Shartistatic int
605116735Shartitx_putc(struct fatm_softc *sc, u_char c)
606116735Sharti{
607116735Sharti	int w = 10;
608116735Sharti	int c1;
609116735Sharti
610116735Sharti	while (w--) {
611116735Sharti		c1 = READ4(sc, FATMO_UART_TO_960);
612116735Sharti		BARRIER_RW(sc);
613116735Sharti		if (c1 == 0) {
614116735Sharti			WRITE4(sc, FATMO_UART_TO_960, c | CHAR_AVAIL);
615116735Sharti			DBGC(sc, UART, ("%c", c & 0xff));
616116735Sharti			return (0);
617116735Sharti		}
618116735Sharti		DELAY(1000);
619116735Sharti	}
620116735Sharti	return (-1);
621116735Sharti}
622116735Sharti
623116735Sharti/*
624116735Sharti * Start the firmware. This is doing by issuing a 'go' command with
625116735Sharti * the hex entry address of the firmware. Then we wait for the self-test to
626116735Sharti * succeed.
627116735Sharti */
628116735Shartistatic int
629116735Shartifatm_start_firmware(struct fatm_softc *sc, uint32_t start)
630116735Sharti{
631116735Sharti	static char hex[] = "0123456789abcdef";
632116735Sharti	u_int w, val;
633116735Sharti
634116735Sharti	DBG(sc, INIT, ("starting"));
635116735Sharti	rx_flush(sc);
636116735Sharti	tx_putc(sc, '\r');
637116735Sharti	DELAY(1000);
638116735Sharti
639116735Sharti	rx_flush(sc);
640116735Sharti
641116735Sharti	tx_putc(sc, 'g');
642116735Sharti	(void)rx_getc(sc);
643116735Sharti	tx_putc(sc, 'o');
644116735Sharti	(void)rx_getc(sc);
645116735Sharti	tx_putc(sc, ' ');
646116735Sharti	(void)rx_getc(sc);
647116735Sharti
648116735Sharti	tx_putc(sc, hex[(start >> 12) & 0xf]);
649116735Sharti	(void)rx_getc(sc);
650116735Sharti	tx_putc(sc, hex[(start >>  8) & 0xf]);
651116735Sharti	(void)rx_getc(sc);
652116735Sharti	tx_putc(sc, hex[(start >>  4) & 0xf]);
653116735Sharti	(void)rx_getc(sc);
654116735Sharti	tx_putc(sc, hex[(start >>  0) & 0xf]);
655116735Sharti	(void)rx_getc(sc);
656116735Sharti
657116735Sharti	tx_putc(sc, '\r');
658116735Sharti	rx_flush(sc);
659116735Sharti
660116735Sharti	for (w = 100; w; w--) {
661116735Sharti		BARRIER_R(sc);
662116735Sharti		val = READ4(sc, FATMO_BOOT_STATUS);
663116735Sharti		switch (val) {
664116735Sharti		  case CP_RUNNING:
665116735Sharti			return (0);
666116735Sharti		  case SELF_TEST_FAIL:
667116735Sharti			return (EIO);
668116735Sharti		}
669116735Sharti		DELAY(1000);
670116735Sharti	}
671116735Sharti	return (EIO);
672116735Sharti}
673116735Sharti
674116735Sharti/*
675116735Sharti * Initialize one card and host queue.
676116735Sharti */
677116735Shartistatic void
678116735Shartiinit_card_queue(struct fatm_softc *sc, struct fqueue *queue, int qlen,
679116735Sharti    size_t qel_size, size_t desc_size, cardoff_t off,
680116735Sharti    u_char **statpp, uint32_t *cardstat, u_char *descp, uint32_t carddesc)
681116735Sharti{
682116735Sharti	struct fqelem *el = queue->chunk;
683116735Sharti
684116735Sharti	while (qlen--) {
685116735Sharti		el->card = off;
686116735Sharti		off += 8;	/* size of card entry */
687116735Sharti
688116735Sharti		el->statp = (uint32_t *)(*statpp);
689116735Sharti		(*statpp) += sizeof(uint32_t);
690116735Sharti		H_SETSTAT(el->statp, FATM_STAT_FREE);
691116735Sharti		H_SYNCSTAT_PREWRITE(sc, el->statp);
692116735Sharti
693116735Sharti		WRITE4(sc, el->card + FATMOS_STATP, (*cardstat));
694116735Sharti		(*cardstat) += sizeof(uint32_t);
695116735Sharti
696116735Sharti		el->ioblk = descp;
697116735Sharti		descp += desc_size;
698116735Sharti		el->card_ioblk = carddesc;
699116735Sharti		carddesc += desc_size;
700116735Sharti
701116735Sharti		el = (struct fqelem *)((u_char *)el + qel_size);
702116735Sharti	}
703116735Sharti	queue->tail = queue->head = 0;
704116735Sharti}
705116735Sharti
706116735Sharti/*
707116735Sharti * Issue the initialize operation to the card, wait for completion and
708116735Sharti * initialize the on-board and host queue structures with offsets and
709116735Sharti * addresses.
710116735Sharti */
711116735Shartistatic int
712116735Shartifatm_init_cmd(struct fatm_softc *sc)
713116735Sharti{
714116735Sharti	int w, c;
715116735Sharti	u_char *statp;
716116735Sharti	uint32_t card_stat;
717116735Sharti	u_int cnt;
718116735Sharti	struct fqelem *el;
719116735Sharti	cardoff_t off;
720116735Sharti
721116735Sharti	DBG(sc, INIT, ("command"));
722116735Sharti	WRITE4(sc, FATMO_ISTAT, 0);
723116735Sharti	WRITE4(sc, FATMO_IMASK, 1);
724116735Sharti	WRITE4(sc, FATMO_HLOGGER, 0);
725116735Sharti
726116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_RECEIVE_TRESHOLD, 0);
727116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_NUM_CONNECT, FORE_MAX_VCC);
728116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_CQUEUE_LEN, FATM_CMD_QLEN);
729116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_TQUEUE_LEN, FATM_TX_QLEN);
730116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_RQUEUE_LEN, FATM_RX_QLEN);
731116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_RPD_EXTENSION, RPD_EXTENSIONS);
732116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_TPD_EXTENSION, TPD_EXTENSIONS);
733116735Sharti
734116735Sharti	/*
735116735Sharti	 * initialize buffer descriptors
736116735Sharti	 */
737116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_QUEUE_LENGTH,
738116735Sharti	    SMALL_SUPPLY_QLEN);
739116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_BUFFER_SIZE,
740116735Sharti	    SMALL_BUFFER_LEN);
741116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_POOL_SIZE,
742116735Sharti	    SMALL_POOL_SIZE);
743116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_SUPPLY_BLKSIZE,
744116735Sharti	    SMALL_SUPPLY_BLKSIZE);
745116735Sharti
746116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_QUEUE_LENGTH,
747116735Sharti	    LARGE_SUPPLY_QLEN);
748116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_BUFFER_SIZE,
749116735Sharti	    LARGE_BUFFER_LEN);
750116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_POOL_SIZE,
751116735Sharti	    LARGE_POOL_SIZE);
752116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_SUPPLY_BLKSIZE,
753116735Sharti	    LARGE_SUPPLY_BLKSIZE);
754116735Sharti
755116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_QUEUE_LENGTH, 0);
756116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_BUFFER_SIZE, 0);
757116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_POOL_SIZE, 0);
758116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_SUPPLY_BLKSIZE, 0);
759116735Sharti
760116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_QUEUE_LENGTH, 0);
761116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_BUFFER_SIZE, 0);
762116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_POOL_SIZE, 0);
763116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_SUPPLY_BLKSIZE, 0);
764116735Sharti
765116735Sharti	/*
766116735Sharti	 * Start the command
767116735Sharti	 */
768116735Sharti	BARRIER_W(sc);
769116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_STATUS, FATM_STAT_PENDING);
770116735Sharti	BARRIER_W(sc);
771116735Sharti	WRITE4(sc, FATMO_INIT + FATMOI_OP, FATM_OP_INITIALIZE);
772116735Sharti	BARRIER_W(sc);
773116735Sharti
774116735Sharti	/*
775116735Sharti	 * Busy wait for completion
776116735Sharti	 */
777116735Sharti	w = 100;
778116735Sharti	while (w--) {
779116735Sharti		c = READ4(sc, FATMO_INIT + FATMOI_STATUS);
780116735Sharti		BARRIER_R(sc);
781116735Sharti		if (c & FATM_STAT_COMPLETE)
782116735Sharti			break;
783116735Sharti		DELAY(1000);
784116735Sharti	}
785116735Sharti
786116735Sharti	if (c & FATM_STAT_ERROR)
787116735Sharti		return (EIO);
788116735Sharti
789116735Sharti	/*
790116735Sharti	 * Initialize the queues
791116735Sharti	 */
792116735Sharti	statp = sc->stat_mem.mem;
793116735Sharti	card_stat = sc->stat_mem.paddr;
794116735Sharti
795116735Sharti	/*
796116735Sharti	 * Command queue. This is special in that it's on the card.
797116735Sharti	 */
798116735Sharti	el = sc->cmdqueue.chunk;
799116735Sharti	off = READ4(sc, FATMO_COMMAND_QUEUE);
800116735Sharti	DBG(sc, INIT, ("cmd queue=%x", off));
801116735Sharti	for (cnt = 0; cnt < FATM_CMD_QLEN; cnt++) {
802116735Sharti		el = &((struct cmdqueue *)sc->cmdqueue.chunk + cnt)->q;
803116735Sharti
804116735Sharti		el->card = off;
805116735Sharti		off += 32;		/* size of card structure */
806116735Sharti
807116735Sharti		el->statp = (uint32_t *)statp;
808116735Sharti		statp += sizeof(uint32_t);
809116735Sharti		H_SETSTAT(el->statp, FATM_STAT_FREE);
810116735Sharti		H_SYNCSTAT_PREWRITE(sc, el->statp);
811116735Sharti
812116735Sharti		WRITE4(sc, el->card + FATMOC_STATP, card_stat);
813116735Sharti		card_stat += sizeof(uint32_t);
814116735Sharti	}
815116735Sharti	sc->cmdqueue.tail = sc->cmdqueue.head = 0;
816116735Sharti
817116735Sharti	/*
818116735Sharti	 * Now the other queues. These are in memory
819116735Sharti	 */
820116735Sharti	init_card_queue(sc, &sc->txqueue, FATM_TX_QLEN,
821116735Sharti	    sizeof(struct txqueue), TPD_SIZE,
822116735Sharti	    READ4(sc, FATMO_TRANSMIT_QUEUE),
823116735Sharti	    &statp, &card_stat, sc->txq_mem.mem, sc->txq_mem.paddr);
824116735Sharti
825116735Sharti	init_card_queue(sc, &sc->rxqueue, FATM_RX_QLEN,
826116735Sharti	    sizeof(struct rxqueue), RPD_SIZE,
827116735Sharti	    READ4(sc, FATMO_RECEIVE_QUEUE),
828116735Sharti	    &statp, &card_stat, sc->rxq_mem.mem, sc->rxq_mem.paddr);
829116735Sharti
830116735Sharti	init_card_queue(sc, &sc->s1queue, SMALL_SUPPLY_QLEN,
831116735Sharti	    sizeof(struct supqueue), BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE),
832116735Sharti	    READ4(sc, FATMO_SMALL_B1_QUEUE),
833116735Sharti	    &statp, &card_stat, sc->s1q_mem.mem, sc->s1q_mem.paddr);
834116735Sharti
835116735Sharti	init_card_queue(sc, &sc->l1queue, LARGE_SUPPLY_QLEN,
836116735Sharti	    sizeof(struct supqueue), BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE),
837116735Sharti	    READ4(sc, FATMO_LARGE_B1_QUEUE),
838116735Sharti	    &statp, &card_stat, sc->l1q_mem.mem, sc->l1q_mem.paddr);
839116735Sharti
840116735Sharti	sc->txcnt = 0;
841116735Sharti
842116735Sharti	return (0);
843116735Sharti}
844116735Sharti
845116735Sharti/*
846116735Sharti * Read PROM. Called only from attach code. Here we spin because the interrupt
847116735Sharti * handler is not yet set up.
848116735Sharti */
849116735Shartistatic int
850116735Shartifatm_getprom(struct fatm_softc *sc)
851116735Sharti{
852116735Sharti	int i;
853116735Sharti	struct prom *prom;
854116735Sharti	struct cmdqueue *q;
855116735Sharti
856116735Sharti	DBG(sc, INIT, ("reading prom"));
857116735Sharti	q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
858116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
859116735Sharti
860116735Sharti	q->error = 0;
861201758Smbr	q->cb = NULL;
862116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
863116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
864116735Sharti
865116735Sharti	bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map,
866116735Sharti	    BUS_DMASYNC_PREREAD);
867116735Sharti
868116735Sharti	WRITE4(sc, q->q.card + FATMOC_GPROM_BUF, sc->prom_mem.paddr);
869116735Sharti	BARRIER_W(sc);
870116735Sharti	WRITE4(sc, q->q.card + FATMOC_OP, FATM_OP_GET_PROM_DATA);
871116735Sharti	BARRIER_W(sc);
872116735Sharti
873116735Sharti	for (i = 0; i < 1000; i++) {
874116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
875116735Sharti		if (H_GETSTAT(q->q.statp) &
876116735Sharti		    (FATM_STAT_COMPLETE | FATM_STAT_ERROR))
877116735Sharti			break;
878116735Sharti		DELAY(1000);
879116735Sharti	}
880116735Sharti	if (i == 1000) {
881147256Sbrooks		if_printf(sc->ifp, "getprom timeout\n");
882116735Sharti		return (EIO);
883116735Sharti	}
884116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
885116735Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
886147256Sbrooks		if_printf(sc->ifp, "getprom error\n");
887116735Sharti		return (EIO);
888116735Sharti	}
889116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_FREE);
890116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
891116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN);
892116735Sharti
893116735Sharti	bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map,
894116735Sharti	    BUS_DMASYNC_POSTREAD);
895116735Sharti
896116735Sharti
897116735Sharti#ifdef notdef
898116735Sharti	{
899116735Sharti		u_int i;
900116735Sharti
901116735Sharti		printf("PROM: ");
902116735Sharti		u_char *ptr = (u_char *)sc->prom_mem.mem;
903116735Sharti		for (i = 0; i < sizeof(struct prom); i++)
904116735Sharti			printf("%02x ", *ptr++);
905116735Sharti		printf("\n");
906116735Sharti	}
907116735Sharti#endif
908116735Sharti
909116735Sharti	prom = (struct prom *)sc->prom_mem.mem;
910116735Sharti
911147256Sbrooks	bcopy(prom->mac + 2, IFP2IFATM(sc->ifp)->mib.esi, 6);
912147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial = le32toh(prom->serial);
913147256Sbrooks	IFP2IFATM(sc->ifp)->mib.hw_version = le32toh(prom->version);
914147256Sbrooks	IFP2IFATM(sc->ifp)->mib.sw_version = READ4(sc, FATMO_FIRMWARE_RELEASE);
915116735Sharti
916147256Sbrooks	if_printf(sc->ifp, "ESI=%02x:%02x:%02x:%02x:%02x:%02x "
917147256Sbrooks	    "serial=%u hw=0x%x sw=0x%x\n", IFP2IFATM(sc->ifp)->mib.esi[0],
918147256Sbrooks	    IFP2IFATM(sc->ifp)->mib.esi[1], IFP2IFATM(sc->ifp)->mib.esi[2], IFP2IFATM(sc->ifp)->mib.esi[3],
919147256Sbrooks	    IFP2IFATM(sc->ifp)->mib.esi[4], IFP2IFATM(sc->ifp)->mib.esi[5], IFP2IFATM(sc->ifp)->mib.serial,
920147256Sbrooks	    IFP2IFATM(sc->ifp)->mib.hw_version, IFP2IFATM(sc->ifp)->mib.sw_version);
921116735Sharti
922116735Sharti	return (0);
923116735Sharti}
924116735Sharti
925116735Sharti/*
926116735Sharti * This is the callback function for bus_dmamap_load. We assume, that we
927116735Sharti * have a 32-bit bus and so have always one segment.
928116735Sharti */
929116735Shartistatic void
930116735Shartidmaload_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
931116735Sharti{
932116735Sharti	bus_addr_t *ptr = (bus_addr_t *)arg;
933116735Sharti
934116735Sharti	if (error != 0) {
935116735Sharti		printf("%s: error=%d\n", __func__, error);
936116735Sharti		return;
937116735Sharti	}
938116735Sharti	KASSERT(nsegs == 1, ("too many DMA segments"));
939116735Sharti	KASSERT(segs[0].ds_addr <= 0xffffffff, ("DMA address too large %lx",
940116735Sharti	    (u_long)segs[0].ds_addr));
941116735Sharti
942116735Sharti	*ptr = segs[0].ds_addr;
943116735Sharti}
944116735Sharti
945116735Sharti/*
946116735Sharti * Allocate a chunk of DMA-able memory and map it.
947116735Sharti */
948116735Shartistatic int
949116735Shartialloc_dma_memory(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem)
950116735Sharti{
951116735Sharti	int error;
952116735Sharti
953116735Sharti	mem->mem = NULL;
954116735Sharti
955116735Sharti	if (bus_dma_tag_create(sc->parent_dmat, mem->align, 0,
956116735Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
957117126Sscottl	    NULL, NULL, mem->size, 1, BUS_SPACE_MAXSIZE_32BIT,
958117126Sscottl	    BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) {
959147256Sbrooks		if_printf(sc->ifp, "could not allocate %s DMA tag\n",
960116735Sharti		    nm);
961116735Sharti		return (ENOMEM);
962116735Sharti	}
963116735Sharti
964116735Sharti	error = bus_dmamem_alloc(mem->dmat, &mem->mem, 0, &mem->map);
965116735Sharti	if (error) {
966147256Sbrooks		if_printf(sc->ifp, "could not allocate %s DMA memory: "
967116735Sharti		    "%d\n", nm, error);
968116735Sharti		bus_dma_tag_destroy(mem->dmat);
969116735Sharti		mem->mem = NULL;
970116735Sharti		return (error);
971116735Sharti	}
972116735Sharti
973116735Sharti	error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size,
974116735Sharti	    dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT);
975116735Sharti	if (error) {
976147256Sbrooks		if_printf(sc->ifp, "could not load %s DMA memory: "
977116735Sharti		    "%d\n", nm, error);
978116735Sharti		bus_dmamem_free(mem->dmat, mem->mem, mem->map);
979116735Sharti		bus_dma_tag_destroy(mem->dmat);
980116735Sharti		mem->mem = NULL;
981116735Sharti		return (error);
982116735Sharti	}
983116735Sharti
984116735Sharti	DBG(sc, DMA, ("DMA %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
985116735Sharti	    (u_long)mem->paddr, mem->size, mem->align));
986116735Sharti
987116735Sharti	return (0);
988116735Sharti}
989116735Sharti
990116735Sharti#ifdef TEST_DMA_SYNC
991116735Shartistatic int
992116735Shartialloc_dma_memoryX(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem)
993116735Sharti{
994116735Sharti	int error;
995116735Sharti
996116735Sharti	mem->mem = NULL;
997116735Sharti
998116735Sharti	if (bus_dma_tag_create(NULL, mem->align, 0,
999116735Sharti	    BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR,
1000116735Sharti	    NULL, NULL, mem->size, 1, mem->size,
1001117126Sscottl	    BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) {
1002147256Sbrooks		if_printf(sc->ifp, "could not allocate %s DMA tag\n",
1003116735Sharti		    nm);
1004116735Sharti		return (ENOMEM);
1005116735Sharti	}
1006116735Sharti
1007116735Sharti	mem->mem = contigmalloc(mem->size, M_DEVBUF, M_WAITOK,
1008116735Sharti	    BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR_32BIT, mem->align, 0);
1009116735Sharti
1010116735Sharti	error = bus_dmamap_create(mem->dmat, 0, &mem->map);
1011116735Sharti	if (error) {
1012147256Sbrooks		if_printf(sc->ifp, "could not allocate %s DMA map: "
1013116735Sharti		    "%d\n", nm, error);
1014116735Sharti		contigfree(mem->mem, mem->size, M_DEVBUF);
1015116735Sharti		bus_dma_tag_destroy(mem->dmat);
1016116735Sharti		mem->mem = NULL;
1017116735Sharti		return (error);
1018116735Sharti	}
1019116735Sharti
1020116735Sharti	error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size,
1021116735Sharti	    dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT);
1022116735Sharti	if (error) {
1023147256Sbrooks		if_printf(sc->ifp, "could not load %s DMA memory: "
1024116735Sharti		    "%d\n", nm, error);
1025116735Sharti		bus_dmamap_destroy(mem->dmat, mem->map);
1026116735Sharti		contigfree(mem->mem, mem->size, M_DEVBUF);
1027116735Sharti		bus_dma_tag_destroy(mem->dmat);
1028116735Sharti		mem->mem = NULL;
1029116735Sharti		return (error);
1030116735Sharti	}
1031116735Sharti
1032116735Sharti	DBG(sc, DMA, ("DMAX %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
1033116735Sharti	    (u_long)mem->paddr, mem->size, mem->align));
1034116735Sharti
1035116735Sharti	printf("DMAX: %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
1036116735Sharti	    (u_long)mem->paddr, mem->size, mem->align);
1037116735Sharti
1038116735Sharti	return (0);
1039116735Sharti}
1040116735Sharti#endif /* TEST_DMA_SYNC */
1041116735Sharti
1042116735Sharti/*
1043116735Sharti * Destroy all resources of an dma-able memory chunk
1044116735Sharti */
1045116735Shartistatic void
1046116735Shartidestroy_dma_memory(struct fatm_mem *mem)
1047116735Sharti{
1048116735Sharti	if (mem->mem != NULL) {
1049116735Sharti		bus_dmamap_unload(mem->dmat, mem->map);
1050116735Sharti		bus_dmamem_free(mem->dmat, mem->mem, mem->map);
1051116735Sharti		bus_dma_tag_destroy(mem->dmat);
1052116735Sharti		mem->mem = NULL;
1053116735Sharti	}
1054116735Sharti}
1055116735Sharti#ifdef TEST_DMA_SYNC
1056116735Shartistatic void
1057116735Shartidestroy_dma_memoryX(struct fatm_mem *mem)
1058116735Sharti{
1059116735Sharti	if (mem->mem != NULL) {
1060116735Sharti		bus_dmamap_unload(mem->dmat, mem->map);
1061116735Sharti		bus_dmamap_destroy(mem->dmat, mem->map);
1062116735Sharti		contigfree(mem->mem, mem->size, M_DEVBUF);
1063116735Sharti		bus_dma_tag_destroy(mem->dmat);
1064116735Sharti		mem->mem = NULL;
1065116735Sharti	}
1066116735Sharti}
1067116735Sharti#endif /* TEST_DMA_SYNC */
1068116735Sharti
1069116735Sharti/*
1070116735Sharti * Try to supply buffers to the card if there are free entries in the queues
1071116735Sharti */
1072116735Shartistatic void
1073116735Shartifatm_supply_small_buffers(struct fatm_softc *sc)
1074116735Sharti{
1075116735Sharti	int nblocks, nbufs;
1076116735Sharti	struct supqueue *q;
1077116735Sharti	struct rbd *bd;
1078116735Sharti	int i, j, error, cnt;
1079116735Sharti	struct mbuf *m;
1080116735Sharti	struct rbuf *rb;
1081116735Sharti	bus_addr_t phys;
1082116735Sharti
1083116735Sharti	nbufs = max(4 * sc->open_vccs, 32);
1084116735Sharti	nbufs = min(nbufs, SMALL_POOL_SIZE);
1085116735Sharti	nbufs -= sc->small_cnt;
1086116735Sharti
1087116735Sharti	nblocks = (nbufs + SMALL_SUPPLY_BLKSIZE - 1) / SMALL_SUPPLY_BLKSIZE;
1088116735Sharti	for (cnt = 0; cnt < nblocks; cnt++) {
1089116735Sharti		q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.head);
1090116735Sharti
1091116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1092116735Sharti		if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE)
1093116735Sharti			break;
1094116735Sharti
1095116735Sharti		bd = (struct rbd *)q->q.ioblk;
1096116735Sharti
1097116735Sharti		for (i = 0; i < SMALL_SUPPLY_BLKSIZE; i++) {
1098116735Sharti			if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) {
1099147256Sbrooks				if_printf(sc->ifp, "out of rbufs\n");
1100116735Sharti				break;
1101116735Sharti			}
1102243857Sglebius			MGETHDR(m, M_NOWAIT, MT_DATA);
1103116735Sharti			if (m == NULL) {
1104116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1105116735Sharti				break;
1106116735Sharti			}
1107116735Sharti			MH_ALIGN(m, SMALL_BUFFER_LEN);
1108116735Sharti			error = bus_dmamap_load(sc->rbuf_tag, rb->map,
1109116735Sharti			    m->m_data, SMALL_BUFFER_LEN, dmaload_helper,
1110116735Sharti			    &phys, BUS_DMA_NOWAIT);
1111116735Sharti			if (error) {
1112147256Sbrooks				if_printf(sc->ifp,
1113116735Sharti				    "dmamap_load mbuf failed %d", error);
1114116735Sharti				m_freem(m);
1115116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1116116735Sharti				break;
1117116735Sharti			}
1118116735Sharti			bus_dmamap_sync(sc->rbuf_tag, rb->map,
1119116735Sharti			    BUS_DMASYNC_PREREAD);
1120116735Sharti
1121116735Sharti			LIST_REMOVE(rb, link);
1122116735Sharti			LIST_INSERT_HEAD(&sc->rbuf_used, rb, link);
1123116735Sharti
1124116735Sharti			rb->m = m;
1125116735Sharti			bd[i].handle = rb - sc->rbufs;
1126116735Sharti			H_SETDESC(bd[i].buffer, phys);
1127116735Sharti		}
1128116735Sharti
1129116735Sharti		if (i < SMALL_SUPPLY_BLKSIZE) {
1130116735Sharti			for (j = 0; j < i; j++) {
1131116735Sharti				rb = sc->rbufs + bd[j].handle;
1132116735Sharti				bus_dmamap_unload(sc->rbuf_tag, rb->map);
1133116735Sharti				m_free(rb->m);
1134116735Sharti				rb->m = NULL;
1135116735Sharti
1136116735Sharti				LIST_REMOVE(rb, link);
1137116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1138116735Sharti			}
1139116735Sharti			break;
1140116735Sharti		}
1141116735Sharti		H_SYNCQ_PREWRITE(&sc->s1q_mem, bd,
1142116735Sharti		    sizeof(struct rbd) * SMALL_SUPPLY_BLKSIZE);
1143116735Sharti
1144116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
1145116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1146116735Sharti
1147116735Sharti		WRITE4(sc, q->q.card, q->q.card_ioblk);
1148116735Sharti		BARRIER_W(sc);
1149116735Sharti
1150116735Sharti		sc->small_cnt += SMALL_SUPPLY_BLKSIZE;
1151116735Sharti
1152116735Sharti		NEXT_QUEUE_ENTRY(sc->s1queue.head, SMALL_SUPPLY_QLEN);
1153116735Sharti	}
1154116735Sharti}
1155116735Sharti
1156116735Sharti/*
1157116735Sharti * Try to supply buffers to the card if there are free entries in the queues
1158116735Sharti * We assume that all buffers are within the address space accessible by the
1159116735Sharti * card (32-bit), so we don't need bounce buffers.
1160116735Sharti */
1161116735Shartistatic void
1162116735Shartifatm_supply_large_buffers(struct fatm_softc *sc)
1163116735Sharti{
1164116735Sharti	int nbufs, nblocks, cnt;
1165116735Sharti	struct supqueue *q;
1166116735Sharti	struct rbd *bd;
1167116735Sharti	int i, j, error;
1168116735Sharti	struct mbuf *m;
1169116735Sharti	struct rbuf *rb;
1170116735Sharti	bus_addr_t phys;
1171116735Sharti
1172116735Sharti	nbufs = max(4 * sc->open_vccs, 32);
1173116735Sharti	nbufs = min(nbufs, LARGE_POOL_SIZE);
1174116735Sharti	nbufs -= sc->large_cnt;
1175116735Sharti
1176116735Sharti	nblocks = (nbufs + LARGE_SUPPLY_BLKSIZE - 1) / LARGE_SUPPLY_BLKSIZE;
1177116735Sharti
1178116735Sharti	for (cnt = 0; cnt < nblocks; cnt++) {
1179116735Sharti		q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.head);
1180116735Sharti
1181116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1182116735Sharti		if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE)
1183116735Sharti			break;
1184116735Sharti
1185116735Sharti		bd = (struct rbd *)q->q.ioblk;
1186116735Sharti
1187116735Sharti		for (i = 0; i < LARGE_SUPPLY_BLKSIZE; i++) {
1188116735Sharti			if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) {
1189147256Sbrooks				if_printf(sc->ifp, "out of rbufs\n");
1190116735Sharti				break;
1191116735Sharti			}
1192243857Sglebius			if ((m = m_getcl(M_NOWAIT, MT_DATA,
1193116735Sharti			    M_PKTHDR)) == NULL) {
1194116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1195116735Sharti				break;
1196116735Sharti			}
1197116735Sharti			/* No MEXT_ALIGN */
1198116735Sharti			m->m_data += MCLBYTES - LARGE_BUFFER_LEN;
1199116735Sharti			error = bus_dmamap_load(sc->rbuf_tag, rb->map,
1200116735Sharti			    m->m_data, LARGE_BUFFER_LEN, dmaload_helper,
1201116735Sharti			    &phys, BUS_DMA_NOWAIT);
1202116735Sharti			if (error) {
1203147256Sbrooks				if_printf(sc->ifp,
1204116735Sharti				    "dmamap_load mbuf failed %d", error);
1205116735Sharti				m_freem(m);
1206116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1207116735Sharti				break;
1208116735Sharti			}
1209116735Sharti
1210116735Sharti			bus_dmamap_sync(sc->rbuf_tag, rb->map,
1211116735Sharti			    BUS_DMASYNC_PREREAD);
1212116735Sharti
1213116735Sharti			LIST_REMOVE(rb, link);
1214116735Sharti			LIST_INSERT_HEAD(&sc->rbuf_used, rb, link);
1215116735Sharti
1216116735Sharti			rb->m = m;
1217116735Sharti			bd[i].handle = rb - sc->rbufs;
1218116735Sharti			H_SETDESC(bd[i].buffer, phys);
1219116735Sharti		}
1220116735Sharti
1221116735Sharti		if (i < LARGE_SUPPLY_BLKSIZE) {
1222116735Sharti			for (j = 0; j < i; j++) {
1223116735Sharti				rb = sc->rbufs + bd[j].handle;
1224116735Sharti				bus_dmamap_unload(sc->rbuf_tag, rb->map);
1225116735Sharti				m_free(rb->m);
1226116735Sharti				rb->m = NULL;
1227116735Sharti
1228116735Sharti				LIST_REMOVE(rb, link);
1229116735Sharti				LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1230116735Sharti			}
1231116735Sharti			break;
1232116735Sharti		}
1233116735Sharti		H_SYNCQ_PREWRITE(&sc->l1q_mem, bd,
1234116735Sharti		    sizeof(struct rbd) * LARGE_SUPPLY_BLKSIZE);
1235116735Sharti
1236116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
1237116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1238116735Sharti		WRITE4(sc, q->q.card, q->q.card_ioblk);
1239116735Sharti		BARRIER_W(sc);
1240116735Sharti
1241116735Sharti		sc->large_cnt += LARGE_SUPPLY_BLKSIZE;
1242116735Sharti
1243116735Sharti		NEXT_QUEUE_ENTRY(sc->l1queue.head, LARGE_SUPPLY_QLEN);
1244116735Sharti	}
1245116735Sharti}
1246116735Sharti
1247116735Sharti
1248116735Sharti/*
1249116735Sharti * Actually start the card. The lock must be held here.
1250116735Sharti * Reset, load the firmware, start it, initializes queues, read the PROM
1251116735Sharti * and supply receive buffers to the card.
1252116735Sharti */
1253116735Shartistatic void
1254116735Shartifatm_init_locked(struct fatm_softc *sc)
1255116735Sharti{
1256116735Sharti	struct rxqueue *q;
1257118596Sharti	int i, c, error;
1258116735Sharti	uint32_t start;
1259116735Sharti
1260116735Sharti	DBG(sc, INIT, ("initialize"));
1261148887Srwatson	if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
1262116735Sharti		fatm_stop(sc);
1263116735Sharti
1264116735Sharti	/*
1265116735Sharti	 * Hard reset the board
1266116735Sharti	 */
1267116735Sharti	if (fatm_reset(sc))
1268116735Sharti		return;
1269116735Sharti
1270116735Sharti	start = firmware_load(sc);
1271116735Sharti	if (fatm_start_firmware(sc, start) || fatm_init_cmd(sc) ||
1272116735Sharti	    fatm_getprom(sc)) {
1273116735Sharti		fatm_reset(sc);
1274116735Sharti		return;
1275116735Sharti	}
1276116735Sharti
1277116735Sharti	/*
1278116735Sharti	 * Handle media
1279116735Sharti	 */
1280116735Sharti	c = READ4(sc, FATMO_MEDIA_TYPE);
1281116735Sharti	switch (c) {
1282116735Sharti
1283116735Sharti	  case FORE_MT_TAXI_100:
1284147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_100;
1285147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 227273;
1286116735Sharti		break;
1287116735Sharti
1288116735Sharti	  case FORE_MT_TAXI_140:
1289147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_140;
1290147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 318181;
1291116735Sharti		break;
1292116735Sharti
1293116735Sharti	  case FORE_MT_UTP_SONET:
1294147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_155;
1295147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 353207;
1296116735Sharti		break;
1297116735Sharti
1298116735Sharti	  case FORE_MT_MM_OC3_ST:
1299116735Sharti	  case FORE_MT_MM_OC3_SC:
1300147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155;
1301147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 353207;
1302116735Sharti		break;
1303116735Sharti
1304116735Sharti	  case FORE_MT_SM_OC3_ST:
1305116735Sharti	  case FORE_MT_SM_OC3_SC:
1306147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_SM_155;
1307147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 353207;
1308116735Sharti		break;
1309116735Sharti
1310116735Sharti	  default:
1311116735Sharti		log(LOG_ERR, "fatm: unknown media type %d\n", c);
1312147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
1313147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = 353207;
1314116735Sharti		break;
1315116735Sharti	}
1316147256Sbrooks	sc->ifp->if_baudrate = 53 * 8 * IFP2IFATM(sc->ifp)->mib.pcr;
1317116735Sharti	utopia_init_media(&sc->utopia);
1318116735Sharti
1319116735Sharti	/*
1320116735Sharti	 * Initialize the RBDs
1321116735Sharti	 */
1322116735Sharti	for (i = 0; i < FATM_RX_QLEN; i++) {
1323116735Sharti		q = GET_QUEUE(sc->rxqueue, struct rxqueue, i);
1324116735Sharti		WRITE4(sc, q->q.card + 0, q->q.card_ioblk);
1325116735Sharti	}
1326116735Sharti	BARRIER_W(sc);
1327116735Sharti
1328116735Sharti	/*
1329116735Sharti	 * Supply buffers to the card
1330116735Sharti	 */
1331116735Sharti	fatm_supply_small_buffers(sc);
1332116735Sharti	fatm_supply_large_buffers(sc);
1333116735Sharti
1334116735Sharti	/*
1335116735Sharti	 * Now set flags, that we are ready
1336116735Sharti	 */
1337148887Srwatson	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
1338116735Sharti
1339116735Sharti	/*
1340116735Sharti	 * Start the watchdog timer
1341116735Sharti	 */
1342199559Sjhb	callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc);
1343116735Sharti
1344116735Sharti	/* start SUNI */
1345116735Sharti	utopia_start(&sc->utopia);
1346116735Sharti
1347147256Sbrooks	ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
1348118168Sharti	    sc->utopia.carrier == UTP_CARR_OK);
1349118168Sharti
1350118596Sharti	/* start all channels */
1351118596Sharti	for (i = 0; i < FORE_MAX_VCC + 1; i++)
1352118596Sharti		if (sc->vccs[i] != NULL) {
1353118596Sharti			sc->vccs[i]->vflags |= FATM_VCC_REOPEN;
1354118596Sharti			error = fatm_load_vc(sc, sc->vccs[i]);
1355118596Sharti			if (error != 0) {
1356147256Sbrooks				if_printf(sc->ifp, "reopening %u "
1357118596Sharti				    "failed: %d\n", i, error);
1358118596Sharti				sc->vccs[i]->vflags &= ~FATM_VCC_REOPEN;
1359118596Sharti			}
1360118596Sharti		}
1361118596Sharti
1362116735Sharti	DBG(sc, INIT, ("done"));
1363116735Sharti}
1364116735Sharti
1365116735Sharti/*
1366116735Sharti * This is the exported as initialisation function.
1367116735Sharti */
1368116735Shartistatic void
1369116735Shartifatm_init(void *p)
1370116735Sharti{
1371116735Sharti	struct fatm_softc *sc = p;
1372116735Sharti
1373116735Sharti	FATM_LOCK(sc);
1374116735Sharti	fatm_init_locked(sc);
1375116735Sharti	FATM_UNLOCK(sc);
1376116735Sharti}
1377116735Sharti
1378116735Sharti/************************************************************/
1379116735Sharti/*
1380116735Sharti * The INTERRUPT handling
1381116735Sharti */
1382116735Sharti/*
1383116735Sharti * Check the command queue. If a command was completed, call the completion
1384116735Sharti * function for that command.
1385116735Sharti */
1386116735Shartistatic void
1387116735Shartifatm_intr_drain_cmd(struct fatm_softc *sc)
1388116735Sharti{
1389116735Sharti	struct cmdqueue *q;
1390116735Sharti	int stat;
1391116735Sharti
1392116735Sharti	/*
1393116735Sharti	 * Drain command queue
1394116735Sharti	 */
1395116735Sharti	for (;;) {
1396116735Sharti		q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.tail);
1397116735Sharti
1398116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1399116735Sharti		stat = H_GETSTAT(q->q.statp);
1400116735Sharti
1401116735Sharti		if (stat != FATM_STAT_COMPLETE &&
1402116735Sharti		   stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) &&
1403116735Sharti		   stat != FATM_STAT_ERROR)
1404116735Sharti			break;
1405116735Sharti
1406116735Sharti		(*q->cb)(sc, q);
1407116735Sharti
1408116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_FREE);
1409116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1410116735Sharti
1411116735Sharti		NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN);
1412116735Sharti	}
1413116735Sharti}
1414116735Sharti
1415116735Sharti/*
1416116735Sharti * Drain the small buffer supply queue.
1417116735Sharti */
1418116735Shartistatic void
1419116735Shartifatm_intr_drain_small_buffers(struct fatm_softc *sc)
1420116735Sharti{
1421116735Sharti	struct supqueue *q;
1422116735Sharti	int stat;
1423116735Sharti
1424116735Sharti	for (;;) {
1425116735Sharti		q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.tail);
1426116735Sharti
1427116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1428116735Sharti		stat = H_GETSTAT(q->q.statp);
1429116735Sharti
1430116735Sharti		if ((stat & FATM_STAT_COMPLETE) == 0)
1431116735Sharti			break;
1432116735Sharti		if (stat & FATM_STAT_ERROR)
1433116735Sharti			log(LOG_ERR, "%s: status %x\n", __func__, stat);
1434116735Sharti
1435116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_FREE);
1436116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1437116735Sharti
1438116735Sharti		NEXT_QUEUE_ENTRY(sc->s1queue.tail, SMALL_SUPPLY_QLEN);
1439116735Sharti	}
1440116735Sharti}
1441116735Sharti
1442116735Sharti/*
1443116735Sharti * Drain the large buffer supply queue.
1444116735Sharti */
1445116735Shartistatic void
1446116735Shartifatm_intr_drain_large_buffers(struct fatm_softc *sc)
1447116735Sharti{
1448116735Sharti	struct supqueue *q;
1449116735Sharti	int stat;
1450116735Sharti
1451116735Sharti	for (;;) {
1452116735Sharti		q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.tail);
1453116735Sharti
1454116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1455116735Sharti		stat = H_GETSTAT(q->q.statp);
1456116735Sharti
1457116735Sharti		if ((stat & FATM_STAT_COMPLETE) == 0)
1458116735Sharti			break;
1459116735Sharti		if (stat & FATM_STAT_ERROR)
1460116735Sharti			log(LOG_ERR, "%s status %x\n", __func__, stat);
1461116735Sharti
1462116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_FREE);
1463116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1464116735Sharti
1465116735Sharti		NEXT_QUEUE_ENTRY(sc->l1queue.tail, LARGE_SUPPLY_QLEN);
1466116735Sharti	}
1467116735Sharti}
1468116735Sharti
1469116735Sharti/*
1470116735Sharti * Check the receive queue. Send any received PDU up the protocol stack
1471116735Sharti * (except when there was an error or the VCI appears to be closed. In this
1472116735Sharti * case discard the PDU).
1473116735Sharti */
1474116735Shartistatic void
1475116735Shartifatm_intr_drain_rx(struct fatm_softc *sc)
1476116735Sharti{
1477116735Sharti	struct rxqueue *q;
1478118208Sharti	int stat, mlen;
1479116735Sharti	u_int i;
1480116735Sharti	uint32_t h;
1481116735Sharti	struct mbuf *last, *m0;
1482116735Sharti	struct rpd *rpd;
1483116735Sharti	struct rbuf *rb;
1484116735Sharti	u_int vci, vpi, pt;
1485116735Sharti	struct atm_pseudohdr aph;
1486116735Sharti	struct ifnet *ifp;
1487118208Sharti	struct card_vcc *vc;
1488116735Sharti
1489116735Sharti	for (;;) {
1490116735Sharti		q = GET_QUEUE(sc->rxqueue, struct rxqueue, sc->rxqueue.tail);
1491116735Sharti
1492116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1493116735Sharti		stat = H_GETSTAT(q->q.statp);
1494116735Sharti
1495116735Sharti		if ((stat & FATM_STAT_COMPLETE) == 0)
1496116735Sharti			break;
1497116735Sharti
1498116735Sharti		rpd = (struct rpd *)q->q.ioblk;
1499116735Sharti		H_SYNCQ_POSTREAD(&sc->rxq_mem, rpd, RPD_SIZE);
1500116735Sharti
1501116735Sharti		rpd->nseg = le32toh(rpd->nseg);
1502116735Sharti		mlen = 0;
1503116735Sharti		m0 = last = 0;
1504116735Sharti		for (i = 0; i < rpd->nseg; i++) {
1505116735Sharti			rb = sc->rbufs + rpd->segment[i].handle;
1506116735Sharti			if (m0 == NULL) {
1507116735Sharti				m0 = last = rb->m;
1508116735Sharti			} else {
1509116735Sharti				last->m_next = rb->m;
1510116735Sharti				last = rb->m;
1511116735Sharti			}
1512116735Sharti			last->m_next = NULL;
1513116735Sharti			if (last->m_flags & M_EXT)
1514116735Sharti				sc->large_cnt--;
1515116735Sharti			else
1516116735Sharti				sc->small_cnt--;
1517116735Sharti			bus_dmamap_sync(sc->rbuf_tag, rb->map,
1518116735Sharti			    BUS_DMASYNC_POSTREAD);
1519116735Sharti			bus_dmamap_unload(sc->rbuf_tag, rb->map);
1520116735Sharti			rb->m = NULL;
1521116735Sharti
1522116735Sharti			LIST_REMOVE(rb, link);
1523116735Sharti			LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
1524116735Sharti
1525116735Sharti			last->m_len = le32toh(rpd->segment[i].length);
1526116735Sharti			mlen += last->m_len;
1527116735Sharti		}
1528116735Sharti
1529116735Sharti		m0->m_pkthdr.len = mlen;
1530147256Sbrooks		m0->m_pkthdr.rcvif = sc->ifp;
1531116735Sharti
1532116735Sharti		h = le32toh(rpd->atm_header);
1533116735Sharti		vpi = (h >> 20) & 0xff;
1534116735Sharti		vci = (h >> 4 ) & 0xffff;
1535116735Sharti		pt  = (h >> 1 ) & 0x7;
1536116735Sharti
1537116735Sharti		/*
1538116735Sharti		 * Locate the VCC this packet belongs to
1539116735Sharti		 */
1540116735Sharti		if (!VC_OK(sc, vpi, vci))
1541118208Sharti			vc = NULL;
1542118208Sharti		else if ((vc = sc->vccs[vci]) == NULL ||
1543118208Sharti		    !(sc->vccs[vci]->vflags & FATM_VCC_OPEN)) {
1544116735Sharti			sc->istats.rx_closed++;
1545118208Sharti			vc = NULL;
1546116735Sharti		}
1547116735Sharti
1548116735Sharti		DBG(sc, RCV, ("RCV: vc=%u.%u pt=%u mlen=%d %s", vpi, vci,
1549118208Sharti		    pt, mlen, vc == NULL ? "dropped" : ""));
1550116735Sharti
1551118208Sharti		if (vc == NULL) {
1552116735Sharti			m_freem(m0);
1553116735Sharti		} else {
1554147525Sharti#ifdef ENABLE_BPF
1555147525Sharti			if (!(vc->param.flags & ATMIO_FLAG_NG) &&
1556147525Sharti			    vc->param.aal == ATMIO_AAL_5 &&
1557147525Sharti			    (vc->param.flags & ATM_PH_LLCSNAP))
1558147525Sharti				BPF_MTAP(sc->ifp, m0);
1559147525Sharti#endif
1560147525Sharti
1561118208Sharti			ATM_PH_FLAGS(&aph) = vc->param.flags;
1562116735Sharti			ATM_PH_VPI(&aph) = vpi;
1563116735Sharti			ATM_PH_SETVCI(&aph, vci);
1564116735Sharti
1565147256Sbrooks			ifp = sc->ifp;
1566116735Sharti			ifp->if_ipackets++;
1567116735Sharti
1568118208Sharti			vc->ipackets++;
1569118208Sharti			vc->ibytes += m0->m_pkthdr.len;
1570118208Sharti
1571118208Sharti			atm_input(ifp, &aph, m0, vc->rxhand);
1572116735Sharti		}
1573116735Sharti
1574116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_FREE);
1575116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1576116735Sharti
1577116735Sharti		WRITE4(sc, q->q.card, q->q.card_ioblk);
1578116735Sharti		BARRIER_W(sc);
1579116735Sharti
1580116735Sharti		NEXT_QUEUE_ENTRY(sc->rxqueue.tail, FATM_RX_QLEN);
1581116735Sharti	}
1582116735Sharti}
1583116735Sharti
1584116735Sharti/*
1585116735Sharti * Check the transmit queue. Free the mbuf chains that we were transmitting.
1586116735Sharti */
1587116735Shartistatic void
1588116735Shartifatm_intr_drain_tx(struct fatm_softc *sc)
1589116735Sharti{
1590116735Sharti	struct txqueue *q;
1591116735Sharti	int stat;
1592116735Sharti
1593116735Sharti	/*
1594116735Sharti	 * Drain tx queue
1595116735Sharti	 */
1596116735Sharti	for (;;) {
1597116735Sharti		q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.tail);
1598116735Sharti
1599116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1600116735Sharti		stat = H_GETSTAT(q->q.statp);
1601116735Sharti
1602116735Sharti		if (stat != FATM_STAT_COMPLETE &&
1603116735Sharti		    stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) &&
1604116735Sharti		    stat != FATM_STAT_ERROR)
1605116735Sharti			break;
1606116735Sharti
1607116735Sharti		H_SETSTAT(q->q.statp, FATM_STAT_FREE);
1608116735Sharti		H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1609116735Sharti
1610116735Sharti		bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_POSTWRITE);
1611116735Sharti		bus_dmamap_unload(sc->tx_tag, q->map);
1612116735Sharti
1613116735Sharti		m_freem(q->m);
1614116735Sharti		q->m = NULL;
1615116735Sharti		sc->txcnt--;
1616116735Sharti
1617116735Sharti		NEXT_QUEUE_ENTRY(sc->txqueue.tail, FATM_TX_QLEN);
1618116735Sharti	}
1619116735Sharti}
1620116735Sharti
1621116735Sharti/*
1622116735Sharti * Interrupt handler
1623116735Sharti */
1624116735Shartistatic void
1625116735Shartifatm_intr(void *p)
1626116735Sharti{
1627116735Sharti	struct fatm_softc *sc = (struct fatm_softc *)p;
1628116735Sharti
1629116735Sharti	FATM_LOCK(sc);
1630116735Sharti	if (!READ4(sc, FATMO_PSR)) {
1631116735Sharti		FATM_UNLOCK(sc);
1632116735Sharti		return;
1633116735Sharti	}
1634116735Sharti	WRITE4(sc, FATMO_HCR, FATM_HCR_CLRIRQ);
1635116735Sharti
1636148887Srwatson	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1637116735Sharti		FATM_UNLOCK(sc);
1638116735Sharti		return;
1639116735Sharti	}
1640116735Sharti	fatm_intr_drain_cmd(sc);
1641116735Sharti	fatm_intr_drain_rx(sc);
1642116735Sharti	fatm_intr_drain_tx(sc);
1643116735Sharti	fatm_intr_drain_small_buffers(sc);
1644116735Sharti	fatm_intr_drain_large_buffers(sc);
1645116735Sharti	fatm_supply_small_buffers(sc);
1646116735Sharti	fatm_supply_large_buffers(sc);
1647116735Sharti
1648116735Sharti	FATM_UNLOCK(sc);
1649116735Sharti
1650147256Sbrooks	if (sc->retry_tx && _IF_QLEN(&sc->ifp->if_snd))
1651147256Sbrooks		(*sc->ifp->if_start)(sc->ifp);
1652116735Sharti}
1653116735Sharti
1654116735Sharti/*
1655116735Sharti * Get device statistics. This must be called with the softc locked.
1656116735Sharti * We use a preallocated buffer, so we need to protect this buffer.
1657116735Sharti * We do this by using a condition variable and a flag. If the flag is set
1658116735Sharti * the buffer is in use by one thread (one thread is executing a GETSTAT
1659116735Sharti * card command). In this case all other threads that are trying to get
1660116735Sharti * statistics block on that condition variable. When the thread finishes
1661116735Sharti * using the buffer it resets the flag and signals the condition variable. This
1662116735Sharti * will wakeup the next thread that is waiting for the buffer. If the interface
1663116735Sharti * is stopped the stopping function will broadcast the cv. All threads will
1664116735Sharti * find that the interface has been stopped and return.
1665116735Sharti *
1666116735Sharti * Aquiring of the buffer is done by the fatm_getstat() function. The freeing
1667116735Sharti * must be done by the caller when he has finished using the buffer.
1668116735Sharti */
1669116735Shartistatic void
1670116735Shartifatm_getstat_complete(struct fatm_softc *sc, struct cmdqueue *q)
1671116735Sharti{
1672116735Sharti
1673116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1674116735Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
1675116735Sharti		sc->istats.get_stat_errors++;
1676116735Sharti		q->error = EIO;
1677116735Sharti	}
1678116735Sharti	wakeup(&sc->sadi_mem);
1679116735Sharti}
1680116735Shartistatic int
1681116735Shartifatm_getstat(struct fatm_softc *sc)
1682116735Sharti{
1683116735Sharti	int error;
1684116735Sharti	struct cmdqueue *q;
1685116735Sharti
1686116735Sharti	/*
1687116735Sharti	 * Wait until either the interface is stopped or we can get the
1688116735Sharti	 * statistics buffer
1689116735Sharti	 */
1690116735Sharti	for (;;) {
1691148887Srwatson		if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
1692116735Sharti			return (EIO);
1693116735Sharti		if (!(sc->flags & FATM_STAT_INUSE))
1694116735Sharti			break;
1695116735Sharti		cv_wait(&sc->cv_stat, &sc->mtx);
1696116735Sharti	}
1697116735Sharti	sc->flags |= FATM_STAT_INUSE;
1698116735Sharti
1699116735Sharti	q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
1700116735Sharti
1701116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1702116735Sharti	if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
1703116735Sharti		sc->istats.cmd_queue_full++;
1704116735Sharti		return (EIO);
1705116735Sharti	}
1706116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
1707116735Sharti
1708116735Sharti	q->error = 0;
1709116735Sharti	q->cb = fatm_getstat_complete;
1710116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
1711116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1712116735Sharti
1713116735Sharti	bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map,
1714116735Sharti	    BUS_DMASYNC_PREREAD);
1715116735Sharti
1716116735Sharti	WRITE4(sc, q->q.card + FATMOC_GSTAT_BUF,
1717116735Sharti	    sc->sadi_mem.paddr);
1718116735Sharti	BARRIER_W(sc);
1719116735Sharti	WRITE4(sc, q->q.card + FATMOC_OP,
1720116735Sharti	    FATM_OP_REQUEST_STATS | FATM_OP_INTERRUPT_SEL);
1721116735Sharti	BARRIER_W(sc);
1722116735Sharti
1723116735Sharti	/*
1724116735Sharti	 * Wait for the command to complete
1725116735Sharti	 */
1726116735Sharti	error = msleep(&sc->sadi_mem, &sc->mtx, PZERO | PCATCH,
1727116735Sharti	    "fatm_stat", hz);
1728116735Sharti
1729116735Sharti	switch (error) {
1730116735Sharti
1731116735Sharti	  case EWOULDBLOCK:
1732116735Sharti		error = EIO;
1733116735Sharti		break;
1734116735Sharti
1735116735Sharti	  case ERESTART:
1736116735Sharti		error = EINTR;
1737116735Sharti		break;
1738116735Sharti
1739116735Sharti	  case 0:
1740116735Sharti		bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map,
1741116735Sharti		    BUS_DMASYNC_POSTREAD);
1742116735Sharti		error = q->error;
1743116735Sharti		break;
1744116735Sharti	}
1745116735Sharti
1746116735Sharti	/*
1747116735Sharti	 * Swap statistics
1748116735Sharti	 */
1749116735Sharti	if (q->error == 0) {
1750116735Sharti		u_int i;
1751116735Sharti		uint32_t *p = (uint32_t *)sc->sadi_mem.mem;
1752116735Sharti
1753116735Sharti		for (i = 0; i < sizeof(struct fatm_stats) / sizeof(uint32_t);
1754116735Sharti		    i++, p++)
1755116735Sharti			*p = be32toh(*p);
1756116735Sharti	}
1757116735Sharti
1758116735Sharti	return (error);
1759116735Sharti}
1760116735Sharti
1761116735Sharti/*
1762116735Sharti * Create a copy of a single mbuf. It can have either internal or
1763116735Sharti * external data, it may have a packet header. External data is really
1764116735Sharti * copied, so the new buffer is writeable.
1765116735Sharti */
1766116735Shartistatic struct mbuf *
1767116735Sharticopy_mbuf(struct mbuf *m)
1768116735Sharti{
1769116735Sharti	struct mbuf *new;
1770116735Sharti
1771243857Sglebius	MGET(new, M_NOWAIT, MT_DATA);
1772116735Sharti	if (new == NULL)
1773116735Sharti		return (NULL);
1774116735Sharti
1775116735Sharti	if (m->m_flags & M_PKTHDR) {
1776116735Sharti		M_MOVE_PKTHDR(new, m);
1777177599Sru		if (m->m_len > MHLEN)
1778243857Sglebius			MCLGET(new, M_WAITOK);
1779116735Sharti	} else {
1780177599Sru		if (m->m_len > MLEN)
1781243857Sglebius			MCLGET(new, M_WAITOK);
1782116735Sharti	}
1783116735Sharti
1784116735Sharti	bcopy(m->m_data, new->m_data, m->m_len);
1785116735Sharti	new->m_len = m->m_len;
1786116735Sharti	new->m_flags &= ~M_RDONLY;
1787116735Sharti
1788116735Sharti	return (new);
1789116735Sharti}
1790116735Sharti
1791116735Sharti/*
1792116735Sharti * All segments must have a four byte aligned buffer address and a four
1793116735Sharti * byte aligned length. Step through an mbuf chain and check these conditions.
1794116735Sharti * If the buffer address is not aligned and this is a normal mbuf, move
1795116735Sharti * the data down. Else make a copy of the mbuf with aligned data.
1796116735Sharti * If the buffer length is not aligned steel data from the next mbuf.
1797116735Sharti * We don't need to check whether this has more than one external reference,
1798116735Sharti * because steeling data doesn't change the external cluster.
1799116735Sharti * If the last mbuf is not aligned, fill with zeroes.
1800116735Sharti *
1801116735Sharti * Return packet length (well we should have this in the packet header),
1802116735Sharti * but be careful not to count the zero fill at the end.
1803116735Sharti *
1804116735Sharti * If fixing fails free the chain and zero the pointer.
1805116735Sharti *
1806116735Sharti * We assume, that aligning the virtual address also aligns the mapped bus
1807116735Sharti * address.
1808116735Sharti */
1809116735Shartistatic u_int
1810116735Shartifatm_fix_chain(struct fatm_softc *sc, struct mbuf **mp)
1811116735Sharti{
1812116735Sharti	struct mbuf *m = *mp, *prev = NULL, *next, *new;
1813116735Sharti	u_int mlen = 0, fill = 0;
1814116735Sharti	int first, off;
1815116735Sharti	u_char *d, *cp;
1816116735Sharti
1817116735Sharti	do {
1818116735Sharti		next = m->m_next;
1819116735Sharti
1820116735Sharti		if ((uintptr_t)mtod(m, void *) % 4 != 0 ||
1821116735Sharti		   (m->m_len % 4 != 0 && next)) {
1822116735Sharti			/*
1823116735Sharti			 * Needs fixing
1824116735Sharti			 */
1825116735Sharti			first = (m == *mp);
1826116735Sharti
1827116735Sharti			d = mtod(m, u_char *);
1828116735Sharti			if ((off = (uintptr_t)(void *)d % 4) != 0) {
1829150346Sandre				if (M_WRITABLE(m)) {
1830116735Sharti					sc->istats.fix_addr_copy++;
1831116735Sharti					bcopy(d, d - off, m->m_len);
1832116735Sharti					m->m_data = (caddr_t)(d - off);
1833116735Sharti				} else {
1834116735Sharti					if ((new = copy_mbuf(m)) == NULL) {
1835116735Sharti						sc->istats.fix_addr_noext++;
1836116735Sharti						goto fail;
1837116735Sharti					}
1838116735Sharti					sc->istats.fix_addr_ext++;
1839116735Sharti					if (prev)
1840116735Sharti						prev->m_next = new;
1841116735Sharti					new->m_next = next;
1842116735Sharti					m_free(m);
1843116735Sharti					m = new;
1844116735Sharti				}
1845116735Sharti			}
1846116735Sharti
1847116735Sharti			if ((off = m->m_len % 4) != 0) {
1848150346Sandre				if (!M_WRITABLE(m)) {
1849116735Sharti					if ((new = copy_mbuf(m)) == NULL) {
1850116735Sharti						sc->istats.fix_len_noext++;
1851116735Sharti						goto fail;
1852116735Sharti					}
1853116735Sharti					sc->istats.fix_len_copy++;
1854116735Sharti					if (prev)
1855116735Sharti						prev->m_next = new;
1856116735Sharti					new->m_next = next;
1857116735Sharti					m_free(m);
1858116735Sharti					m = new;
1859116735Sharti				} else
1860116735Sharti					sc->istats.fix_len++;
1861116735Sharti				d = mtod(m, u_char *) + m->m_len;
1862116735Sharti				off = 4 - off;
1863116735Sharti				while (off) {
1864116735Sharti					if (next == NULL) {
1865116735Sharti						*d++ = 0;
1866116735Sharti						fill++;
1867116735Sharti					} else if (next->m_len == 0) {
1868116735Sharti						sc->istats.fix_empty++;
1869116735Sharti						next = m_free(next);
1870116735Sharti						continue;
1871116735Sharti					} else {
1872116735Sharti						cp = mtod(next, u_char *);
1873116735Sharti						*d++ = *cp++;
1874116735Sharti						next->m_len--;
1875116735Sharti						next->m_data = (caddr_t)cp;
1876116735Sharti					}
1877116735Sharti					off--;
1878116735Sharti					m->m_len++;
1879116735Sharti				}
1880116735Sharti			}
1881116735Sharti
1882116735Sharti			if (first)
1883116735Sharti				*mp = m;
1884116735Sharti		}
1885116735Sharti
1886116735Sharti		mlen += m->m_len;
1887116735Sharti		prev = m;
1888116735Sharti	} while ((m = next) != NULL);
1889116735Sharti
1890116735Sharti	return (mlen - fill);
1891116735Sharti
1892116735Sharti  fail:
1893116735Sharti	m_freem(*mp);
1894116735Sharti	*mp = NULL;
1895116735Sharti	return (0);
1896116735Sharti}
1897116735Sharti
1898116735Sharti/*
1899116735Sharti * The helper function is used to load the computed physical addresses
1900116735Sharti * into the transmit descriptor.
1901116735Sharti */
1902116735Shartistatic void
1903116735Shartifatm_tpd_load(void *varg, bus_dma_segment_t *segs, int nsegs,
1904116735Sharti    bus_size_t mapsize, int error)
1905116735Sharti{
1906116735Sharti	struct tpd *tpd = varg;
1907116735Sharti
1908116735Sharti	if (error)
1909116735Sharti		return;
1910116735Sharti
1911116735Sharti	KASSERT(nsegs <= TPD_EXTENSIONS + TXD_FIXED, ("too many segments"));
1912116735Sharti
1913116735Sharti	tpd->spec = 0;
1914116735Sharti	while (nsegs--) {
1915116735Sharti		H_SETDESC(tpd->segment[tpd->spec].buffer, segs->ds_addr);
1916116735Sharti		H_SETDESC(tpd->segment[tpd->spec].length, segs->ds_len);
1917116735Sharti		tpd->spec++;
1918116735Sharti		segs++;
1919116735Sharti	}
1920116735Sharti}
1921116735Sharti
1922116735Sharti/*
1923116735Sharti * Start output.
1924116735Sharti *
1925116735Sharti * Note, that we update the internal statistics without the lock here.
1926116735Sharti */
1927116735Shartistatic int
1928118208Shartifatm_tx(struct fatm_softc *sc, struct mbuf *m, struct card_vcc *vc, u_int mlen)
1929116735Sharti{
1930116735Sharti	struct txqueue *q;
1931116735Sharti	u_int nblks;
1932116735Sharti	int error, aal, nsegs;
1933116735Sharti	struct tpd *tpd;
1934116735Sharti
1935116735Sharti	/*
1936116735Sharti	 * Get a queue element.
1937116735Sharti	 * If there isn't one - try to drain the transmit queue
1938116735Sharti	 * We used to sleep here if that doesn't help, but we
1939116735Sharti	 * should not sleep here, because we are called with locks.
1940116735Sharti	 */
1941116735Sharti	q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.head);
1942116735Sharti
1943116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1944116735Sharti	if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) {
1945116735Sharti		fatm_intr_drain_tx(sc);
1946116735Sharti		H_SYNCSTAT_POSTREAD(sc, q->q.statp);
1947116735Sharti		if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) {
1948116735Sharti			if (sc->retry_tx) {
1949116735Sharti				sc->istats.tx_retry++;
1950147256Sbrooks				IF_PREPEND(&sc->ifp->if_snd, m);
1951116735Sharti				return (1);
1952116735Sharti			}
1953116735Sharti			sc->istats.tx_queue_full++;
1954116735Sharti			m_freem(m);
1955116735Sharti			return (0);
1956116735Sharti		}
1957116735Sharti		sc->istats.tx_queue_almost_full++;
1958116735Sharti	}
1959116735Sharti
1960116735Sharti	tpd = q->q.ioblk;
1961116735Sharti
1962116735Sharti	m->m_data += sizeof(struct atm_pseudohdr);
1963116735Sharti	m->m_len -= sizeof(struct atm_pseudohdr);
1964116735Sharti
1965147525Sharti#ifdef ENABLE_BPF
1966147525Sharti	if (!(vc->param.flags & ATMIO_FLAG_NG) &&
1967147525Sharti	    vc->param.aal == ATMIO_AAL_5 &&
1968147525Sharti	    (vc->param.flags & ATM_PH_LLCSNAP))
1969147525Sharti		BPF_MTAP(sc->ifp, m);
1970147525Sharti#endif
1971147525Sharti
1972116735Sharti	/* map the mbuf */
1973116735Sharti	error = bus_dmamap_load_mbuf(sc->tx_tag, q->map, m,
1974116735Sharti	    fatm_tpd_load, tpd, BUS_DMA_NOWAIT);
1975116735Sharti	if(error) {
1976147256Sbrooks		sc->ifp->if_oerrors++;
1977147256Sbrooks		if_printf(sc->ifp, "mbuf loaded error=%d\n", error);
1978116735Sharti		m_freem(m);
1979116735Sharti		return (0);
1980116735Sharti	}
1981116735Sharti	nsegs = tpd->spec;
1982116735Sharti
1983116735Sharti	bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_PREWRITE);
1984116735Sharti
1985116735Sharti	/*
1986116735Sharti	 * OK. Now go and do it.
1987116735Sharti	 */
1988118208Sharti	aal = (vc->param.aal == ATMIO_AAL_5) ? 5 : 0;
1989116735Sharti
1990116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
1991116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
1992116735Sharti	q->m = m;
1993116735Sharti
1994116735Sharti	/*
1995116735Sharti	 * If the transmit queue is almost full, schedule a
1996116735Sharti	 * transmit interrupt so that transmit descriptors can
1997116735Sharti	 * be recycled.
1998116735Sharti	 */
1999116735Sharti	H_SETDESC(tpd->spec, TDX_MKSPEC((sc->txcnt >=
2000116735Sharti	    (4 * FATM_TX_QLEN) / 5), aal, nsegs, mlen));
2001118208Sharti	H_SETDESC(tpd->atm_header, TDX_MKHDR(vc->param.vpi,
2002118208Sharti	    vc->param.vci, 0, 0));
2003116735Sharti
2004118208Sharti	if (vc->param.traffic == ATMIO_TRAFFIC_UBR)
2005116735Sharti		H_SETDESC(tpd->stream, 0);
2006116735Sharti	else {
2007116735Sharti		u_int i;
2008116735Sharti
2009116735Sharti		for (i = 0; i < RATE_TABLE_SIZE; i++)
2010118208Sharti			if (rate_table[i].cell_rate < vc->param.tparam.pcr)
2011116735Sharti				break;
2012116735Sharti		if (i > 0)
2013116735Sharti			i--;
2014116735Sharti		H_SETDESC(tpd->stream, rate_table[i].ratio);
2015116735Sharti	}
2016116735Sharti	H_SYNCQ_PREWRITE(&sc->txq_mem, tpd, TPD_SIZE);
2017116735Sharti
2018116735Sharti	nblks = TDX_SEGS2BLKS(nsegs);
2019116735Sharti
2020116735Sharti	DBG(sc, XMIT, ("XMIT: mlen=%d spec=0x%x nsegs=%d blocks=%d",
2021116735Sharti	    mlen, le32toh(tpd->spec), nsegs, nblks));
2022116735Sharti
2023116735Sharti	WRITE4(sc, q->q.card + 0, q->q.card_ioblk | nblks);
2024116735Sharti	BARRIER_W(sc);
2025116735Sharti
2026116735Sharti	sc->txcnt++;
2027147256Sbrooks	sc->ifp->if_opackets++;
2028118208Sharti	vc->obytes += m->m_pkthdr.len;
2029118208Sharti	vc->opackets++;
2030116735Sharti
2031116735Sharti	NEXT_QUEUE_ENTRY(sc->txqueue.head, FATM_TX_QLEN);
2032116735Sharti
2033116735Sharti	return (0);
2034116735Sharti}
2035116735Sharti
2036116735Shartistatic void
2037116735Shartifatm_start(struct ifnet *ifp)
2038116735Sharti{
2039116735Sharti	struct atm_pseudohdr aph;
2040116735Sharti	struct fatm_softc *sc;
2041116735Sharti	struct mbuf *m;
2042116735Sharti	u_int mlen, vpi, vci;
2043118208Sharti	struct card_vcc *vc;
2044116735Sharti
2045147721Sharti	sc = ifp->if_softc;
2046116735Sharti
2047116735Sharti	while (1) {
2048116735Sharti		IF_DEQUEUE(&ifp->if_snd, m);
2049116735Sharti		if (m == NULL)
2050116735Sharti			break;
2051116735Sharti
2052116735Sharti		/*
2053116735Sharti		 * Loop through the mbuf chain and compute the total length
2054116735Sharti		 * of the packet. Check that all data pointer are
2055116735Sharti		 * 4 byte aligned. If they are not, call fatm_mfix to
2056116735Sharti		 * fix that problem. This comes more or less from the
2057116735Sharti		 * en driver.
2058116735Sharti		 */
2059116735Sharti		mlen = fatm_fix_chain(sc, &m);
2060116735Sharti		if (m == NULL)
2061116735Sharti			continue;
2062116735Sharti
2063116735Sharti		if (m->m_len < sizeof(struct atm_pseudohdr) &&
2064116735Sharti		    (m = m_pullup(m, sizeof(struct atm_pseudohdr))) == NULL)
2065116735Sharti			continue;
2066116735Sharti
2067116735Sharti		aph = *mtod(m, struct atm_pseudohdr *);
2068116735Sharti		mlen -= sizeof(struct atm_pseudohdr);
2069116735Sharti
2070116735Sharti		if (mlen == 0) {
2071116735Sharti			m_freem(m);
2072116735Sharti			continue;
2073116735Sharti		}
2074116735Sharti		if (mlen > FATM_MAXPDU) {
2075116735Sharti			sc->istats.tx_pdu2big++;
2076116735Sharti			m_freem(m);
2077116735Sharti			continue;
2078116735Sharti		}
2079116735Sharti
2080116735Sharti		vci = ATM_PH_VCI(&aph);
2081116735Sharti		vpi = ATM_PH_VPI(&aph);
2082116735Sharti
2083116735Sharti		/*
2084116735Sharti		 * From here on we need the softc
2085116735Sharti		 */
2086116735Sharti		FATM_LOCK(sc);
2087148887Srwatson		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2088116735Sharti			FATM_UNLOCK(sc);
2089116735Sharti			m_freem(m);
2090116735Sharti			break;
2091116735Sharti		}
2092118208Sharti		if (!VC_OK(sc, vpi, vci) || (vc = sc->vccs[vci]) == NULL ||
2093118208Sharti		    !(vc->vflags & FATM_VCC_OPEN)) {
2094116735Sharti			FATM_UNLOCK(sc);
2095116735Sharti			m_freem(m);
2096116735Sharti			continue;
2097116735Sharti		}
2098118208Sharti		if (fatm_tx(sc, m, vc, mlen)) {
2099116735Sharti			FATM_UNLOCK(sc);
2100116735Sharti			break;
2101116735Sharti		}
2102116735Sharti		FATM_UNLOCK(sc);
2103116735Sharti	}
2104116735Sharti}
2105116735Sharti
2106116735Sharti/*
2107116735Sharti * VCC managment
2108116735Sharti *
2109116735Sharti * This may seem complicated. The reason for this is, that we need an
2110116735Sharti * asynchronuous open/close for the NATM VCCs because our ioctl handler
2111116735Sharti * is called with the radix node head of the routing table locked. Therefor
2112116735Sharti * we cannot sleep there and wait for the open/close to succeed. For this
2113116735Sharti * reason we just initiate the operation from the ioctl.
2114116735Sharti */
2115116735Sharti
2116116735Sharti/*
2117116735Sharti * Command the card to open/close a VC.
2118116735Sharti * Return the queue entry for waiting if we are succesful.
2119116735Sharti */
2120116735Shartistatic struct cmdqueue *
2121116735Shartifatm_start_vcc(struct fatm_softc *sc, u_int vpi, u_int vci, uint32_t cmd,
2122116735Sharti    u_int mtu, void (*func)(struct fatm_softc *, struct cmdqueue *))
2123116735Sharti{
2124116735Sharti	struct cmdqueue *q;
2125116735Sharti
2126116735Sharti	q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
2127116735Sharti
2128116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
2129116735Sharti	if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
2130116735Sharti		sc->istats.cmd_queue_full++;
2131116735Sharti		return (NULL);
2132116735Sharti	}
2133116735Sharti	NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
2134116735Sharti
2135116735Sharti	q->error = 0;
2136116735Sharti	q->cb = func;
2137116735Sharti	H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
2138116735Sharti	H_SYNCSTAT_PREWRITE(sc, q->q.statp);
2139116735Sharti
2140116735Sharti	WRITE4(sc, q->q.card + FATMOC_ACTIN_VPVC, MKVPVC(vpi, vci));
2141116735Sharti	BARRIER_W(sc);
2142116735Sharti	WRITE4(sc, q->q.card + FATMOC_ACTIN_MTU, mtu);
2143116735Sharti	BARRIER_W(sc);
2144116735Sharti	WRITE4(sc, q->q.card + FATMOC_OP, cmd);
2145116735Sharti	BARRIER_W(sc);
2146116735Sharti
2147116735Sharti	return (q);
2148116735Sharti}
2149116735Sharti
2150116735Sharti/*
2151118208Sharti * The VC has been opened/closed and somebody has been waiting for this.
2152118208Sharti * Wake him up.
2153116735Sharti */
2154118208Shartistatic void
2155118208Shartifatm_cmd_complete(struct fatm_softc *sc, struct cmdqueue *q)
2156116735Sharti{
2157116735Sharti
2158118208Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
2159118208Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
2160118208Sharti		sc->istats.get_stat_errors++;
2161118208Sharti		q->error = EIO;
2162118208Sharti	}
2163118208Sharti	wakeup(q);
2164118208Sharti}
2165116735Sharti
2166118208Sharti/*
2167118208Sharti * Open complete
2168118208Sharti */
2169118208Shartistatic void
2170118208Shartifatm_open_finish(struct fatm_softc *sc, struct card_vcc *vc)
2171118208Sharti{
2172118208Sharti	vc->vflags &= ~FATM_VCC_TRY_OPEN;
2173118208Sharti	vc->vflags |= FATM_VCC_OPEN;
2174116735Sharti
2175118596Sharti	if (vc->vflags & FATM_VCC_REOPEN) {
2176118596Sharti		vc->vflags &= ~FATM_VCC_REOPEN;
2177118596Sharti		return;
2178118596Sharti	}
2179118596Sharti
2180118208Sharti	/* inform management if this is not an NG
2181118208Sharti	 * VCC or it's an NG PVC. */
2182118208Sharti	if (!(vc->param.flags & ATMIO_FLAG_NG) ||
2183118208Sharti	    (vc->param.flags & ATMIO_FLAG_PVC))
2184147256Sbrooks		ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 1);
2185116735Sharti}
2186116735Sharti
2187116735Sharti/*
2188118208Sharti * The VC that we have tried to open asynchronuosly has been opened.
2189116735Sharti */
2190118208Shartistatic void
2191118208Shartifatm_open_complete(struct fatm_softc *sc, struct cmdqueue *q)
2192116735Sharti{
2193118208Sharti	u_int vci;
2194118208Sharti	struct card_vcc *vc;
2195116735Sharti
2196118208Sharti	vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC));
2197118208Sharti	vc = sc->vccs[vci];
2198118208Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
2199118208Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
2200118208Sharti		sc->istats.get_stat_errors++;
2201118208Sharti		sc->vccs[vci] = NULL;
2202118208Sharti		uma_zfree(sc->vcc_zone, vc);
2203147256Sbrooks		if_printf(sc->ifp, "opening VCI %u failed\n", vci);
2204118208Sharti		return;
2205118208Sharti	}
2206118208Sharti	fatm_open_finish(sc, vc);
2207116735Sharti}
2208116735Sharti
2209116735Sharti/*
2210116735Sharti * Wait on the queue entry until the VCC is opened/closed.
2211116735Sharti */
2212116735Shartistatic int
2213116735Shartifatm_waitvcc(struct fatm_softc *sc, struct cmdqueue *q)
2214116735Sharti{
2215116735Sharti	int error;
2216116735Sharti
2217116735Sharti	/*
2218116735Sharti	 * Wait for the command to complete
2219116735Sharti	 */
2220116735Sharti	error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_vci", hz);
2221116735Sharti
2222116735Sharti	if (error != 0)
2223116735Sharti		return (error);
2224116735Sharti	return (q->error);
2225116735Sharti}
2226116735Sharti
2227116735Sharti/*
2228118208Sharti * Start to open a VCC. This just initiates the operation.
2229116735Sharti */
2230116735Shartistatic int
2231118548Shartifatm_open_vcc(struct fatm_softc *sc, struct atmio_openvcc *op)
2232116735Sharti{
2233116735Sharti	int error;
2234118208Sharti	struct card_vcc *vc;
2235116735Sharti
2236118208Sharti	/*
2237118208Sharti	 * Check parameters
2238118208Sharti	 */
2239118208Sharti	if ((op->param.flags & ATMIO_FLAG_NOTX) &&
2240118208Sharti	    (op->param.flags & ATMIO_FLAG_NORX))
2241118208Sharti		return (EINVAL);
2242118208Sharti
2243118208Sharti	if (!VC_OK(sc, op->param.vpi, op->param.vci))
2244118208Sharti		return (EINVAL);
2245118208Sharti	if (op->param.aal != ATMIO_AAL_0 && op->param.aal != ATMIO_AAL_5)
2246118208Sharti		return (EINVAL);
2247118208Sharti
2248118208Sharti	vc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO);
2249118208Sharti	if (vc == NULL)
2250118208Sharti		return (ENOMEM);
2251118208Sharti
2252116735Sharti	error = 0;
2253116735Sharti
2254116735Sharti	FATM_LOCK(sc);
2255148887Srwatson	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2256118208Sharti		error = EIO;
2257118208Sharti		goto done;
2258116735Sharti	}
2259118208Sharti	if (sc->vccs[op->param.vci] != NULL) {
2260118208Sharti		error = EBUSY;
2261118208Sharti		goto done;
2262118208Sharti	}
2263118208Sharti	vc->param = op->param;
2264118208Sharti	vc->rxhand = op->rxhand;
2265116735Sharti
2266118208Sharti	switch (op->param.traffic) {
2267116735Sharti
2268118208Sharti	  case ATMIO_TRAFFIC_UBR:
2269118208Sharti		break;
2270116735Sharti
2271118208Sharti	  case ATMIO_TRAFFIC_CBR:
2272118208Sharti		if (op->param.tparam.pcr == 0 ||
2273147256Sbrooks		    op->param.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr) {
2274118208Sharti			error = EINVAL;
2275118208Sharti			goto done;
2276118208Sharti		}
2277118208Sharti		break;
2278116735Sharti
2279118208Sharti	  default:
2280118208Sharti		error = EINVAL;
2281118208Sharti		goto done;
2282118208Sharti	}
2283118208Sharti	vc->ibytes = vc->obytes = 0;
2284118208Sharti	vc->ipackets = vc->opackets = 0;
2285116735Sharti
2286118208Sharti	vc->vflags = FATM_VCC_TRY_OPEN;
2287118208Sharti	sc->vccs[op->param.vci] = vc;
2288118208Sharti	sc->open_vccs++;
2289116735Sharti
2290118596Sharti	error = fatm_load_vc(sc, vc);
2291123798Speter	if (error != 0) {
2292118596Sharti		sc->vccs[op->param.vci] = NULL;
2293118596Sharti		sc->open_vccs--;
2294118596Sharti		goto done;
2295116735Sharti	}
2296116735Sharti
2297118208Sharti	/* don't free below */
2298118208Sharti	vc = NULL;
2299118208Sharti
2300118208Sharti  done:
2301116735Sharti	FATM_UNLOCK(sc);
2302118208Sharti	if (vc != NULL)
2303118208Sharti		uma_zfree(sc->vcc_zone, vc);
2304116735Sharti	return (error);
2305116735Sharti}
2306116735Sharti
2307116735Sharti/*
2308118596Sharti * Try to initialize the given VC
2309118596Sharti */
2310118596Shartistatic int
2311118596Shartifatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc)
2312118596Sharti{
2313118596Sharti	uint32_t cmd;
2314118596Sharti	struct cmdqueue *q;
2315118596Sharti	int error;
2316118596Sharti
2317118596Sharti	/* Command and buffer strategy */
2318118596Sharti	cmd = FATM_OP_ACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL | (0 << 16);
2319118596Sharti	if (vc->param.aal == ATMIO_AAL_0)
2320118596Sharti		cmd |= (0 << 8);
2321118596Sharti	else
2322118596Sharti		cmd |= (5 << 8);
2323118596Sharti
2324118596Sharti	q = fatm_start_vcc(sc, vc->param.vpi, vc->param.vci, cmd, 1,
2325118596Sharti	    (vc->param.flags & ATMIO_FLAG_ASYNC) ?
2326118596Sharti	    fatm_open_complete : fatm_cmd_complete);
2327118596Sharti	if (q == NULL)
2328118596Sharti		return (EIO);
2329118596Sharti
2330118596Sharti	if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) {
2331118596Sharti		error = fatm_waitvcc(sc, q);
2332118596Sharti		if (error != 0)
2333118596Sharti			return (error);
2334118596Sharti		fatm_open_finish(sc, vc);
2335118596Sharti	}
2336118596Sharti	return (0);
2337118596Sharti}
2338118596Sharti
2339118596Sharti/*
2340118208Sharti * Finish close
2341116735Sharti */
2342116735Shartistatic void
2343118208Shartifatm_close_finish(struct fatm_softc *sc, struct card_vcc *vc)
2344116735Sharti{
2345118208Sharti	/* inform management of this is not an NG
2346118208Sharti	 * VCC or it's an NG PVC. */
2347118208Sharti	if (!(vc->param.flags & ATMIO_FLAG_NG) ||
2348118208Sharti	    (vc->param.flags & ATMIO_FLAG_PVC))
2349147256Sbrooks		ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 0);
2350116735Sharti
2351118208Sharti	sc->vccs[vc->param.vci] = NULL;
2352118208Sharti	sc->open_vccs--;
2353116735Sharti
2354118208Sharti	uma_zfree(sc->vcc_zone, vc);
2355116735Sharti}
2356116735Sharti
2357116735Sharti/*
2358116735Sharti * The VC has been closed.
2359116735Sharti */
2360116735Shartistatic void
2361116735Shartifatm_close_complete(struct fatm_softc *sc, struct cmdqueue *q)
2362116735Sharti{
2363116735Sharti	u_int vci;
2364118208Sharti	struct card_vcc *vc;
2365116735Sharti
2366116735Sharti	vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC));
2367118208Sharti	vc = sc->vccs[vci];
2368116735Sharti	H_SYNCSTAT_POSTREAD(sc, q->q.statp);
2369116735Sharti	if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
2370116735Sharti		sc->istats.get_stat_errors++;
2371116735Sharti		/* keep the VCC in that state */
2372147256Sbrooks		if_printf(sc->ifp, "closing VCI %u failed\n", vci);
2373116735Sharti		return;
2374116735Sharti	}
2375116735Sharti
2376118208Sharti	fatm_close_finish(sc, vc);
2377116735Sharti}
2378116735Sharti
2379116735Sharti/*
2380118208Sharti * Initiate closing a VCC
2381116735Sharti */
2382116735Shartistatic int
2383118548Shartifatm_close_vcc(struct fatm_softc *sc, struct atmio_closevcc *cl)
2384116735Sharti{
2385116735Sharti	int error;
2386118208Sharti	struct cmdqueue *q;
2387118208Sharti	struct card_vcc *vc;
2388116735Sharti
2389118208Sharti	if (!VC_OK(sc, cl->vpi, cl->vci))
2390118208Sharti		return (EINVAL);
2391118208Sharti
2392118208Sharti	error = 0;
2393118208Sharti
2394116735Sharti	FATM_LOCK(sc);
2395148887Srwatson	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2396118208Sharti		error = EIO;
2397118208Sharti		goto done;
2398118208Sharti	}
2399118208Sharti	vc = sc->vccs[cl->vci];
2400118208Sharti	if (vc == NULL || !(vc->vflags & (FATM_VCC_OPEN | FATM_VCC_TRY_OPEN))) {
2401118208Sharti		error = ENOENT;
2402118208Sharti		goto done;
2403118208Sharti	}
2404116735Sharti
2405118208Sharti	q = fatm_start_vcc(sc, cl->vpi, cl->vci,
2406118208Sharti	    FATM_OP_DEACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL, 1,
2407118548Sharti	    (vc->param.flags & ATMIO_FLAG_ASYNC) ?
2408118548Sharti	    fatm_close_complete : fatm_cmd_complete);
2409118208Sharti	if (q == NULL) {
2410118208Sharti		error = EIO;
2411118208Sharti		goto done;
2412118208Sharti	}
2413116735Sharti
2414118208Sharti	vc->vflags &= ~(FATM_VCC_OPEN | FATM_VCC_TRY_OPEN);
2415118208Sharti	vc->vflags |= FATM_VCC_TRY_CLOSE;
2416118208Sharti
2417118548Sharti	if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) {
2418118208Sharti		error = fatm_waitvcc(sc, q);
2419118208Sharti		if (error != 0)
2420118208Sharti			goto done;
2421118208Sharti
2422118208Sharti		fatm_close_finish(sc, vc);
2423118208Sharti	}
2424118208Sharti
2425118208Sharti  done:
2426116735Sharti	FATM_UNLOCK(sc);
2427116735Sharti	return (error);
2428116735Sharti}
2429116735Sharti
2430116735Sharti/*
2431116735Sharti * IOCTL handler
2432116735Sharti */
2433116735Shartistatic int
2434116735Shartifatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t arg)
2435116735Sharti{
2436116735Sharti	int error;
2437116735Sharti	struct fatm_softc *sc = ifp->if_softc;
2438116735Sharti	struct ifaddr *ifa = (struct ifaddr *)arg;
2439116735Sharti	struct ifreq *ifr = (struct ifreq *)arg;
2440116735Sharti	struct atmio_closevcc *cl = (struct atmio_closevcc *)arg;
2441116735Sharti	struct atmio_openvcc *op = (struct atmio_openvcc *)arg;
2442116735Sharti	struct atmio_vcctable *vtab;
2443116735Sharti
2444116735Sharti	error = 0;
2445116735Sharti	switch (cmd) {
2446116735Sharti
2447118548Sharti	  case SIOCATMOPENVCC:		/* kernel internal use */
2448118548Sharti		error = fatm_open_vcc(sc, op);
2449116735Sharti		break;
2450116735Sharti
2451118548Sharti	  case SIOCATMCLOSEVCC:		/* kernel internal use */
2452118548Sharti		error = fatm_close_vcc(sc, cl);
2453116735Sharti		break;
2454116735Sharti
2455116735Sharti	  case SIOCSIFADDR:
2456116735Sharti		FATM_LOCK(sc);
2457116735Sharti		ifp->if_flags |= IFF_UP;
2458148887Srwatson		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
2459116735Sharti			fatm_init_locked(sc);
2460116735Sharti		switch (ifa->ifa_addr->sa_family) {
2461116735Sharti#ifdef INET
2462116735Sharti		  case AF_INET:
2463116735Sharti		  case AF_INET6:
2464116735Sharti			ifa->ifa_rtrequest = atm_rtrequest;
2465116735Sharti			break;
2466116735Sharti#endif
2467116735Sharti		  default:
2468116735Sharti			break;
2469116735Sharti		}
2470116735Sharti		FATM_UNLOCK(sc);
2471116735Sharti		break;
2472116735Sharti
2473116735Sharti	  case SIOCSIFFLAGS:
2474116735Sharti		FATM_LOCK(sc);
2475116735Sharti		if (ifp->if_flags & IFF_UP) {
2476148887Srwatson			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2477116735Sharti				fatm_init_locked(sc);
2478116735Sharti			}
2479116735Sharti		} else {
2480148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2481116735Sharti				fatm_stop(sc);
2482116735Sharti			}
2483116735Sharti		}
2484116735Sharti		FATM_UNLOCK(sc);
2485116735Sharti		break;
2486116735Sharti
2487116735Sharti	  case SIOCGIFMEDIA:
2488116735Sharti	  case SIOCSIFMEDIA:
2489148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2490116735Sharti			error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
2491116735Sharti		else
2492116735Sharti			error = EINVAL;
2493116735Sharti		break;
2494116735Sharti
2495116735Sharti	  case SIOCATMGVCCS:
2496116735Sharti		/* return vcc table */
2497118208Sharti		vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
2498118208Sharti		    FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 1);
2499116735Sharti		error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) +
2500116735Sharti		    vtab->count * sizeof(vtab->vccs[0]));
2501116735Sharti		free(vtab, M_DEVBUF);
2502116735Sharti		break;
2503116735Sharti
2504116735Sharti	  case SIOCATMGETVCCS:	/* internal netgraph use */
2505118208Sharti		vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
2506118208Sharti		    FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 0);
2507116735Sharti		if (vtab == NULL) {
2508116735Sharti			error = ENOMEM;
2509116735Sharti			break;
2510116735Sharti		}
2511116735Sharti		*(void **)arg = vtab;
2512116735Sharti		break;
2513116735Sharti
2514116735Sharti	  default:
2515116735Sharti		DBG(sc, IOCTL, ("+++ cmd=%08lx arg=%p", cmd, arg));
2516116735Sharti		error = EINVAL;
2517116735Sharti		break;
2518116735Sharti	}
2519116735Sharti
2520116735Sharti	return (error);
2521116735Sharti}
2522116735Sharti
2523116735Sharti/*
2524116735Sharti * Detach from the interface and free all resources allocated during
2525116735Sharti * initialisation and later.
2526116735Sharti */
2527116735Shartistatic int
2528116735Shartifatm_detach(device_t dev)
2529116735Sharti{
2530116735Sharti	u_int i;
2531116735Sharti	struct rbuf *rb;
2532116735Sharti	struct fatm_softc *sc;
2533116735Sharti	struct txqueue *tx;
2534116735Sharti
2535147721Sharti	sc = device_get_softc(dev);
2536116735Sharti
2537116735Sharti	if (device_is_alive(dev)) {
2538116735Sharti		FATM_LOCK(sc);
2539116735Sharti		fatm_stop(sc);
2540116735Sharti		utopia_detach(&sc->utopia);
2541116735Sharti		FATM_UNLOCK(sc);
2542147256Sbrooks		atm_ifdetach(sc->ifp);		/* XXX race */
2543116735Sharti	}
2544199559Sjhb	callout_drain(&sc->watchdog_timer);
2545116735Sharti
2546116735Sharti	if (sc->ih != NULL)
2547116735Sharti		bus_teardown_intr(dev, sc->irqres, sc->ih);
2548116735Sharti
2549116735Sharti	while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) {
2550147256Sbrooks		if_printf(sc->ifp, "rbuf %p still in use!\n", rb);
2551116735Sharti		bus_dmamap_unload(sc->rbuf_tag, rb->map);
2552116735Sharti		m_freem(rb->m);
2553116735Sharti		LIST_REMOVE(rb, link);
2554116735Sharti		LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
2555116735Sharti	}
2556116735Sharti
2557116735Sharti	if (sc->txqueue.chunk != NULL) {
2558116735Sharti		for (i = 0; i < FATM_TX_QLEN; i++) {
2559116735Sharti			tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
2560116735Sharti			bus_dmamap_destroy(sc->tx_tag, tx->map);
2561116735Sharti		}
2562116735Sharti	}
2563116735Sharti
2564116735Sharti	while ((rb = LIST_FIRST(&sc->rbuf_free)) != NULL) {
2565116735Sharti		bus_dmamap_destroy(sc->rbuf_tag, rb->map);
2566116735Sharti		LIST_REMOVE(rb, link);
2567116735Sharti	}
2568116735Sharti
2569118208Sharti	if (sc->rbufs != NULL)
2570118208Sharti		free(sc->rbufs, M_DEVBUF);
2571118596Sharti	if (sc->vccs != NULL) {
2572118596Sharti		for (i = 0; i < FORE_MAX_VCC + 1; i++)
2573118596Sharti			if (sc->vccs[i] != NULL) {
2574118596Sharti				uma_zfree(sc->vcc_zone, sc->vccs[i]);
2575118596Sharti				sc->vccs[i] = NULL;
2576118596Sharti			}
2577118208Sharti		free(sc->vccs, M_DEVBUF);
2578118596Sharti	}
2579118208Sharti	if (sc->vcc_zone != NULL)
2580118208Sharti		uma_zdestroy(sc->vcc_zone);
2581116735Sharti
2582118208Sharti	if (sc->l1queue.chunk != NULL)
2583118208Sharti		free(sc->l1queue.chunk, M_DEVBUF);
2584118208Sharti	if (sc->s1queue.chunk != NULL)
2585118208Sharti		free(sc->s1queue.chunk, M_DEVBUF);
2586118208Sharti	if (sc->rxqueue.chunk != NULL)
2587118208Sharti		free(sc->rxqueue.chunk, M_DEVBUF);
2588118208Sharti	if (sc->txqueue.chunk != NULL)
2589118208Sharti		free(sc->txqueue.chunk, M_DEVBUF);
2590118208Sharti	if (sc->cmdqueue.chunk != NULL)
2591118208Sharti		free(sc->cmdqueue.chunk, M_DEVBUF);
2592116735Sharti
2593116735Sharti	destroy_dma_memory(&sc->reg_mem);
2594116735Sharti	destroy_dma_memory(&sc->sadi_mem);
2595116735Sharti	destroy_dma_memory(&sc->prom_mem);
2596116735Sharti#ifdef TEST_DMA_SYNC
2597116735Sharti	destroy_dma_memoryX(&sc->s1q_mem);
2598116735Sharti	destroy_dma_memoryX(&sc->l1q_mem);
2599116735Sharti	destroy_dma_memoryX(&sc->rxq_mem);
2600116735Sharti	destroy_dma_memoryX(&sc->txq_mem);
2601116735Sharti	destroy_dma_memoryX(&sc->stat_mem);
2602116735Sharti#endif
2603116735Sharti
2604116735Sharti	if (sc->tx_tag != NULL)
2605116735Sharti		if (bus_dma_tag_destroy(sc->tx_tag))
2606116735Sharti			printf("tx DMA tag busy!\n");
2607116735Sharti
2608116735Sharti	if (sc->rbuf_tag != NULL)
2609116735Sharti		if (bus_dma_tag_destroy(sc->rbuf_tag))
2610116735Sharti			printf("rbuf DMA tag busy!\n");
2611116735Sharti
2612116735Sharti	if (sc->parent_dmat != NULL)
2613116735Sharti		if (bus_dma_tag_destroy(sc->parent_dmat))
2614116735Sharti			printf("parent DMA tag busy!\n");
2615116735Sharti
2616116735Sharti	if (sc->irqres != NULL)
2617116735Sharti		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irqres);
2618116735Sharti
2619116735Sharti	if (sc->memres != NULL)
2620116735Sharti		bus_release_resource(dev, SYS_RES_MEMORY,
2621116735Sharti		    sc->memid, sc->memres);
2622116735Sharti
2623116735Sharti	(void)sysctl_ctx_free(&sc->sysctl_ctx);
2624116735Sharti
2625116735Sharti	cv_destroy(&sc->cv_stat);
2626116735Sharti	cv_destroy(&sc->cv_regs);
2627116735Sharti
2628116735Sharti	mtx_destroy(&sc->mtx);
2629116735Sharti
2630147525Sharti	if_free(sc->ifp);
2631147525Sharti
2632116735Sharti	return (0);
2633116735Sharti}
2634116735Sharti
2635116735Sharti/*
2636116735Sharti * Sysctl handler
2637116735Sharti */
2638116735Shartistatic int
2639116735Shartifatm_sysctl_istats(SYSCTL_HANDLER_ARGS)
2640116735Sharti{
2641116735Sharti	struct fatm_softc *sc = arg1;
2642116735Sharti	u_long *ret;
2643116735Sharti	int error;
2644116735Sharti
2645116735Sharti	ret = malloc(sizeof(sc->istats), M_TEMP, M_WAITOK);
2646116735Sharti
2647116735Sharti	FATM_LOCK(sc);
2648116735Sharti	bcopy(&sc->istats, ret, sizeof(sc->istats));
2649116735Sharti	FATM_UNLOCK(sc);
2650116735Sharti
2651116735Sharti	error = SYSCTL_OUT(req, ret, sizeof(sc->istats));
2652116735Sharti	free(ret, M_TEMP);
2653116735Sharti
2654116735Sharti	return (error);
2655116735Sharti}
2656116735Sharti
2657116735Sharti/*
2658116735Sharti * Sysctl handler for card statistics
2659118168Sharti * This is disable because it destroys the PHY statistics.
2660116735Sharti */
2661116735Shartistatic int
2662116735Shartifatm_sysctl_stats(SYSCTL_HANDLER_ARGS)
2663116735Sharti{
2664116735Sharti	struct fatm_softc *sc = arg1;
2665116735Sharti	int error;
2666116735Sharti	const struct fatm_stats *s;
2667116735Sharti	u_long *ret;
2668116735Sharti	u_int i;
2669116735Sharti
2670116735Sharti	ret = malloc(sizeof(u_long) * FATM_NSTATS, M_TEMP, M_WAITOK);
2671116735Sharti
2672116735Sharti	FATM_LOCK(sc);
2673116735Sharti
2674116735Sharti	if ((error = fatm_getstat(sc)) == 0) {
2675116735Sharti		s = sc->sadi_mem.mem;
2676116735Sharti		i = 0;
2677116735Sharti		ret[i++] = s->phy_4b5b.crc_header_errors;
2678116735Sharti		ret[i++] = s->phy_4b5b.framing_errors;
2679116735Sharti		ret[i++] = s->phy_oc3.section_bip8_errors;
2680116735Sharti		ret[i++] = s->phy_oc3.path_bip8_errors;
2681116735Sharti		ret[i++] = s->phy_oc3.line_bip24_errors;
2682116735Sharti		ret[i++] = s->phy_oc3.line_febe_errors;
2683116735Sharti		ret[i++] = s->phy_oc3.path_febe_errors;
2684116735Sharti		ret[i++] = s->phy_oc3.corr_hcs_errors;
2685116735Sharti		ret[i++] = s->phy_oc3.ucorr_hcs_errors;
2686116735Sharti		ret[i++] = s->atm.cells_transmitted;
2687116735Sharti		ret[i++] = s->atm.cells_received;
2688116735Sharti		ret[i++] = s->atm.vpi_bad_range;
2689116735Sharti		ret[i++] = s->atm.vpi_no_conn;
2690116735Sharti		ret[i++] = s->atm.vci_bad_range;
2691116735Sharti		ret[i++] = s->atm.vci_no_conn;
2692116735Sharti		ret[i++] = s->aal0.cells_transmitted;
2693116735Sharti		ret[i++] = s->aal0.cells_received;
2694116735Sharti		ret[i++] = s->aal0.cells_dropped;
2695116735Sharti		ret[i++] = s->aal4.cells_transmitted;
2696116735Sharti		ret[i++] = s->aal4.cells_received;
2697116735Sharti		ret[i++] = s->aal4.cells_crc_errors;
2698116735Sharti		ret[i++] = s->aal4.cels_protocol_errors;
2699116735Sharti		ret[i++] = s->aal4.cells_dropped;
2700116735Sharti		ret[i++] = s->aal4.cspdus_transmitted;
2701116735Sharti		ret[i++] = s->aal4.cspdus_received;
2702116735Sharti		ret[i++] = s->aal4.cspdus_protocol_errors;
2703116735Sharti		ret[i++] = s->aal4.cspdus_dropped;
2704116735Sharti		ret[i++] = s->aal5.cells_transmitted;
2705116735Sharti		ret[i++] = s->aal5.cells_received;
2706116735Sharti		ret[i++] = s->aal5.congestion_experienced;
2707116735Sharti		ret[i++] = s->aal5.cells_dropped;
2708116735Sharti		ret[i++] = s->aal5.cspdus_transmitted;
2709116735Sharti		ret[i++] = s->aal5.cspdus_received;
2710116735Sharti		ret[i++] = s->aal5.cspdus_crc_errors;
2711116735Sharti		ret[i++] = s->aal5.cspdus_protocol_errors;
2712116735Sharti		ret[i++] = s->aal5.cspdus_dropped;
2713116735Sharti		ret[i++] = s->aux.small_b1_failed;
2714116735Sharti		ret[i++] = s->aux.large_b1_failed;
2715116735Sharti		ret[i++] = s->aux.small_b2_failed;
2716116735Sharti		ret[i++] = s->aux.large_b2_failed;
2717116735Sharti		ret[i++] = s->aux.rpd_alloc_failed;
2718116735Sharti		ret[i++] = s->aux.receive_carrier;
2719116735Sharti	}
2720116735Sharti	/* declare the buffer free */
2721116735Sharti	sc->flags &= ~FATM_STAT_INUSE;
2722116735Sharti	cv_signal(&sc->cv_stat);
2723116735Sharti
2724116735Sharti	FATM_UNLOCK(sc);
2725116735Sharti
2726116735Sharti	if (error == 0)
2727116735Sharti		error = SYSCTL_OUT(req, ret, sizeof(u_long) * FATM_NSTATS);
2728116735Sharti	free(ret, M_TEMP);
2729116735Sharti
2730116735Sharti	return (error);
2731116735Sharti}
2732116735Sharti
2733116735Sharti#define MAXDMASEGS 32		/* maximum number of receive descriptors */
2734116735Sharti
2735116735Sharti/*
2736116735Sharti * Attach to the device.
2737116735Sharti *
2738116735Sharti * We assume, that there is a global lock (Giant in this case) that protects
2739116735Sharti * multiple threads from entering this function. This makes sense, doesn't it?
2740116735Sharti */
2741116735Shartistatic int
2742116735Shartifatm_attach(device_t dev)
2743116735Sharti{
2744116735Sharti	struct ifnet *ifp;
2745116735Sharti	struct fatm_softc *sc;
2746116735Sharti	int unit;
2747116735Sharti	uint16_t cfg;
2748116735Sharti	int error = 0;
2749116735Sharti	struct rbuf *rb;
2750116735Sharti	u_int i;
2751116735Sharti	struct txqueue *tx;
2752116735Sharti
2753116735Sharti	sc = device_get_softc(dev);
2754116735Sharti	unit = device_get_unit(dev);
2755116735Sharti
2756147256Sbrooks	ifp = sc->ifp = if_alloc(IFT_ATM);
2757147256Sbrooks	if (ifp == NULL) {
2758147256Sbrooks		error = ENOSPC;
2759147256Sbrooks		goto fail;
2760147256Sbrooks	}
2761116735Sharti
2762147256Sbrooks	IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PCA200E;
2763147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial = 0;
2764147256Sbrooks	IFP2IFATM(sc->ifp)->mib.hw_version = 0;
2765147256Sbrooks	IFP2IFATM(sc->ifp)->mib.sw_version = 0;
2766147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vpi_bits = 0;
2767147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vci_bits = FORE_VCIBITS;
2768147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vpcs = 0;
2769147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vccs = FORE_MAX_VCC;
2770147256Sbrooks	IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
2771147256Sbrooks	IFP2IFATM(sc->ifp)->phy = &sc->utopia;
2772147256Sbrooks
2773116735Sharti	LIST_INIT(&sc->rbuf_free);
2774116735Sharti	LIST_INIT(&sc->rbuf_used);
2775116735Sharti
2776116735Sharti	/*
2777116735Sharti	 * Initialize mutex and condition variables.
2778116735Sharti	 */
2779116735Sharti	mtx_init(&sc->mtx, device_get_nameunit(dev),
2780116735Sharti	    MTX_NETWORK_LOCK, MTX_DEF);
2781116735Sharti
2782116735Sharti	cv_init(&sc->cv_stat, "fatm_stat");
2783116735Sharti	cv_init(&sc->cv_regs, "fatm_regs");
2784116735Sharti
2785116735Sharti	sysctl_ctx_init(&sc->sysctl_ctx);
2786199559Sjhb	callout_init_mtx(&sc->watchdog_timer, &sc->mtx, 0);
2787116735Sharti
2788116735Sharti	/*
2789116735Sharti	 * Make the sysctl tree
2790116735Sharti	 */
2791116735Sharti	if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
2792116735Sharti	    SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO,
2793116735Sharti	    device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL)
2794116735Sharti		goto fail;
2795116735Sharti
2796116735Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
2797217556Smdf	    OID_AUTO, "istats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0,
2798217556Smdf	    fatm_sysctl_istats, "LU", "internal statistics") == NULL)
2799116735Sharti		goto fail;
2800116735Sharti
2801116735Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
2802217556Smdf	    OID_AUTO, "stats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0,
2803217556Smdf	    fatm_sysctl_stats, "LU", "card statistics") == NULL)
2804116735Sharti		goto fail;
2805116735Sharti
2806116735Sharti	if (SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
2807116735Sharti	    OID_AUTO, "retry_tx", CTLFLAG_RW, &sc->retry_tx, 0,
2808116735Sharti	    "retry flag") == NULL)
2809116735Sharti		goto fail;
2810116735Sharti
2811116735Sharti#ifdef FATM_DEBUG
2812116735Sharti	if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
2813116735Sharti	    OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 0, "debug flags")
2814116735Sharti	    == NULL)
2815116735Sharti		goto fail;
2816116735Sharti	sc->debug = FATM_DEBUG;
2817116735Sharti#endif
2818116735Sharti
2819116735Sharti	/*
2820116735Sharti	 * Network subsystem stuff
2821116735Sharti	 */
2822116735Sharti	ifp->if_softc = sc;
2823121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2824116735Sharti	ifp->if_flags = IFF_SIMPLEX;
2825116735Sharti	ifp->if_ioctl = fatm_ioctl;
2826116735Sharti	ifp->if_start = fatm_start;
2827116735Sharti	ifp->if_init = fatm_init;
2828147256Sbrooks	ifp->if_linkmib = &IFP2IFATM(sc->ifp)->mib;
2829147256Sbrooks	ifp->if_linkmiblen = sizeof(IFP2IFATM(sc->ifp)->mib);
2830116735Sharti
2831116735Sharti	/*
2832254263Sscottl	 * Enable busmaster
2833116735Sharti	 */
2834254263Sscottl	pci_enable_busmaster(dev);
2835116735Sharti
2836116735Sharti	/*
2837116735Sharti	 * Map memory
2838116735Sharti	 */
2839116735Sharti	sc->memid = 0x10;
2840127135Snjl	sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->memid,
2841127135Snjl	    RF_ACTIVE);
2842116735Sharti	if (sc->memres == NULL) {
2843116735Sharti		if_printf(ifp, "could not map memory\n");
2844116735Sharti		error = ENXIO;
2845116735Sharti		goto fail;
2846116735Sharti	}
2847116735Sharti	sc->memh = rman_get_bushandle(sc->memres);
2848116735Sharti	sc->memt = rman_get_bustag(sc->memres);
2849116735Sharti
2850116735Sharti	/*
2851116735Sharti	 * Convert endianess of slave access
2852116735Sharti	 */
2853116735Sharti	cfg = pci_read_config(dev, FATM_PCIR_MCTL, 1);
2854116735Sharti	cfg |= FATM_PCIM_SWAB;
2855116735Sharti	pci_write_config(dev, FATM_PCIR_MCTL, cfg, 1);
2856116735Sharti
2857116735Sharti	/*
2858116735Sharti	 * Allocate interrupt (activate at the end)
2859116735Sharti	 */
2860116735Sharti	sc->irqid = 0;
2861127135Snjl	sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
2862127135Snjl	    RF_SHAREABLE | RF_ACTIVE);
2863116735Sharti	if (sc->irqres == NULL) {
2864116735Sharti		if_printf(ifp, "could not allocate irq\n");
2865116735Sharti		error = ENXIO;
2866116735Sharti		goto fail;
2867116735Sharti	}
2868116735Sharti
2869116735Sharti	/*
2870116735Sharti	 * Allocate the parent DMA tag. This is used simply to hold overall
2871116735Sharti	 * restrictions for the controller (and PCI bus) and is never used
2872116735Sharti	 * to do anything.
2873116735Sharti	 */
2874183504Smarius	if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
2875116735Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
2876117126Sscottl	    NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, MAXDMASEGS,
2877117164Sharti	    BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
2878117126Sscottl	    &sc->parent_dmat)) {
2879116735Sharti		if_printf(ifp, "could not allocate parent DMA tag\n");
2880116735Sharti		error = ENOMEM;
2881116735Sharti		goto fail;
2882116735Sharti	}
2883116735Sharti
2884116735Sharti	/*
2885116735Sharti	 * Allocate the receive buffer DMA tag. This tag must map a maximum of
2886116735Sharti	 * a mbuf cluster.
2887116735Sharti	 */
2888116735Sharti	if (bus_dma_tag_create(sc->parent_dmat, 1, 0,
2889116735Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
2890117126Sscottl	    NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
2891117164Sharti	    NULL, NULL, &sc->rbuf_tag)) {
2892116735Sharti		if_printf(ifp, "could not allocate rbuf DMA tag\n");
2893116735Sharti		error = ENOMEM;
2894116735Sharti		goto fail;
2895116735Sharti	}
2896116735Sharti
2897116735Sharti	/*
2898117164Sharti	 * Allocate the transmission DMA tag. Must add 1, because
2899117164Sharti	 * rounded up PDU will be 65536 bytes long.
2900116735Sharti	 */
2901116735Sharti	if (bus_dma_tag_create(sc->parent_dmat, 1, 0,
2902116735Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
2903116735Sharti	    NULL, NULL,
2904117164Sharti	    FATM_MAXPDU + 1, TPD_EXTENSIONS + TXD_FIXED, MCLBYTES, 0,
2905117164Sharti	    NULL, NULL, &sc->tx_tag)) {
2906116735Sharti		if_printf(ifp, "could not allocate tx DMA tag\n");
2907116735Sharti		error = ENOMEM;
2908116735Sharti		goto fail;
2909116735Sharti	}
2910116735Sharti
2911116735Sharti	/*
2912116735Sharti	 * Allocate DMAable memory.
2913116735Sharti	 */
2914116735Sharti	sc->stat_mem.size = sizeof(uint32_t) * (FATM_CMD_QLEN + FATM_TX_QLEN
2915116735Sharti	    + FATM_RX_QLEN + SMALL_SUPPLY_QLEN + LARGE_SUPPLY_QLEN);
2916116735Sharti	sc->stat_mem.align = 4;
2917116735Sharti
2918116735Sharti	sc->txq_mem.size = FATM_TX_QLEN * TPD_SIZE;
2919116735Sharti	sc->txq_mem.align = 32;
2920116735Sharti
2921116735Sharti	sc->rxq_mem.size = FATM_RX_QLEN * RPD_SIZE;
2922116735Sharti	sc->rxq_mem.align = 32;
2923116735Sharti
2924116735Sharti	sc->s1q_mem.size = SMALL_SUPPLY_QLEN *
2925116735Sharti	    BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE);
2926116735Sharti	sc->s1q_mem.align = 32;
2927116735Sharti
2928116735Sharti	sc->l1q_mem.size = LARGE_SUPPLY_QLEN *
2929116735Sharti	    BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE);
2930116735Sharti	sc->l1q_mem.align = 32;
2931116735Sharti
2932116735Sharti#ifdef TEST_DMA_SYNC
2933116735Sharti	if ((error = alloc_dma_memoryX(sc, "STATUS", &sc->stat_mem)) != 0 ||
2934116735Sharti	    (error = alloc_dma_memoryX(sc, "TXQ", &sc->txq_mem)) != 0 ||
2935116735Sharti	    (error = alloc_dma_memoryX(sc, "RXQ", &sc->rxq_mem)) != 0 ||
2936116735Sharti	    (error = alloc_dma_memoryX(sc, "S1Q", &sc->s1q_mem)) != 0 ||
2937116735Sharti	    (error = alloc_dma_memoryX(sc, "L1Q", &sc->l1q_mem)) != 0)
2938116735Sharti		goto fail;
2939116735Sharti#else
2940116735Sharti	if ((error = alloc_dma_memory(sc, "STATUS", &sc->stat_mem)) != 0 ||
2941116735Sharti	    (error = alloc_dma_memory(sc, "TXQ", &sc->txq_mem)) != 0 ||
2942116735Sharti	    (error = alloc_dma_memory(sc, "RXQ", &sc->rxq_mem)) != 0 ||
2943116735Sharti	    (error = alloc_dma_memory(sc, "S1Q", &sc->s1q_mem)) != 0 ||
2944116735Sharti	    (error = alloc_dma_memory(sc, "L1Q", &sc->l1q_mem)) != 0)
2945116735Sharti		goto fail;
2946116735Sharti#endif
2947116735Sharti
2948116735Sharti	sc->prom_mem.size = sizeof(struct prom);
2949116735Sharti	sc->prom_mem.align = 32;
2950116735Sharti	if ((error = alloc_dma_memory(sc, "PROM", &sc->prom_mem)) != 0)
2951116735Sharti		goto fail;
2952116735Sharti
2953116735Sharti	sc->sadi_mem.size = sizeof(struct fatm_stats);
2954116735Sharti	sc->sadi_mem.align = 32;
2955116735Sharti	if ((error = alloc_dma_memory(sc, "STATISTICS", &sc->sadi_mem)) != 0)
2956116735Sharti		goto fail;
2957116735Sharti
2958116735Sharti	sc->reg_mem.size = sizeof(uint32_t) * FATM_NREGS;
2959116735Sharti	sc->reg_mem.align = 32;
2960116735Sharti	if ((error = alloc_dma_memory(sc, "REGISTERS", &sc->reg_mem)) != 0)
2961116735Sharti		goto fail;
2962116735Sharti
2963116735Sharti	/*
2964116735Sharti	 * Allocate queues
2965116735Sharti	 */
2966116735Sharti	sc->cmdqueue.chunk = malloc(FATM_CMD_QLEN * sizeof(struct cmdqueue),
2967116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2968116735Sharti	sc->txqueue.chunk = malloc(FATM_TX_QLEN * sizeof(struct txqueue),
2969116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2970116735Sharti	sc->rxqueue.chunk = malloc(FATM_RX_QLEN * sizeof(struct rxqueue),
2971116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2972116735Sharti	sc->s1queue.chunk = malloc(SMALL_SUPPLY_QLEN * sizeof(struct supqueue),
2973116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2974116735Sharti	sc->l1queue.chunk = malloc(LARGE_SUPPLY_QLEN * sizeof(struct supqueue),
2975116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2976116735Sharti
2977118208Sharti	sc->vccs = malloc((FORE_MAX_VCC + 1) * sizeof(sc->vccs[0]),
2978116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2979118208Sharti	sc->vcc_zone = uma_zcreate("FATM vccs", sizeof(struct card_vcc),
2980118208Sharti	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
2981118208Sharti	if (sc->vcc_zone == NULL) {
2982118208Sharti		error = ENOMEM;
2983118208Sharti		goto fail;
2984118208Sharti	}
2985116735Sharti
2986116735Sharti	/*
2987116735Sharti	 * Allocate memory for the receive buffer headers. The total number
2988116735Sharti	 * of headers should probably also include the maximum number of
2989116735Sharti	 * buffers on the receive queue.
2990116735Sharti	 */
2991116735Sharti	sc->rbuf_total = SMALL_POOL_SIZE + LARGE_POOL_SIZE;
2992116735Sharti	sc->rbufs = malloc(sc->rbuf_total * sizeof(struct rbuf),
2993116735Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
2994116735Sharti
2995116735Sharti	/*
2996116735Sharti	 * Put all rbuf headers on the free list and create DMA maps.
2997116735Sharti	 */
2998116735Sharti	for (rb = sc->rbufs, i = 0; i < sc->rbuf_total; i++, rb++) {
2999116735Sharti		if ((error = bus_dmamap_create(sc->rbuf_tag, 0, &rb->map))) {
3000147256Sbrooks			if_printf(sc->ifp, "creating rx map: %d\n",
3001116735Sharti			    error);
3002116735Sharti			goto fail;
3003116735Sharti		}
3004116735Sharti		LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
3005116735Sharti	}
3006116735Sharti
3007116735Sharti	/*
3008116735Sharti	 * Create dma maps for transmission. In case of an error, free the
3009116735Sharti	 * allocated DMA maps, because on some architectures maps are NULL
3010116735Sharti	 * and we cannot distinguish between a failure and a NULL map in
3011116735Sharti	 * the detach routine.
3012116735Sharti	 */
3013116735Sharti	for (i = 0; i < FATM_TX_QLEN; i++) {
3014116735Sharti		tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
3015116735Sharti		if ((error = bus_dmamap_create(sc->tx_tag, 0, &tx->map))) {
3016147256Sbrooks			if_printf(sc->ifp, "creating tx map: %d\n",
3017116735Sharti			    error);
3018116735Sharti			while (i > 0) {
3019116735Sharti				tx = GET_QUEUE(sc->txqueue, struct txqueue,
3020116735Sharti				    i - 1);
3021116735Sharti				bus_dmamap_destroy(sc->tx_tag, tx->map);
3022116735Sharti				i--;
3023116735Sharti			}
3024116735Sharti			goto fail;
3025116735Sharti		}
3026116735Sharti	}
3027116735Sharti
3028147256Sbrooks	utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx,
3029116735Sharti	    &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
3030116735Sharti	    &fatm_utopia_methods);
3031116735Sharti	sc->utopia.flags |= UTP_FL_NORESET | UTP_FL_POLL_CARRIER;
3032116735Sharti
3033116735Sharti	/*
3034116735Sharti	 * Attach the interface
3035116735Sharti	 */
3036116735Sharti	atm_ifattach(ifp);
3037116735Sharti	ifp->if_snd.ifq_maxlen = 512;
3038116735Sharti
3039147525Sharti#ifdef ENABLE_BPF
3040147525Sharti	bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
3041147525Sharti#endif
3042147525Sharti
3043156950Sharti	error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET | INTR_MPSAFE,
3044166901Spiso	    NULL, fatm_intr, sc, &sc->ih);
3045116735Sharti	if (error) {
3046116735Sharti		if_printf(ifp, "couldn't setup irq\n");
3047116735Sharti		goto fail;
3048116735Sharti	}
3049116735Sharti
3050116735Sharti  fail:
3051116735Sharti	if (error)
3052116735Sharti		fatm_detach(dev);
3053116735Sharti
3054116735Sharti	return (error);
3055116735Sharti}
3056116735Sharti
3057116735Sharti#if defined(FATM_DEBUG) && 0
3058116735Shartistatic void
3059116735Shartidump_s1_queue(struct fatm_softc *sc)
3060116735Sharti{
3061116735Sharti	int i;
3062116735Sharti	struct supqueue *q;
3063116735Sharti
3064116735Sharti	for(i = 0; i < SMALL_SUPPLY_QLEN; i++) {
3065116735Sharti		q = GET_QUEUE(sc->s1queue, struct supqueue, i);
3066116735Sharti		printf("%2d: card=%x(%x,%x) stat=%x\n", i,
3067116735Sharti		    q->q.card,
3068116735Sharti		    READ4(sc, q->q.card),
3069116735Sharti		    READ4(sc, q->q.card + 4),
3070116735Sharti		    *q->q.statp);
3071116735Sharti	}
3072116735Sharti}
3073116735Sharti#endif
3074116735Sharti
3075116735Sharti/*
3076116735Sharti * Driver infrastructure.
3077116735Sharti */
3078116735Shartistatic device_method_t fatm_methods[] = {
3079116735Sharti	DEVMETHOD(device_probe,		fatm_probe),
3080116735Sharti	DEVMETHOD(device_attach,	fatm_attach),
3081116735Sharti	DEVMETHOD(device_detach,	fatm_detach),
3082116735Sharti	{ 0, 0 }
3083116735Sharti};
3084116735Shartistatic driver_t fatm_driver = {
3085116735Sharti	"fatm",
3086116735Sharti	fatm_methods,
3087116735Sharti	sizeof(struct fatm_softc),
3088116735Sharti};
3089116735Sharti
3090116735ShartiDRIVER_MODULE(fatm, pci, fatm_driver, fatm_devclass, 0, 0);
3091