3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Author: Hartmut Brandt <harti@freebsd.org>
29 * Driver for IDT77252 based cards like ProSum's.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/kernel.h>
44 #include <sys/errno.h>
46 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/sysctl.h>
50 #include <sys/queue.h>
51 #include <sys/condvar.h>
52 #include <sys/endian.h>
55 #include <sys/sockio.h>
57 #include <sys/socket.h>
60 #include <net/if_var.h>
61 #include <net/if_media.h>
62 #include <net/if_atm.h>
63 #include <net/route.h>
64 #include <netinet/in.h>
65 #include <netinet/if_atm.h>
67 #include <machine/bus.h>
68 #include <machine/resource.h>
71 #include <sys/mbpool.h>
73 #include <dev/utopia/utopia.h>
74 #include <dev/patm/idt77252reg.h>
75 #include <dev/patm/if_patmvar.h>
77 static void patm_feed_sbufs(struct patm_softc *sc);
78 static void patm_feed_lbufs(struct patm_softc *sc);
79 static void patm_feed_vbufs(struct patm_softc *sc);
80 static void patm_intr_tsif(struct patm_softc *sc);
81 static void patm_intr_raw(struct patm_softc *sc);
84 static int patm_mbuf_cnt(u_int unit) __unused;
91 patm_fbq_write(struct patm_softc *sc, u_int queue, uint32_t h0,
92 uint32_t p0, uint32_t h1, uint32_t p1)
94 patm_debug(sc, FREEQ, "supplying(%u,%#x,%#x,%#x,%#x)",
95 queue, h0, p0, h1, p1);
96 patm_nor_write(sc, IDT_NOR_D0, h0);
97 patm_nor_write(sc, IDT_NOR_D1, p0);
98 patm_nor_write(sc, IDT_NOR_D2, h1);
99 patm_nor_write(sc, IDT_NOR_D3, p1);
100 patm_cmd_exec(sc, IDT_CMD_WFBQ | queue);
109 struct patm_softc *sc = p;
112 const uint32_t ints = IDT_STAT_TSIF | IDT_STAT_TXICP | IDT_STAT_TSQF |
113 IDT_STAT_TMROF | IDT_STAT_PHYI | IDT_STAT_RSQF | IDT_STAT_EPDU |
114 IDT_STAT_RAWCF | IDT_STAT_RSQAF;
115 const uint32_t fbqa = IDT_STAT_FBQ3A | IDT_STAT_FBQ2A |
116 IDT_STAT_FBQ1A | IDT_STAT_FBQ0A;
120 stat = patm_nor_read(sc, IDT_NOR_STAT);
121 patm_nor_write(sc, IDT_NOR_STAT, stat & (ints | fbqa));
123 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
124 /* if we are stopped ack all interrupts and handle PHYI */
125 if (stat & IDT_STAT_PHYI) {
126 patm_debug(sc, INTR, "PHYI (stopped)");
127 utopia_intr(&sc->utopia);
129 mtx_unlock(&sc->mtx);
133 patm_debug(sc, INTR, "stat=%08x", stat);
136 * If the buffer queues are empty try to fill them. If this fails
137 * disable the interrupt. Otherwise enable the interrupt.
140 cfg = patm_nor_read(sc, IDT_NOR_CFG);
141 if (stat & IDT_STAT_FBQ0A)
143 if (stat & IDT_STAT_FBQ1A)
145 if (stat & IDT_STAT_FBQ2A) {
147 * Workaround for missing interrupt on AAL0. Check the
148 * receive status queue if the FBQ2 is not full.
153 if ((patm_nor_read(sc, IDT_NOR_STAT) & fbqa) &&
154 (cfg & IDT_CFG_FBIE)) {
156 patm_nor_write(sc, IDT_NOR_CFG, cfg & ~IDT_CFG_FBIE);
157 patm_printf(sc, "out of buffers -- intr disabled\n");
158 } else if (!(cfg & IDT_CFG_FBIE)) {
159 patm_printf(sc, "bufQ intr re-enabled\n");
160 patm_nor_write(sc, IDT_NOR_CFG, cfg | IDT_CFG_FBIE);
162 patm_nor_write(sc, IDT_NOR_STAT, fbqa);
166 while ((stat & ints) != 0) {
168 patm_printf(sc, "%s: excessive interrupts\n", __func__);
172 if (stat & IDT_STAT_TSIF) {
173 patm_debug(sc, INTR, "TSIF");
176 if (stat & IDT_STAT_TXICP) {
177 patm_printf(sc, "incomplete PDU transmitted\n");
179 if (stat & IDT_STAT_TSQF) {
180 patm_printf(sc, "TSQF\n");
183 if (stat & IDT_STAT_TMROF) {
184 patm_debug(sc, INTR, "TMROF");
187 if (stat & IDT_STAT_PHYI) {
188 patm_debug(sc, INTR, "PHYI");
189 utopia_intr(&sc->utopia);
191 if (stat & IDT_STAT_RSQF) {
192 patm_printf(sc, "RSQF\n");
195 if (stat & IDT_STAT_EPDU) {
196 patm_debug(sc, INTR, "EPDU");
199 if (stat & IDT_STAT_RAWCF) {
200 patm_debug(sc, INTR, "RAWCF");
203 if (stat & IDT_STAT_RSQAF) {
204 patm_debug(sc, INTR, "RSQAF");
206 } else if (IDT_STAT_FRAC2(stat) != 0xf) {
208 * Workaround for missing interrupt on AAL0. Check the
209 * receive status queue if the FBQ2 is not full.
214 stat = patm_nor_read(sc, IDT_NOR_STAT);
215 patm_nor_write(sc, IDT_NOR_STAT, ints & stat);
216 patm_debug(sc, INTR, "stat=%08x", stat);
219 mtx_unlock(&sc->mtx);
221 patm_debug(sc, INTR, "... exit");
225 * Compute the amount of buffers to feed into a given free buffer queue
227 * Feeding buffers is actually not so easy as it seems. We cannot use the
228 * fraction fields in the status registers, because they round down, i.e.
229 * if we have 34 buffers in the queue, it will show 1. If we now feed
230 * 512 - 1 * 32 buffers, we lose two buffers. The only reliable way to know
231 * how many buffers are in the queue are the FBQP registers.
234 patm_feed_cnt(struct patm_softc *sc, u_int q)
240 /* get the FBQ read and write pointers */
241 reg = patm_nor_read(sc, IDT_NOR_FBQP0 + 4 * q);
242 r = (reg & 0x7ff) >> 1;
243 w = ((reg >> 16) & 0x7ff) >> 1;
244 /* compute amount of free buffers */
245 if ((free = w - r) < 0)
247 KASSERT(free <= 512, ("bad FBQP 0x%x", reg));
250 /* can only feed pairs of buffers */
256 patm_debug(sc, FREEQ, "feeding %u buffers into queue %u", feed, q);
262 * Feed small buffers into buffer queue 0
266 patm_feed_sbufs(struct patm_softc *sc)
273 feed = patm_feed_cnt(sc, 0);
276 if ((v0 = mbp_alloc(sc->sbuf_pool, &p0, &h0)) == NULL)
278 if (mbp_alloc(sc->sbuf_pool, &p1, &h1) == NULL) {
279 mbp_free(sc->sbuf_pool, v0);
282 patm_fbq_write(sc, 0,
283 h0 | MBUF_SHANDLE, (p0 + SMBUF_OFFSET),
284 h1 | MBUF_SHANDLE, (p1 + SMBUF_OFFSET));
291 * Feed small buffers into buffer queue 0
294 patm_feed_vbufs(struct patm_softc *sc)
301 feed = patm_feed_cnt(sc, 2);
304 if ((v0 = mbp_alloc(sc->vbuf_pool, &p0, &h0)) == NULL)
306 if (mbp_alloc(sc->vbuf_pool, &p1, &h1) == NULL) {
307 mbp_free(sc->vbuf_pool, v0);
310 patm_fbq_write(sc, 2,
311 h0 | MBUF_VHANDLE, (p0 + VMBUF_OFFSET),
312 h1 | MBUF_VHANDLE, (p1 + VMBUF_OFFSET));
319 * Allocate a large buffer
321 static struct lmbuf *
322 patm_lmbuf_alloc(struct patm_softc *sc)
328 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
331 m->m_data += LMBUF_OFFSET;
333 if ((b = SLIST_FIRST(&sc->lbuf_free_list)) == NULL) {
338 b->phy = 0; /* alignment */
339 error = bus_dmamap_load(sc->lbuf_tag, b->map, m->m_data, LMBUF_SIZE,
340 patm_load_callback, &b->phy, BUS_DMA_NOWAIT);
342 patm_printf(sc, "%s -- bus_dmamap_load: %d\n", __func__, error);
347 SLIST_REMOVE_HEAD(&sc->lbuf_free_list, link);
354 * Feed large buffers into buffer queue 1
357 patm_feed_lbufs(struct patm_softc *sc)
360 struct lmbuf *b0, *b1;
362 feed = patm_feed_cnt(sc, 1);
365 if ((b0 = patm_lmbuf_alloc(sc)) == NULL)
367 if ((b1 = patm_lmbuf_alloc(sc)) == NULL) {
368 patm_lbuf_free(sc, b0);
371 patm_fbq_write(sc, 1,
372 LMBUF_HANDLE | b0->handle, b0->phy,
373 LMBUF_HANDLE | b1->handle, b1->phy);
380 * Handle transmit status interrupt
383 patm_intr_tsif(struct patm_softc *sc)
385 struct idt_tsqe *tsqe = sc->tsq_next;
386 struct idt_tsqe *prev = NULL;
389 stamp = le32toh(tsqe->stamp);
390 if (stamp & IDT_TSQE_EMPTY)
394 switch (IDT_TSQE_TYPE(stamp)) {
397 patm_tx(sc, stamp, le32toh(tsqe->stat));
401 patm_tx_idle(sc, le32toh(tsqe->stat));
407 tsqe->stamp = htole32(IDT_TSQE_EMPTY);
409 /* save pointer to this entry and advance */
411 if (++tsqe == &sc->tsq[IDT_TSQ_SIZE])
414 stamp = le32toh(tsqe->stamp);
415 } while (!(stamp & IDT_TSQE_EMPTY));
418 patm_nor_write(sc, IDT_NOR_TSQH, ((prev - sc->tsq) << IDT_TSQE_SHIFT));
422 * Handle receive interrupt
425 patm_intr_rsq(struct patm_softc *sc)
427 struct idt_rsqe *rsqe;
430 if (sc->rsq_last + 1 == PATM_RSQ_SIZE)
433 rsqe = &sc->rsq[sc->rsq_last + 1];
434 stat = le32toh(rsqe->stat);
435 if (!(stat & IDT_RSQE_VALID))
438 while (stat & IDT_RSQE_VALID) {
447 /* save pointer to this entry and advance */
448 if (++sc->rsq_last == PATM_RSQ_SIZE)
450 if (++rsqe == &sc->rsq[PATM_RSQ_SIZE])
453 stat = le32toh(rsqe->stat);
456 patm_nor_write(sc, IDT_NOR_RSQH, sc->rsq_phy | (sc->rsq_last << 2));
464 * Handle raw cell receive.
466 * Note that the description on page 3-8 is wrong. The RAWHND contains not
467 * the same value as RAWCT. RAWCT points to the next address the chip is
468 * going to write to whike RAWHND points to the last cell's address the chip
472 patm_intr_raw(struct patm_softc *sc)
478 bus_dma_sync_size(sc->sq_tag, sc->sq_map, IDT_TSQ_SIZE * IDT_TSQE_SIZE +
479 PATM_RSQ_SIZE * IDT_RSQE_SIZE, sizeof(*sc->rawhnd),
480 BUS_DMASYNC_POSTREAD);
483 if (sc->rawh == NULL) {
484 sc->rawh = &sc->lbufs[le32toh(sc->rawhnd->handle) & MBUF_HMASK];
486 tail = le32toh(sc->rawhnd->tail);
487 if (tail == sc->rawh->phy)
488 /* not really a raw interrupt */
491 while (tail + 64 != sc->rawh->phy + sc->rawi * 64) {
493 bus_dmamap_sync_size(sc->lbuf_tag, sc->rawh->map,
494 sc->rawi * 64, 64, BUS_DMASYNC_POSTREAD);
496 cell = (uint32_t *)(mtod(sc->rawh->m, u_char *) +
498 if (sc->rawi == (LMBUF_SIZE / 64) - 1) {
500 h = le32toh(cell[1]);
501 patm_lbuf_free(sc, sc->rawh);
502 sc->rawh = &sc->lbufs[h & MBUF_HMASK];
507 patm_rx_raw(sc, (u_char *)cell);
513 * Free a large mbuf. This is called by us.
516 patm_lbuf_free(struct patm_softc *sc, struct lmbuf *b)
519 bus_dmamap_unload(sc->lbuf_tag, b->map);
524 SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
529 patm_mbuf_cnt(u_int unit)
532 struct patm_softc *sc;
533 u_int used, card, free;
535 dc = devclass_find("patm");
537 printf("%s: can't find devclass\n", __func__);
540 sc = devclass_get_softc(dc, unit);
542 printf("%s: invalid unit number: %d\n", __func__, unit);
546 mbp_count(sc->sbuf_pool, &used, &card, &free);
547 printf("sbufs: %u on card, %u used, %u free\n", card, used, free);
549 mbp_count(sc->vbuf_pool, &used, &card, &free);
550 printf("aal0 bufs: %u on card, %u used, %u free\n", card, used, free);