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