Deleted Added
full compact
if_patm_intr.c (148887) if_patm_intr.c (160964)
1/*-
2 * Copyright (c) 2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * Driver for IDT77252 based cards like ProSum's.
30 */
31
32#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * Driver for IDT77252 based cards like ProSum's.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_intr.c 148887 2005-08-09 10:20:02Z rwatson $");
33__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_intr.c 160964 2006-08-04 07:56:35Z yar $");
34
35#include "opt_inet.h"
36#include "opt_natm.h"
37
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>
43#include <sys/bus.h>
44#include <sys/errno.h>
45#include <sys/conf.h>
46#include <sys/module.h>
47#include <sys/lock.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>
53#include <vm/uma.h>
54
55#include <sys/sockio.h>
56#include <sys/mbuf.h>
57#include <sys/socket.h>
58
59#include <net/if.h>
60#include <net/if_media.h>
61#include <net/if_atm.h>
62#include <net/route.h>
63#include <netinet/in.h>
64#include <netinet/if_atm.h>
65
66#include <machine/bus.h>
67#include <machine/resource.h>
68#include <sys/bus.h>
69#include <sys/rman.h>
70#include <sys/mbpool.h>
71
72#include <dev/utopia/utopia.h>
73#include <dev/patm/idt77252reg.h>
74#include <dev/patm/if_patmvar.h>
75
76static void patm_feed_sbufs(struct patm_softc *sc);
77static void patm_feed_lbufs(struct patm_softc *sc);
78static void patm_feed_vbufs(struct patm_softc *sc);
79static void patm_intr_tsif(struct patm_softc *sc);
80static void patm_intr_raw(struct patm_softc *sc);
81
82#ifdef PATM_DEBUG
83static int patm_mbuf_cnt(u_int unit) __unused;
84#endif
85
86/*
87 * Write free buf Q
88 */
89static __inline void
90patm_fbq_write(struct patm_softc *sc, u_int queue, uint32_t h0,
91 uint32_t p0, uint32_t h1, uint32_t p1)
92{
93 patm_debug(sc, FREEQ, "supplying(%u,%#x,%#x,%#x,%#x)",
94 queue, h0, p0, h1, p1);
95 patm_nor_write(sc, IDT_NOR_D0, h0);
96 patm_nor_write(sc, IDT_NOR_D1, p0);
97 patm_nor_write(sc, IDT_NOR_D2, h1);
98 patm_nor_write(sc, IDT_NOR_D3, p1);
99 patm_cmd_exec(sc, IDT_CMD_WFBQ | queue);
100}
101
102/*
103 * Interrupt
104 */
105void
106patm_intr(void *p)
107{
108 struct patm_softc *sc = p;
109 uint32_t stat, cfg;
110 u_int cnt;
111 const uint32_t ints = IDT_STAT_TSIF | IDT_STAT_TXICP | IDT_STAT_TSQF |
112 IDT_STAT_TMROF | IDT_STAT_PHYI | IDT_STAT_RSQF | IDT_STAT_EPDU |
113 IDT_STAT_RAWCF | IDT_STAT_RSQAF;
114 const uint32_t fbqa = IDT_STAT_FBQ3A | IDT_STAT_FBQ2A |
115 IDT_STAT_FBQ1A | IDT_STAT_FBQ0A;
116
117 mtx_lock(&sc->mtx);
118
119 stat = patm_nor_read(sc, IDT_NOR_STAT);
120 patm_nor_write(sc, IDT_NOR_STAT, stat & (ints | fbqa));
121
122 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
123 /* if we are stopped ack all interrupts and handle PHYI */
124 if (stat & IDT_STAT_PHYI) {
125 patm_debug(sc, INTR, "PHYI (stopped)");
126 utopia_intr(&sc->utopia);
127 }
128 mtx_unlock(&sc->mtx);
129 return;
130 }
131
132 patm_debug(sc, INTR, "stat=%08x", stat);
133
134 /*
135 * If the buffer queues are empty try to fill them. If this fails
136 * disable the interrupt. Otherwise enable the interrupt.
137 */
138 if (stat & fbqa) {
139 cfg = patm_nor_read(sc, IDT_NOR_CFG);
140 if (stat & IDT_STAT_FBQ0A)
141 patm_feed_sbufs(sc);
142 if (stat & IDT_STAT_FBQ1A)
143 patm_feed_lbufs(sc);
144 if (stat & IDT_STAT_FBQ2A) {
145 /*
146 * Workaround for missing interrupt on AAL0. Check the
147 * receive status queue if the FBQ2 is not full.
148 */
149 patm_intr_rsq(sc);
150 patm_feed_vbufs(sc);
151 }
152 if ((patm_nor_read(sc, IDT_NOR_STAT) & fbqa) &&
153 (cfg & IDT_CFG_FBIE)) {
154 /* failed */
155 patm_nor_write(sc, IDT_NOR_CFG, cfg & ~IDT_CFG_FBIE);
156 patm_printf(sc, "out of buffers -- intr disabled\n");
157 } else if (!(cfg & IDT_CFG_FBIE)) {
158 patm_printf(sc, "bufQ intr re-enabled\n");
159 patm_nor_write(sc, IDT_NOR_CFG, cfg | IDT_CFG_FBIE);
160 }
161 patm_nor_write(sc, IDT_NOR_STAT, fbqa);
162 }
163
164 cnt = 0;
165 while ((stat & ints) != 0) {
166 if (++cnt == 200) {
167 patm_printf(sc, "%s: excessive interrupts\n", __func__);
168 patm_stop(sc);
169 break;
170 }
171 if (stat & IDT_STAT_TSIF) {
172 patm_debug(sc, INTR, "TSIF");
173 patm_intr_tsif(sc);
174 }
175 if (stat & IDT_STAT_TXICP) {
176 patm_printf(sc, "incomplete PDU transmitted\n");
177 }
178 if (stat & IDT_STAT_TSQF) {
179 patm_printf(sc, "TSQF\n");
180 patm_intr_tsif(sc);
181 }
182 if (stat & IDT_STAT_TMROF) {
183 patm_debug(sc, INTR, "TMROF");
184 patm_intr_tsif(sc);
185 }
186 if (stat & IDT_STAT_PHYI) {
187 patm_debug(sc, INTR, "PHYI");
188 utopia_intr(&sc->utopia);
189 }
190 if (stat & IDT_STAT_RSQF) {
191 patm_printf(sc, "RSQF\n");
192 patm_intr_rsq(sc);
193 }
194 if (stat & IDT_STAT_EPDU) {
195 patm_debug(sc, INTR, "EPDU");
196 patm_intr_rsq(sc);
197 }
198 if (stat & IDT_STAT_RAWCF) {
199 patm_debug(sc, INTR, "RAWCF");
200 patm_intr_raw(sc);
201 }
202 if (stat & IDT_STAT_RSQAF) {
203 patm_debug(sc, INTR, "RSQAF");
204 patm_intr_rsq(sc);
205 } else if (IDT_STAT_FRAC2(stat) != 0xf) {
206 /*
207 * Workaround for missing interrupt on AAL0. Check the
208 * receive status queue if the FBQ2 is not full.
209 */
210 patm_intr_rsq(sc);
211 }
212
213 stat = patm_nor_read(sc, IDT_NOR_STAT);
214 patm_nor_write(sc, IDT_NOR_STAT, ints & stat);
215 patm_debug(sc, INTR, "stat=%08x", stat);
216 }
217
218 mtx_unlock(&sc->mtx);
219
220 patm_debug(sc, INTR, "... exit");
221}
222
223/*
224 * Compute the amount of buffers to feed into a given free buffer queue
225 *
226 * Feeding buffers is actually not so easy as it seems. We cannot use the
227 * fraction fields in the status registers, because they round down, i.e.
228 * if we have 34 buffers in the queue, it will show 1. If we now feed
34
35#include "opt_inet.h"
36#include "opt_natm.h"
37
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>
43#include <sys/bus.h>
44#include <sys/errno.h>
45#include <sys/conf.h>
46#include <sys/module.h>
47#include <sys/lock.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>
53#include <vm/uma.h>
54
55#include <sys/sockio.h>
56#include <sys/mbuf.h>
57#include <sys/socket.h>
58
59#include <net/if.h>
60#include <net/if_media.h>
61#include <net/if_atm.h>
62#include <net/route.h>
63#include <netinet/in.h>
64#include <netinet/if_atm.h>
65
66#include <machine/bus.h>
67#include <machine/resource.h>
68#include <sys/bus.h>
69#include <sys/rman.h>
70#include <sys/mbpool.h>
71
72#include <dev/utopia/utopia.h>
73#include <dev/patm/idt77252reg.h>
74#include <dev/patm/if_patmvar.h>
75
76static void patm_feed_sbufs(struct patm_softc *sc);
77static void patm_feed_lbufs(struct patm_softc *sc);
78static void patm_feed_vbufs(struct patm_softc *sc);
79static void patm_intr_tsif(struct patm_softc *sc);
80static void patm_intr_raw(struct patm_softc *sc);
81
82#ifdef PATM_DEBUG
83static int patm_mbuf_cnt(u_int unit) __unused;
84#endif
85
86/*
87 * Write free buf Q
88 */
89static __inline void
90patm_fbq_write(struct patm_softc *sc, u_int queue, uint32_t h0,
91 uint32_t p0, uint32_t h1, uint32_t p1)
92{
93 patm_debug(sc, FREEQ, "supplying(%u,%#x,%#x,%#x,%#x)",
94 queue, h0, p0, h1, p1);
95 patm_nor_write(sc, IDT_NOR_D0, h0);
96 patm_nor_write(sc, IDT_NOR_D1, p0);
97 patm_nor_write(sc, IDT_NOR_D2, h1);
98 patm_nor_write(sc, IDT_NOR_D3, p1);
99 patm_cmd_exec(sc, IDT_CMD_WFBQ | queue);
100}
101
102/*
103 * Interrupt
104 */
105void
106patm_intr(void *p)
107{
108 struct patm_softc *sc = p;
109 uint32_t stat, cfg;
110 u_int cnt;
111 const uint32_t ints = IDT_STAT_TSIF | IDT_STAT_TXICP | IDT_STAT_TSQF |
112 IDT_STAT_TMROF | IDT_STAT_PHYI | IDT_STAT_RSQF | IDT_STAT_EPDU |
113 IDT_STAT_RAWCF | IDT_STAT_RSQAF;
114 const uint32_t fbqa = IDT_STAT_FBQ3A | IDT_STAT_FBQ2A |
115 IDT_STAT_FBQ1A | IDT_STAT_FBQ0A;
116
117 mtx_lock(&sc->mtx);
118
119 stat = patm_nor_read(sc, IDT_NOR_STAT);
120 patm_nor_write(sc, IDT_NOR_STAT, stat & (ints | fbqa));
121
122 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
123 /* if we are stopped ack all interrupts and handle PHYI */
124 if (stat & IDT_STAT_PHYI) {
125 patm_debug(sc, INTR, "PHYI (stopped)");
126 utopia_intr(&sc->utopia);
127 }
128 mtx_unlock(&sc->mtx);
129 return;
130 }
131
132 patm_debug(sc, INTR, "stat=%08x", stat);
133
134 /*
135 * If the buffer queues are empty try to fill them. If this fails
136 * disable the interrupt. Otherwise enable the interrupt.
137 */
138 if (stat & fbqa) {
139 cfg = patm_nor_read(sc, IDT_NOR_CFG);
140 if (stat & IDT_STAT_FBQ0A)
141 patm_feed_sbufs(sc);
142 if (stat & IDT_STAT_FBQ1A)
143 patm_feed_lbufs(sc);
144 if (stat & IDT_STAT_FBQ2A) {
145 /*
146 * Workaround for missing interrupt on AAL0. Check the
147 * receive status queue if the FBQ2 is not full.
148 */
149 patm_intr_rsq(sc);
150 patm_feed_vbufs(sc);
151 }
152 if ((patm_nor_read(sc, IDT_NOR_STAT) & fbqa) &&
153 (cfg & IDT_CFG_FBIE)) {
154 /* failed */
155 patm_nor_write(sc, IDT_NOR_CFG, cfg & ~IDT_CFG_FBIE);
156 patm_printf(sc, "out of buffers -- intr disabled\n");
157 } else if (!(cfg & IDT_CFG_FBIE)) {
158 patm_printf(sc, "bufQ intr re-enabled\n");
159 patm_nor_write(sc, IDT_NOR_CFG, cfg | IDT_CFG_FBIE);
160 }
161 patm_nor_write(sc, IDT_NOR_STAT, fbqa);
162 }
163
164 cnt = 0;
165 while ((stat & ints) != 0) {
166 if (++cnt == 200) {
167 patm_printf(sc, "%s: excessive interrupts\n", __func__);
168 patm_stop(sc);
169 break;
170 }
171 if (stat & IDT_STAT_TSIF) {
172 patm_debug(sc, INTR, "TSIF");
173 patm_intr_tsif(sc);
174 }
175 if (stat & IDT_STAT_TXICP) {
176 patm_printf(sc, "incomplete PDU transmitted\n");
177 }
178 if (stat & IDT_STAT_TSQF) {
179 patm_printf(sc, "TSQF\n");
180 patm_intr_tsif(sc);
181 }
182 if (stat & IDT_STAT_TMROF) {
183 patm_debug(sc, INTR, "TMROF");
184 patm_intr_tsif(sc);
185 }
186 if (stat & IDT_STAT_PHYI) {
187 patm_debug(sc, INTR, "PHYI");
188 utopia_intr(&sc->utopia);
189 }
190 if (stat & IDT_STAT_RSQF) {
191 patm_printf(sc, "RSQF\n");
192 patm_intr_rsq(sc);
193 }
194 if (stat & IDT_STAT_EPDU) {
195 patm_debug(sc, INTR, "EPDU");
196 patm_intr_rsq(sc);
197 }
198 if (stat & IDT_STAT_RAWCF) {
199 patm_debug(sc, INTR, "RAWCF");
200 patm_intr_raw(sc);
201 }
202 if (stat & IDT_STAT_RSQAF) {
203 patm_debug(sc, INTR, "RSQAF");
204 patm_intr_rsq(sc);
205 } else if (IDT_STAT_FRAC2(stat) != 0xf) {
206 /*
207 * Workaround for missing interrupt on AAL0. Check the
208 * receive status queue if the FBQ2 is not full.
209 */
210 patm_intr_rsq(sc);
211 }
212
213 stat = patm_nor_read(sc, IDT_NOR_STAT);
214 patm_nor_write(sc, IDT_NOR_STAT, ints & stat);
215 patm_debug(sc, INTR, "stat=%08x", stat);
216 }
217
218 mtx_unlock(&sc->mtx);
219
220 patm_debug(sc, INTR, "... exit");
221}
222
223/*
224 * Compute the amount of buffers to feed into a given free buffer queue
225 *
226 * Feeding buffers is actually not so easy as it seems. We cannot use the
227 * fraction fields in the status registers, because they round down, i.e.
228 * if we have 34 buffers in the queue, it will show 1. If we now feed
229 * 512 - 1 * 32 buffers, we loose two buffers. The only reliable way to know
229 * 512 - 1 * 32 buffers, we lose two buffers. The only reliable way to know
230 * how many buffers are in the queue are the FBQP registers.
231 */
232static u_int
233patm_feed_cnt(struct patm_softc *sc, u_int q)
234{
235 u_int w, r, reg;
236 u_int feed;
237 int free;
238
239 /* get the FBQ read and write pointers */
240 reg = patm_nor_read(sc, IDT_NOR_FBQP0 + 4 * q);
241 r = (reg & 0x7ff) >> 1;
242 w = ((reg >> 16) & 0x7ff) >> 1;
243 /* compute amount of free buffers */
244 if ((free = w - r) < 0)
245 free += 0x400;
246 KASSERT(free <= 512, ("bad FBQP 0x%x", reg));
247 feed = 512 - free;
248
249 /* can only feed pairs of buffers */
250 feed &= ~1;
251
252 if (feed > 0)
253 feed -= 2;
254
255 patm_debug(sc, FREEQ, "feeding %u buffers into queue %u", feed, q);
256
257 return (feed);
258}
259
260/*
261 * Feed small buffers into buffer queue 0
262 *
263 */
264static void
265patm_feed_sbufs(struct patm_softc *sc)
266{
267 u_int feed;
268 bus_addr_t p0, p1;
269 void *v0, *v1;
270 uint32_t h0, h1;
271
272 feed = patm_feed_cnt(sc, 0);
273
274 while (feed > 0) {
275 if ((v0 = mbp_alloc(sc->sbuf_pool, &p0, &h0)) == NULL)
276 break;
277 if ((v1 = mbp_alloc(sc->sbuf_pool, &p1, &h1)) == NULL) {
278 mbp_free(sc->sbuf_pool, v0);
279 break;
280 }
281 patm_fbq_write(sc, 0,
282 h0 | MBUF_SHANDLE, (p0 + SMBUF_OFFSET),
283 h1 | MBUF_SHANDLE, (p1 + SMBUF_OFFSET));
284
285 feed -= 2;
286 }
287}
288
289/*
290 * Feed small buffers into buffer queue 0
291 */
292static void
293patm_feed_vbufs(struct patm_softc *sc)
294{
295 u_int feed;
296 bus_addr_t p0, p1;
297 void *v0, *v1;
298 uint32_t h0, h1;
299
300 feed = patm_feed_cnt(sc, 2);
301
302 while (feed > 0) {
303 if ((v0 = mbp_alloc(sc->vbuf_pool, &p0, &h0)) == NULL)
304 break;
305 if ((v1 = mbp_alloc(sc->vbuf_pool, &p1, &h1)) == NULL) {
306 mbp_free(sc->vbuf_pool, v0);
307 break;
308 }
309 patm_fbq_write(sc, 2,
310 h0 | MBUF_VHANDLE, (p0 + VMBUF_OFFSET),
311 h1 | MBUF_VHANDLE, (p1 + VMBUF_OFFSET));
312
313 feed -= 2;
314 }
315}
316
317/*
318 * Allocate a large buffer
319 */
320static struct lmbuf *
321patm_lmbuf_alloc(struct patm_softc *sc)
322{
323 int error;
324 struct mbuf *m;
325 struct lmbuf *b;
326
327 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
328 if (m == NULL)
329 return (NULL);
330 m->m_data += LMBUF_OFFSET;
331
332 if ((b = SLIST_FIRST(&sc->lbuf_free_list)) == NULL) {
333 m_freem(m);
334 return (NULL);
335 }
336
337 b->phy = 0; /* alignment */
338 error = bus_dmamap_load(sc->lbuf_tag, b->map, m->m_data, LMBUF_SIZE,
339 patm_load_callback, &b->phy, BUS_DMA_NOWAIT);
340 if (error) {
341 patm_printf(sc, "%s -- bus_dmamap_load: %d\n", __func__, error);
342 m_free(m);
343 return (NULL);
344 }
345
346 SLIST_REMOVE_HEAD(&sc->lbuf_free_list, link);
347 b->m = m;
348
349 return (b);
350}
351
352/*
353 * Feed large buffers into buffer queue 1
354 */
355static void
356patm_feed_lbufs(struct patm_softc *sc)
357{
358 u_int feed;
359 struct lmbuf *b0, *b1;
360
361 feed = patm_feed_cnt(sc, 1);
362
363 while (feed > 0) {
364 if ((b0 = patm_lmbuf_alloc(sc)) == NULL)
365 break;
366 if ((b1 = patm_lmbuf_alloc(sc)) == NULL) {
367 patm_lbuf_free(sc, b0);
368 break;
369 }
370 patm_fbq_write(sc, 1,
371 LMBUF_HANDLE | b0->handle, b0->phy,
372 LMBUF_HANDLE | b1->handle, b1->phy);
373
374 feed -= 2;
375 }
376}
377
378/*
379 * Handle transmit status interrupt
380 */
381static void
382patm_intr_tsif(struct patm_softc *sc)
383{
384 struct idt_tsqe *tsqe = sc->tsq_next;;
385 struct idt_tsqe *prev = NULL;
386 uint32_t stamp;
387
388 stamp = le32toh(tsqe->stamp);
389 if (stamp & IDT_TSQE_EMPTY)
390 return;
391
392 do {
393 switch (IDT_TSQE_TYPE(stamp)) {
394
395 case IDT_TSQE_TBD:
396 patm_tx(sc, stamp, le32toh(tsqe->stat));
397 break;
398
399 case IDT_TSQE_IDLE:
400 patm_tx_idle(sc, le32toh(tsqe->stat));
401 break;
402 }
403
404 /* recycle */
405 tsqe->stat = 0;
406 tsqe->stamp = htole32(IDT_TSQE_EMPTY);
407
408 /* save pointer to this entry and advance */
409 prev = tsqe;
410 if (++tsqe == &sc->tsq[IDT_TSQ_SIZE])
411 tsqe = &sc->tsq[0];
412
413 stamp = le32toh(tsqe->stamp);
414 } while (!(stamp & IDT_TSQE_EMPTY));
415
416 sc->tsq_next = tsqe;
417 patm_nor_write(sc, IDT_NOR_TSQH, ((prev - sc->tsq) << IDT_TSQE_SHIFT));
418}
419
420/*
421 * Handle receive interrupt
422 */
423void
424patm_intr_rsq(struct patm_softc *sc)
425{
426 struct idt_rsqe *rsqe;
427 u_int stat;
428
429 if (sc->rsq_last + 1 == PATM_RSQ_SIZE)
430 rsqe = &sc->rsq[0];
431 else
432 rsqe = &sc->rsq[sc->rsq_last + 1];
433 stat = le32toh(rsqe->stat);
434 if (!(stat & IDT_RSQE_VALID))
435 return;
436
437 while (stat & IDT_RSQE_VALID) {
438 patm_rx(sc, rsqe);
439
440 /* recycle RSQE */
441 rsqe->cid = 0;
442 rsqe->handle = 0;
443 rsqe->crc = 0;
444 rsqe->stat = 0;
445
446 /* save pointer to this entry and advance */
447 if (++sc->rsq_last == PATM_RSQ_SIZE)
448 sc->rsq_last = 0;
449 if (++rsqe == &sc->rsq[PATM_RSQ_SIZE])
450 rsqe = sc->rsq;
451
452 stat = le32toh(rsqe->stat);
453 }
454
455 patm_nor_write(sc, IDT_NOR_RSQH, sc->rsq_phy | (sc->rsq_last << 2));
456
457 patm_feed_sbufs(sc);
458 patm_feed_lbufs(sc);
459 patm_feed_vbufs(sc);
460}
461
462/*
463 * Handle raw cell receive.
464 *
465 * Note that the description on page 3-8 is wrong. The RAWHND contains not
466 * the same value as RAWCT. RAWCT points to the next address the chip is
467 * going to write to whike RAWHND points to the last cell's address the chip
468 * has written to.
469 */
470static void
471patm_intr_raw(struct patm_softc *sc)
472{
473 uint32_t tail;
474 uint32_t h, *cell;
475
476#ifdef notyet
477 bus_dma_sync_size(sc->sq_tag, sc->sq_map, IDT_TSQ_SIZE * IDT_TSQE_SIZE +
478 PATM_RSQ_SIZE * IDT_RSQE_SIZE, sizeof(*sc->rawhnd),
479 BUS_DMASYNC_POSTREAD);
480#endif
481 /* first turn */
482 if (sc->rawh == NULL) {
483 sc->rawh = &sc->lbufs[le32toh(sc->rawhnd->handle) & MBUF_HMASK];
484 }
485 tail = le32toh(sc->rawhnd->tail);
486 if (tail == sc->rawh->phy)
487 /* not really a raw interrupt */
488 return;
489
490 while (tail + 64 != sc->rawh->phy + sc->rawi * 64) {
491#ifdef notyet
492 bus_dmamap_sync_size(sc->lbuf_tag, sc->rawh->map,
493 sc->rawi * 64, 64, BUS_DMASYNC_POSTREAD);
494#endif
495 cell = (uint32_t *)(mtod(sc->rawh->m, u_char *) +
496 sc->rawi * 64);
497 if (sc->rawi == (LMBUF_SIZE / 64) - 1) {
498 /* chain */
499 h = le32toh(cell[1]);
500 patm_lbuf_free(sc, sc->rawh);
501 sc->rawh = &sc->lbufs[h & MBUF_HMASK];
502 sc->rawi = 0;
503 continue;
504 }
505
506 patm_rx_raw(sc, (u_char *)cell);
507 sc->rawi++;
508 }
509}
510
511/*
512 * Free a large mbuf. This is called by us.
513 */
514void
515patm_lbuf_free(struct patm_softc *sc, struct lmbuf *b)
516{
517
518 bus_dmamap_unload(sc->lbuf_tag, b->map);
519 if (b->m != NULL) {
520 m_free(b->m);
521 b->m = NULL;
522 }
523 SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
524}
525
526#ifdef PATM_DEBUG
527static int
528patm_mbuf_cnt(u_int unit)
529{
530 devclass_t dc;
531 struct patm_softc *sc;
532 u_int used, card, free;
533
534 dc = devclass_find("patm");
535 if (dc == NULL) {
536 printf("%s: can't find devclass\n", __func__);
537 return (0);
538 }
539 sc = devclass_get_softc(dc, unit);
540 if (sc == NULL) {
541 printf("%s: invalid unit number: %d\n", __func__, unit);
542 return (0);
543 }
544
545 mbp_count(sc->sbuf_pool, &used, &card, &free);
546 printf("sbufs: %u on card, %u used, %u free\n", card, used, free);
547
548 mbp_count(sc->vbuf_pool, &used, &card, &free);
549 printf("aal0 bufs: %u on card, %u used, %u free\n", card, used, free);
550
551 return (0);
552}
553#endif
230 * how many buffers are in the queue are the FBQP registers.
231 */
232static u_int
233patm_feed_cnt(struct patm_softc *sc, u_int q)
234{
235 u_int w, r, reg;
236 u_int feed;
237 int free;
238
239 /* get the FBQ read and write pointers */
240 reg = patm_nor_read(sc, IDT_NOR_FBQP0 + 4 * q);
241 r = (reg & 0x7ff) >> 1;
242 w = ((reg >> 16) & 0x7ff) >> 1;
243 /* compute amount of free buffers */
244 if ((free = w - r) < 0)
245 free += 0x400;
246 KASSERT(free <= 512, ("bad FBQP 0x%x", reg));
247 feed = 512 - free;
248
249 /* can only feed pairs of buffers */
250 feed &= ~1;
251
252 if (feed > 0)
253 feed -= 2;
254
255 patm_debug(sc, FREEQ, "feeding %u buffers into queue %u", feed, q);
256
257 return (feed);
258}
259
260/*
261 * Feed small buffers into buffer queue 0
262 *
263 */
264static void
265patm_feed_sbufs(struct patm_softc *sc)
266{
267 u_int feed;
268 bus_addr_t p0, p1;
269 void *v0, *v1;
270 uint32_t h0, h1;
271
272 feed = patm_feed_cnt(sc, 0);
273
274 while (feed > 0) {
275 if ((v0 = mbp_alloc(sc->sbuf_pool, &p0, &h0)) == NULL)
276 break;
277 if ((v1 = mbp_alloc(sc->sbuf_pool, &p1, &h1)) == NULL) {
278 mbp_free(sc->sbuf_pool, v0);
279 break;
280 }
281 patm_fbq_write(sc, 0,
282 h0 | MBUF_SHANDLE, (p0 + SMBUF_OFFSET),
283 h1 | MBUF_SHANDLE, (p1 + SMBUF_OFFSET));
284
285 feed -= 2;
286 }
287}
288
289/*
290 * Feed small buffers into buffer queue 0
291 */
292static void
293patm_feed_vbufs(struct patm_softc *sc)
294{
295 u_int feed;
296 bus_addr_t p0, p1;
297 void *v0, *v1;
298 uint32_t h0, h1;
299
300 feed = patm_feed_cnt(sc, 2);
301
302 while (feed > 0) {
303 if ((v0 = mbp_alloc(sc->vbuf_pool, &p0, &h0)) == NULL)
304 break;
305 if ((v1 = mbp_alloc(sc->vbuf_pool, &p1, &h1)) == NULL) {
306 mbp_free(sc->vbuf_pool, v0);
307 break;
308 }
309 patm_fbq_write(sc, 2,
310 h0 | MBUF_VHANDLE, (p0 + VMBUF_OFFSET),
311 h1 | MBUF_VHANDLE, (p1 + VMBUF_OFFSET));
312
313 feed -= 2;
314 }
315}
316
317/*
318 * Allocate a large buffer
319 */
320static struct lmbuf *
321patm_lmbuf_alloc(struct patm_softc *sc)
322{
323 int error;
324 struct mbuf *m;
325 struct lmbuf *b;
326
327 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
328 if (m == NULL)
329 return (NULL);
330 m->m_data += LMBUF_OFFSET;
331
332 if ((b = SLIST_FIRST(&sc->lbuf_free_list)) == NULL) {
333 m_freem(m);
334 return (NULL);
335 }
336
337 b->phy = 0; /* alignment */
338 error = bus_dmamap_load(sc->lbuf_tag, b->map, m->m_data, LMBUF_SIZE,
339 patm_load_callback, &b->phy, BUS_DMA_NOWAIT);
340 if (error) {
341 patm_printf(sc, "%s -- bus_dmamap_load: %d\n", __func__, error);
342 m_free(m);
343 return (NULL);
344 }
345
346 SLIST_REMOVE_HEAD(&sc->lbuf_free_list, link);
347 b->m = m;
348
349 return (b);
350}
351
352/*
353 * Feed large buffers into buffer queue 1
354 */
355static void
356patm_feed_lbufs(struct patm_softc *sc)
357{
358 u_int feed;
359 struct lmbuf *b0, *b1;
360
361 feed = patm_feed_cnt(sc, 1);
362
363 while (feed > 0) {
364 if ((b0 = patm_lmbuf_alloc(sc)) == NULL)
365 break;
366 if ((b1 = patm_lmbuf_alloc(sc)) == NULL) {
367 patm_lbuf_free(sc, b0);
368 break;
369 }
370 patm_fbq_write(sc, 1,
371 LMBUF_HANDLE | b0->handle, b0->phy,
372 LMBUF_HANDLE | b1->handle, b1->phy);
373
374 feed -= 2;
375 }
376}
377
378/*
379 * Handle transmit status interrupt
380 */
381static void
382patm_intr_tsif(struct patm_softc *sc)
383{
384 struct idt_tsqe *tsqe = sc->tsq_next;;
385 struct idt_tsqe *prev = NULL;
386 uint32_t stamp;
387
388 stamp = le32toh(tsqe->stamp);
389 if (stamp & IDT_TSQE_EMPTY)
390 return;
391
392 do {
393 switch (IDT_TSQE_TYPE(stamp)) {
394
395 case IDT_TSQE_TBD:
396 patm_tx(sc, stamp, le32toh(tsqe->stat));
397 break;
398
399 case IDT_TSQE_IDLE:
400 patm_tx_idle(sc, le32toh(tsqe->stat));
401 break;
402 }
403
404 /* recycle */
405 tsqe->stat = 0;
406 tsqe->stamp = htole32(IDT_TSQE_EMPTY);
407
408 /* save pointer to this entry and advance */
409 prev = tsqe;
410 if (++tsqe == &sc->tsq[IDT_TSQ_SIZE])
411 tsqe = &sc->tsq[0];
412
413 stamp = le32toh(tsqe->stamp);
414 } while (!(stamp & IDT_TSQE_EMPTY));
415
416 sc->tsq_next = tsqe;
417 patm_nor_write(sc, IDT_NOR_TSQH, ((prev - sc->tsq) << IDT_TSQE_SHIFT));
418}
419
420/*
421 * Handle receive interrupt
422 */
423void
424patm_intr_rsq(struct patm_softc *sc)
425{
426 struct idt_rsqe *rsqe;
427 u_int stat;
428
429 if (sc->rsq_last + 1 == PATM_RSQ_SIZE)
430 rsqe = &sc->rsq[0];
431 else
432 rsqe = &sc->rsq[sc->rsq_last + 1];
433 stat = le32toh(rsqe->stat);
434 if (!(stat & IDT_RSQE_VALID))
435 return;
436
437 while (stat & IDT_RSQE_VALID) {
438 patm_rx(sc, rsqe);
439
440 /* recycle RSQE */
441 rsqe->cid = 0;
442 rsqe->handle = 0;
443 rsqe->crc = 0;
444 rsqe->stat = 0;
445
446 /* save pointer to this entry and advance */
447 if (++sc->rsq_last == PATM_RSQ_SIZE)
448 sc->rsq_last = 0;
449 if (++rsqe == &sc->rsq[PATM_RSQ_SIZE])
450 rsqe = sc->rsq;
451
452 stat = le32toh(rsqe->stat);
453 }
454
455 patm_nor_write(sc, IDT_NOR_RSQH, sc->rsq_phy | (sc->rsq_last << 2));
456
457 patm_feed_sbufs(sc);
458 patm_feed_lbufs(sc);
459 patm_feed_vbufs(sc);
460}
461
462/*
463 * Handle raw cell receive.
464 *
465 * Note that the description on page 3-8 is wrong. The RAWHND contains not
466 * the same value as RAWCT. RAWCT points to the next address the chip is
467 * going to write to whike RAWHND points to the last cell's address the chip
468 * has written to.
469 */
470static void
471patm_intr_raw(struct patm_softc *sc)
472{
473 uint32_t tail;
474 uint32_t h, *cell;
475
476#ifdef notyet
477 bus_dma_sync_size(sc->sq_tag, sc->sq_map, IDT_TSQ_SIZE * IDT_TSQE_SIZE +
478 PATM_RSQ_SIZE * IDT_RSQE_SIZE, sizeof(*sc->rawhnd),
479 BUS_DMASYNC_POSTREAD);
480#endif
481 /* first turn */
482 if (sc->rawh == NULL) {
483 sc->rawh = &sc->lbufs[le32toh(sc->rawhnd->handle) & MBUF_HMASK];
484 }
485 tail = le32toh(sc->rawhnd->tail);
486 if (tail == sc->rawh->phy)
487 /* not really a raw interrupt */
488 return;
489
490 while (tail + 64 != sc->rawh->phy + sc->rawi * 64) {
491#ifdef notyet
492 bus_dmamap_sync_size(sc->lbuf_tag, sc->rawh->map,
493 sc->rawi * 64, 64, BUS_DMASYNC_POSTREAD);
494#endif
495 cell = (uint32_t *)(mtod(sc->rawh->m, u_char *) +
496 sc->rawi * 64);
497 if (sc->rawi == (LMBUF_SIZE / 64) - 1) {
498 /* chain */
499 h = le32toh(cell[1]);
500 patm_lbuf_free(sc, sc->rawh);
501 sc->rawh = &sc->lbufs[h & MBUF_HMASK];
502 sc->rawi = 0;
503 continue;
504 }
505
506 patm_rx_raw(sc, (u_char *)cell);
507 sc->rawi++;
508 }
509}
510
511/*
512 * Free a large mbuf. This is called by us.
513 */
514void
515patm_lbuf_free(struct patm_softc *sc, struct lmbuf *b)
516{
517
518 bus_dmamap_unload(sc->lbuf_tag, b->map);
519 if (b->m != NULL) {
520 m_free(b->m);
521 b->m = NULL;
522 }
523 SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
524}
525
526#ifdef PATM_DEBUG
527static int
528patm_mbuf_cnt(u_int unit)
529{
530 devclass_t dc;
531 struct patm_softc *sc;
532 u_int used, card, free;
533
534 dc = devclass_find("patm");
535 if (dc == NULL) {
536 printf("%s: can't find devclass\n", __func__);
537 return (0);
538 }
539 sc = devclass_get_softc(dc, unit);
540 if (sc == NULL) {
541 printf("%s: invalid unit number: %d\n", __func__, unit);
542 return (0);
543 }
544
545 mbp_count(sc->sbuf_pool, &used, &card, &free);
546 printf("sbufs: %u on card, %u used, %u free\n", card, used, free);
547
548 mbp_count(sc->vbuf_pool, &used, &card, &free);
549 printf("aal0 bufs: %u on card, %u used, %u free\n", card, used, free);
550
551 return (0);
552}
553#endif