1139749Simp/*-
2117632Sharti * Copyright (c) 2003
3117632Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4117632Sharti * 	All rights reserved.
5117632Sharti *
6117632Sharti * Redistribution and use in source and binary forms, with or without
7117632Sharti * modification, are permitted provided that the following conditions
8117632Sharti * are met:
9117632Sharti * 1. Redistributions of source code must retain the above copyright
10117632Sharti *    notice, this list of conditions and the following disclaimer.
11117632Sharti * 2. Redistributions in binary form must reproduce the above copyright
12117632Sharti *    notice, this list of conditions and the following disclaimer in the
13117632Sharti *    documentation and/or other materials provided with the distribution.
14117632Sharti *
15117632Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18117632Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25117632Sharti * SUCH DAMAGE.
26117632Sharti *
27117632Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28117632Sharti *
29117632Sharti * Driver for IDT77252 based cards like ProSum's.
30117632Sharti */
31119418Sobrien
32117632Sharti#include <sys/cdefs.h>
33117632Sharti__FBSDID("$FreeBSD$");
34117632Sharti
35117632Sharti#include "opt_inet.h"
36117632Sharti#include "opt_natm.h"
37117632Sharti
38117632Sharti#include <sys/types.h>
39117632Sharti#include <sys/param.h>
40117632Sharti#include <sys/systm.h>
41117632Sharti#include <sys/malloc.h>
42117632Sharti#include <sys/kernel.h>
43117632Sharti#include <sys/bus.h>
44117632Sharti#include <sys/errno.h>
45117632Sharti#include <sys/conf.h>
46117632Sharti#include <sys/module.h>
47117632Sharti#include <sys/lock.h>
48117632Sharti#include <sys/mutex.h>
49117632Sharti#include <sys/sysctl.h>
50117632Sharti#include <sys/queue.h>
51117632Sharti#include <sys/condvar.h>
52117632Sharti#include <sys/endian.h>
53117632Sharti#include <vm/uma.h>
54117632Sharti
55117632Sharti#include <sys/sockio.h>
56117632Sharti#include <sys/mbuf.h>
57117632Sharti#include <sys/socket.h>
58117632Sharti
59117632Sharti#include <net/if.h>
60117632Sharti#include <net/if_media.h>
61117632Sharti#include <net/if_atm.h>
62117632Sharti#include <net/route.h>
63117632Sharti#include <netinet/in.h>
64117632Sharti#include <netinet/if_atm.h>
65117632Sharti
66117632Sharti#include <machine/bus.h>
67117632Sharti#include <machine/resource.h>
68117632Sharti#include <sys/bus.h>
69117632Sharti#include <sys/rman.h>
70117632Sharti#include <sys/mbpool.h>
71117632Sharti
72117632Sharti#include <dev/utopia/utopia.h>
73117632Sharti#include <dev/patm/idt77252reg.h>
74117632Sharti#include <dev/patm/if_patmvar.h>
75117632Sharti
76117632Shartistatic void patm_feed_sbufs(struct patm_softc *sc);
77117632Shartistatic void patm_feed_lbufs(struct patm_softc *sc);
78117632Shartistatic void patm_feed_vbufs(struct patm_softc *sc);
79117632Shartistatic void patm_intr_tsif(struct patm_softc *sc);
80117632Shartistatic void patm_intr_raw(struct patm_softc *sc);
81117632Sharti
82117632Sharti#ifdef PATM_DEBUG
83117632Shartistatic int patm_mbuf_cnt(u_int unit) __unused;
84117632Sharti#endif
85117632Sharti
86117632Sharti/*
87117632Sharti * Write free buf Q
88117632Sharti */
89117632Shartistatic __inline void
90117632Shartipatm_fbq_write(struct patm_softc *sc, u_int queue, uint32_t h0,
91117632Sharti    uint32_t p0, uint32_t h1, uint32_t p1)
92117632Sharti{
93117632Sharti	patm_debug(sc, FREEQ, "supplying(%u,%#x,%#x,%#x,%#x)",
94117632Sharti	    queue, h0, p0, h1, p1);
95117632Sharti	patm_nor_write(sc, IDT_NOR_D0, h0);
96117632Sharti	patm_nor_write(sc, IDT_NOR_D1, p0);
97117632Sharti	patm_nor_write(sc, IDT_NOR_D2, h1);
98117632Sharti	patm_nor_write(sc, IDT_NOR_D3, p1);
99117632Sharti	patm_cmd_exec(sc, IDT_CMD_WFBQ | queue);
100117632Sharti}
101117632Sharti
102117632Sharti/*
103117632Sharti * Interrupt
104117632Sharti */
105117632Shartivoid
106117632Shartipatm_intr(void *p)
107117632Sharti{
108117632Sharti	struct patm_softc *sc = p;
109117632Sharti	uint32_t stat, cfg;
110117632Sharti	u_int cnt;
111117632Sharti	const uint32_t ints = IDT_STAT_TSIF | IDT_STAT_TXICP | IDT_STAT_TSQF |
112117632Sharti	    IDT_STAT_TMROF | IDT_STAT_PHYI | IDT_STAT_RSQF | IDT_STAT_EPDU |
113117632Sharti	    IDT_STAT_RAWCF | IDT_STAT_RSQAF;
114117632Sharti	const uint32_t fbqa = IDT_STAT_FBQ3A | IDT_STAT_FBQ2A |
115117632Sharti	    IDT_STAT_FBQ1A | IDT_STAT_FBQ0A;
116117632Sharti
117117632Sharti	mtx_lock(&sc->mtx);
118117632Sharti
119117632Sharti	stat = patm_nor_read(sc, IDT_NOR_STAT);
120117632Sharti	patm_nor_write(sc, IDT_NOR_STAT, stat & (ints | fbqa));
121117632Sharti
122148887Srwatson	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
123117632Sharti		/* if we are stopped ack all interrupts and handle PHYI */
124117632Sharti		if (stat & IDT_STAT_PHYI) {
125117632Sharti			patm_debug(sc, INTR, "PHYI (stopped)");
126117632Sharti			utopia_intr(&sc->utopia);
127117632Sharti		}
128117632Sharti		mtx_unlock(&sc->mtx);
129117632Sharti		return;
130117632Sharti	}
131117632Sharti
132117632Sharti	patm_debug(sc, INTR, "stat=%08x", stat);
133117632Sharti
134117632Sharti	/*
135117632Sharti	 * If the buffer queues are empty try to fill them. If this fails
136117632Sharti	 * disable the interrupt. Otherwise enable the interrupt.
137117632Sharti	 */
138117632Sharti	if (stat & fbqa) {
139117632Sharti		cfg = patm_nor_read(sc, IDT_NOR_CFG);
140117632Sharti		if (stat & IDT_STAT_FBQ0A)
141117632Sharti			patm_feed_sbufs(sc);
142117632Sharti		if (stat & IDT_STAT_FBQ1A)
143117632Sharti			patm_feed_lbufs(sc);
144117632Sharti		if (stat & IDT_STAT_FBQ2A) {
145117632Sharti			/*
146117632Sharti			 * Workaround for missing interrupt on AAL0. Check the
147117632Sharti			 * receive status queue if the FBQ2 is not full.
148117632Sharti			 */
149117632Sharti			patm_intr_rsq(sc);
150117632Sharti			patm_feed_vbufs(sc);
151117632Sharti		}
152117632Sharti		if ((patm_nor_read(sc, IDT_NOR_STAT) & fbqa) &&
153117632Sharti		    (cfg & IDT_CFG_FBIE)) {
154117632Sharti			/* failed */
155117632Sharti			patm_nor_write(sc, IDT_NOR_CFG, cfg & ~IDT_CFG_FBIE);
156117632Sharti			patm_printf(sc, "out of buffers -- intr disabled\n");
157117632Sharti		} else if (!(cfg & IDT_CFG_FBIE)) {
158117632Sharti			patm_printf(sc, "bufQ intr re-enabled\n");
159117632Sharti			patm_nor_write(sc, IDT_NOR_CFG, cfg | IDT_CFG_FBIE);
160117632Sharti		}
161117632Sharti		patm_nor_write(sc, IDT_NOR_STAT, fbqa);
162117632Sharti	}
163117632Sharti
164117632Sharti	cnt = 0;
165117632Sharti	while ((stat & ints) != 0) {
166117632Sharti		if (++cnt == 200) {
167117632Sharti			patm_printf(sc, "%s: excessive interrupts\n", __func__);
168117632Sharti			patm_stop(sc);
169117632Sharti			break;
170117632Sharti		}
171117632Sharti		if (stat & IDT_STAT_TSIF) {
172117632Sharti			patm_debug(sc, INTR, "TSIF");
173117632Sharti			patm_intr_tsif(sc);
174117632Sharti		}
175117632Sharti		if (stat & IDT_STAT_TXICP) {
176117632Sharti			patm_printf(sc, "incomplete PDU transmitted\n");
177117632Sharti		}
178117632Sharti		if (stat & IDT_STAT_TSQF) {
179117632Sharti			patm_printf(sc, "TSQF\n");
180117632Sharti			patm_intr_tsif(sc);
181117632Sharti		}
182117632Sharti		if (stat & IDT_STAT_TMROF) {
183117632Sharti			patm_debug(sc, INTR, "TMROF");
184117632Sharti			patm_intr_tsif(sc);
185117632Sharti		}
186117632Sharti		if (stat & IDT_STAT_PHYI) {
187117632Sharti			patm_debug(sc, INTR, "PHYI");
188117632Sharti			utopia_intr(&sc->utopia);
189117632Sharti		}
190117632Sharti		if (stat & IDT_STAT_RSQF) {
191117632Sharti			patm_printf(sc, "RSQF\n");
192117632Sharti			patm_intr_rsq(sc);
193117632Sharti		}
194117632Sharti		if (stat & IDT_STAT_EPDU) {
195117632Sharti			patm_debug(sc, INTR, "EPDU");
196117632Sharti			patm_intr_rsq(sc);
197117632Sharti		}
198117632Sharti		if (stat & IDT_STAT_RAWCF) {
199117632Sharti			patm_debug(sc, INTR, "RAWCF");
200117632Sharti			patm_intr_raw(sc);
201117632Sharti		}
202117632Sharti		if (stat & IDT_STAT_RSQAF) {
203117632Sharti			patm_debug(sc, INTR, "RSQAF");
204117632Sharti			patm_intr_rsq(sc);
205117632Sharti		} else if (IDT_STAT_FRAC2(stat) != 0xf) {
206117632Sharti			/*
207117632Sharti			 * Workaround for missing interrupt on AAL0. Check the
208117632Sharti			 * receive status queue if the FBQ2 is not full.
209117632Sharti			 */
210117632Sharti			patm_intr_rsq(sc);
211117632Sharti		}
212117632Sharti
213117632Sharti		stat = patm_nor_read(sc, IDT_NOR_STAT);
214117632Sharti		patm_nor_write(sc, IDT_NOR_STAT, ints & stat);
215117632Sharti		patm_debug(sc, INTR, "stat=%08x", stat);
216117632Sharti	}
217117632Sharti
218117632Sharti	mtx_unlock(&sc->mtx);
219117632Sharti
220117632Sharti	patm_debug(sc, INTR, "... exit");
221117632Sharti}
222117632Sharti
223117632Sharti/*
224117632Sharti * Compute the amount of buffers to feed into a given free buffer queue
225117632Sharti *
226117632Sharti * Feeding buffers is actually not so easy as it seems. We cannot use the
227117632Sharti * fraction fields in the status registers, because they round down, i.e.
228117632Sharti * if we have 34 buffers in the queue, it will show 1. If we now feed
229160964Syar * 512 - 1 * 32 buffers, we lose two buffers. The only reliable way to know
230117632Sharti * how many buffers are in the queue are the FBQP registers.
231117632Sharti */
232117632Shartistatic u_int
233117632Shartipatm_feed_cnt(struct patm_softc *sc, u_int q)
234117632Sharti{
235117632Sharti	u_int w, r, reg;
236117632Sharti	u_int feed;
237117632Sharti	int free;
238117632Sharti
239117632Sharti	/* get the FBQ read and write pointers */
240117632Sharti	reg = patm_nor_read(sc, IDT_NOR_FBQP0 + 4 * q);
241117632Sharti	r = (reg & 0x7ff) >> 1;
242117632Sharti	w = ((reg >> 16) & 0x7ff) >> 1;
243117632Sharti	/* compute amount of free buffers */
244117632Sharti	if ((free = w - r) < 0)
245117632Sharti		free += 0x400;
246117632Sharti	KASSERT(free <= 512, ("bad FBQP 0x%x", reg));
247117632Sharti	feed = 512 - free;
248117632Sharti
249117632Sharti	/* can only feed pairs of buffers */
250117632Sharti	feed &= ~1;
251117632Sharti
252117632Sharti	if (feed > 0)
253117632Sharti		feed -= 2;
254117632Sharti
255117632Sharti	patm_debug(sc, FREEQ, "feeding %u buffers into queue %u", feed, q);
256117632Sharti
257117632Sharti	return (feed);
258117632Sharti}
259117632Sharti
260117632Sharti/*
261117632Sharti * Feed small buffers into buffer queue 0
262117632Sharti *
263117632Sharti */
264117632Shartistatic void
265117632Shartipatm_feed_sbufs(struct patm_softc *sc)
266117632Sharti{
267117632Sharti	u_int feed;
268117632Sharti	bus_addr_t p0, p1;
269185336Sganbold	void *v0;
270117632Sharti	uint32_t h0, h1;
271117632Sharti
272117632Sharti	feed = patm_feed_cnt(sc, 0);
273117632Sharti
274117632Sharti	while (feed > 0) {
275117632Sharti		if ((v0 = mbp_alloc(sc->sbuf_pool, &p0, &h0)) == NULL)
276117632Sharti			break;
277185336Sganbold		if (mbp_alloc(sc->sbuf_pool, &p1, &h1) == NULL) {
278117632Sharti			mbp_free(sc->sbuf_pool, v0);
279117632Sharti			break;
280117632Sharti		}
281117632Sharti		patm_fbq_write(sc, 0,
282117632Sharti		    h0 | MBUF_SHANDLE, (p0 + SMBUF_OFFSET),
283117632Sharti		    h1 | MBUF_SHANDLE, (p1 + SMBUF_OFFSET));
284117632Sharti
285117632Sharti		feed -= 2;
286117632Sharti	}
287117632Sharti}
288117632Sharti
289117632Sharti/*
290117632Sharti * Feed small buffers into buffer queue 0
291117632Sharti */
292117632Shartistatic void
293117632Shartipatm_feed_vbufs(struct patm_softc *sc)
294117632Sharti{
295117632Sharti	u_int feed;
296117632Sharti	bus_addr_t p0, p1;
297185336Sganbold	void *v0;
298117632Sharti	uint32_t h0, h1;
299117632Sharti
300117632Sharti	feed = patm_feed_cnt(sc, 2);
301117632Sharti
302117632Sharti	while (feed > 0) {
303117632Sharti		if ((v0 = mbp_alloc(sc->vbuf_pool, &p0, &h0)) == NULL)
304117632Sharti			break;
305185336Sganbold		if (mbp_alloc(sc->vbuf_pool, &p1, &h1) == NULL) {
306117632Sharti			mbp_free(sc->vbuf_pool, v0);
307117632Sharti			break;
308117632Sharti		}
309117632Sharti		patm_fbq_write(sc, 2,
310117632Sharti		    h0 | MBUF_VHANDLE, (p0 + VMBUF_OFFSET),
311117632Sharti		    h1 | MBUF_VHANDLE, (p1 + VMBUF_OFFSET));
312117632Sharti
313117632Sharti		feed -= 2;
314117632Sharti	}
315117632Sharti}
316117632Sharti
317117632Sharti/*
318117632Sharti * Allocate a large buffer
319117632Sharti */
320117632Shartistatic struct lmbuf *
321117632Shartipatm_lmbuf_alloc(struct patm_softc *sc)
322117632Sharti{
323117632Sharti	int error;
324117632Sharti	struct mbuf *m;
325117632Sharti	struct lmbuf *b;
326117632Sharti
327248078Smarius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
328117632Sharti	if (m == NULL)
329117632Sharti		return (NULL);
330117632Sharti	m->m_data += LMBUF_OFFSET;
331117632Sharti
332117632Sharti	if ((b = SLIST_FIRST(&sc->lbuf_free_list)) == NULL) {
333117632Sharti		m_freem(m);
334117632Sharti		return (NULL);
335117632Sharti	}
336117632Sharti
337117632Sharti	b->phy = 0;		/* alignment */
338117632Sharti	error = bus_dmamap_load(sc->lbuf_tag, b->map, m->m_data, LMBUF_SIZE,
339117632Sharti	    patm_load_callback, &b->phy, BUS_DMA_NOWAIT);
340117632Sharti	if (error) {
341117632Sharti		patm_printf(sc, "%s -- bus_dmamap_load: %d\n", __func__, error);
342117632Sharti		m_free(m);
343117632Sharti		return (NULL);
344117632Sharti	}
345117632Sharti
346117632Sharti	SLIST_REMOVE_HEAD(&sc->lbuf_free_list, link);
347117632Sharti	b->m = m;
348117632Sharti
349117632Sharti	return (b);
350117632Sharti}
351117632Sharti
352117632Sharti/*
353117632Sharti * Feed large buffers into buffer queue 1
354117632Sharti */
355117632Shartistatic void
356117632Shartipatm_feed_lbufs(struct patm_softc *sc)
357117632Sharti{
358117632Sharti	u_int feed;
359117632Sharti	struct lmbuf *b0, *b1;
360117632Sharti
361117632Sharti	feed = patm_feed_cnt(sc, 1);
362117632Sharti
363117632Sharti	while (feed > 0) {
364117632Sharti		if ((b0 = patm_lmbuf_alloc(sc)) == NULL)
365117632Sharti			break;
366117632Sharti		if ((b1 = patm_lmbuf_alloc(sc)) == NULL) {
367117632Sharti			patm_lbuf_free(sc, b0);
368117632Sharti			break;
369117632Sharti		}
370117632Sharti		patm_fbq_write(sc, 1,
371117632Sharti		    LMBUF_HANDLE | b0->handle, b0->phy,
372117632Sharti		    LMBUF_HANDLE | b1->handle, b1->phy);
373117632Sharti
374117632Sharti		feed -= 2;
375117632Sharti	}
376117632Sharti}
377117632Sharti
378117632Sharti/*
379117632Sharti * Handle transmit status interrupt
380117632Sharti */
381117632Shartistatic void
382117632Shartipatm_intr_tsif(struct patm_softc *sc)
383117632Sharti{
384201758Smbr	struct idt_tsqe *tsqe = sc->tsq_next;
385117632Sharti	struct idt_tsqe *prev = NULL;
386117632Sharti	uint32_t stamp;
387117632Sharti
388117632Sharti	stamp = le32toh(tsqe->stamp);
389117632Sharti	if (stamp & IDT_TSQE_EMPTY)
390117632Sharti		return;
391117632Sharti
392117632Sharti	do {
393117632Sharti		switch (IDT_TSQE_TYPE(stamp)) {
394117632Sharti
395117632Sharti		  case IDT_TSQE_TBD:
396117632Sharti			patm_tx(sc, stamp, le32toh(tsqe->stat));
397117632Sharti			break;
398117632Sharti
399117632Sharti		  case IDT_TSQE_IDLE:
400117632Sharti			patm_tx_idle(sc, le32toh(tsqe->stat));
401117632Sharti			break;
402117632Sharti		}
403117632Sharti
404117632Sharti		/* recycle */
405117632Sharti		tsqe->stat = 0;
406117632Sharti		tsqe->stamp = htole32(IDT_TSQE_EMPTY);
407117632Sharti
408117632Sharti		/* save pointer to this entry and advance */
409117632Sharti		prev = tsqe;
410117632Sharti		if (++tsqe == &sc->tsq[IDT_TSQ_SIZE])
411117632Sharti			tsqe = &sc->tsq[0];
412117632Sharti
413117632Sharti		stamp = le32toh(tsqe->stamp);
414117632Sharti	} while (!(stamp & IDT_TSQE_EMPTY));
415117632Sharti
416117632Sharti	sc->tsq_next = tsqe;
417117632Sharti	patm_nor_write(sc, IDT_NOR_TSQH, ((prev - sc->tsq) << IDT_TSQE_SHIFT));
418117632Sharti}
419117632Sharti
420117632Sharti/*
421117632Sharti * Handle receive interrupt
422117632Sharti */
423117632Shartivoid
424117632Shartipatm_intr_rsq(struct patm_softc *sc)
425117632Sharti{
426117632Sharti	struct idt_rsqe *rsqe;
427117632Sharti	u_int stat;
428117632Sharti
429117632Sharti	if (sc->rsq_last + 1 == PATM_RSQ_SIZE)
430117632Sharti		rsqe = &sc->rsq[0];
431117632Sharti	else
432117632Sharti		rsqe = &sc->rsq[sc->rsq_last + 1];
433117632Sharti	stat = le32toh(rsqe->stat);
434117632Sharti	if (!(stat & IDT_RSQE_VALID))
435117632Sharti		return;
436117632Sharti
437117632Sharti	while (stat & IDT_RSQE_VALID) {
438117632Sharti		patm_rx(sc, rsqe);
439117632Sharti
440117632Sharti		/* recycle RSQE */
441117632Sharti		rsqe->cid = 0;
442117632Sharti		rsqe->handle = 0;
443117632Sharti		rsqe->crc = 0;
444117632Sharti		rsqe->stat = 0;
445117632Sharti
446117632Sharti		/* save pointer to this entry and advance */
447117632Sharti		if (++sc->rsq_last == PATM_RSQ_SIZE)
448117632Sharti			sc->rsq_last = 0;
449117632Sharti		if (++rsqe == &sc->rsq[PATM_RSQ_SIZE])
450117632Sharti			rsqe = sc->rsq;
451117632Sharti
452117632Sharti		stat = le32toh(rsqe->stat);
453117632Sharti	}
454117632Sharti
455117632Sharti	patm_nor_write(sc, IDT_NOR_RSQH, sc->rsq_phy | (sc->rsq_last << 2));
456117632Sharti
457117632Sharti	patm_feed_sbufs(sc);
458117632Sharti	patm_feed_lbufs(sc);
459117632Sharti	patm_feed_vbufs(sc);
460117632Sharti}
461117632Sharti
462117632Sharti/*
463117632Sharti * Handle raw cell receive.
464117632Sharti *
465117632Sharti * Note that the description on page 3-8 is wrong. The RAWHND contains not
466117632Sharti * the same value as RAWCT. RAWCT points to the next address the chip is
467117632Sharti * going to write to whike RAWHND points to the last cell's address the chip
468117632Sharti * has written to.
469117632Sharti */
470117632Shartistatic void
471117632Shartipatm_intr_raw(struct patm_softc *sc)
472117632Sharti{
473117632Sharti	uint32_t tail;
474117632Sharti	uint32_t h, *cell;
475117632Sharti
476117632Sharti#ifdef notyet
477117632Sharti	bus_dma_sync_size(sc->sq_tag, sc->sq_map, IDT_TSQ_SIZE * IDT_TSQE_SIZE +
478117632Sharti	    PATM_RSQ_SIZE * IDT_RSQE_SIZE, sizeof(*sc->rawhnd),
479117632Sharti	    BUS_DMASYNC_POSTREAD);
480117632Sharti#endif
481117632Sharti	/* first turn */
482117632Sharti	if (sc->rawh == NULL) {
483117632Sharti		sc->rawh = &sc->lbufs[le32toh(sc->rawhnd->handle) & MBUF_HMASK];
484117632Sharti	}
485117632Sharti	tail = le32toh(sc->rawhnd->tail);
486117632Sharti	if (tail == sc->rawh->phy)
487117632Sharti		/* not really a raw interrupt */
488117632Sharti		return;
489117632Sharti
490117632Sharti	while (tail + 64 != sc->rawh->phy + sc->rawi * 64) {
491117632Sharti#ifdef notyet
492117632Sharti		bus_dmamap_sync_size(sc->lbuf_tag, sc->rawh->map,
493117632Sharti		    sc->rawi * 64, 64, BUS_DMASYNC_POSTREAD);
494117632Sharti#endif
495117632Sharti		cell = (uint32_t *)(mtod(sc->rawh->m, u_char *) +
496117632Sharti		    sc->rawi * 64);
497117632Sharti		if (sc->rawi == (LMBUF_SIZE / 64) - 1) {
498117632Sharti			/* chain */
499117632Sharti			h = le32toh(cell[1]);
500117632Sharti			patm_lbuf_free(sc, sc->rawh);
501117632Sharti			sc->rawh = &sc->lbufs[h & MBUF_HMASK];
502117632Sharti			sc->rawi = 0;
503117632Sharti			continue;
504117632Sharti		}
505117632Sharti
506117632Sharti		patm_rx_raw(sc, (u_char *)cell);
507117632Sharti		sc->rawi++;
508117632Sharti	}
509117632Sharti}
510117632Sharti
511117632Sharti/*
512117632Sharti * Free a large mbuf. This is called by us.
513117632Sharti */
514117632Shartivoid
515117632Shartipatm_lbuf_free(struct patm_softc *sc, struct lmbuf *b)
516117632Sharti{
517117632Sharti
518117632Sharti	bus_dmamap_unload(sc->lbuf_tag, b->map);
519117632Sharti	if (b->m != NULL) {
520117632Sharti		m_free(b->m);
521117632Sharti		b->m = NULL;
522117632Sharti	}
523117632Sharti	SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
524117632Sharti}
525117632Sharti
526117632Sharti#ifdef PATM_DEBUG
527117632Shartistatic int
528117632Shartipatm_mbuf_cnt(u_int unit)
529117632Sharti{
530117632Sharti	devclass_t dc;
531117632Sharti	struct patm_softc *sc;
532117632Sharti	u_int used, card, free;
533117632Sharti
534117632Sharti	dc = devclass_find("patm");
535117632Sharti	if (dc == NULL) {
536117632Sharti		printf("%s: can't find devclass\n", __func__);
537117632Sharti		return (0);
538117632Sharti	}
539117632Sharti	sc = devclass_get_softc(dc, unit);
540117632Sharti	if (sc == NULL) {
541117632Sharti		printf("%s: invalid unit number: %d\n", __func__, unit);
542117632Sharti		return (0);
543117632Sharti	}
544117632Sharti
545117632Sharti	mbp_count(sc->sbuf_pool, &used, &card, &free);
546117632Sharti	printf("sbufs: %u on card, %u used, %u free\n", card, used, free);
547117632Sharti
548117632Sharti	mbp_count(sc->vbuf_pool, &used, &card, &free);
549117632Sharti	printf("aal0 bufs: %u on card, %u used, %u free\n", card, used, free);
550117632Sharti
551117632Sharti	return (0);
552117632Sharti}
553117632Sharti#endif
554