FreeBSD/Linux Kernel Cross Reference
sys/dev/idt/idt.c
1 /*-
2 * Copyright (c) 2000, 2001 Richard Hodges and Matriplex, inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Matriplex, inc.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 ******************************************************************************
32 *
33 * This driver is derived from the Nicstar driver by Mark Tinguely, and
34 * some of the original driver still exists here. Those portions are...
35 * Copyright (c) 1996, 1997, 1998, 1999 Mark Tinguely
36 * All rights reserved.
37 *
38 ******************************************************************************
39 *
40 * This driver supports the Fore LE155, LE25, and IDT 77211 cards.
41 *
42 * ATM CBR connections are supported, and bandwidth is allocated in
43 * slots of 64k each. Three VBR queues handle traffic for VBR and
44 * UBR. Two UBR queues prioritize UBR traffic. ILMI and signalling
45 * get the higher priority queue, as well as UBR traffic that specifies
46 * a peak cell rate. All other UBR traffic goes into the lower queue.
47 *
48 ******************************************************************************
49 *
50 * The following sysctl variables are used:
51 *
52 * hw.idt.log_bufstat (0) Log free buffers (every few minutes)
53 * hw.idt.log_vcs (0) Log VC opens, closes, and other events
54 * hw.idt.bufs_large (100) Max/target number of free 2k buffers
55 * hw.idt.bufs_small (200) Max/target number of free mbufs
56 * hw.idt.cur_large (R/O) Current number of free 2k buffers
57 * hw.idt.cur_small (R/O) Current number of free mbufs
58 * hw.idt.qptr_hold (1) Optimize TX queue buffer for lowest overhead
59 *
60 * Note that the read-only buffer counts will not work with multiple cards.
61 *
62 ******************************************************************************
63 *
64 * Assumptions:
65 *
66 * 1. All mbuf clusters are 2048 bytes, and aligned.
67 * 2. All mbufs are 256 bytes, and aligned (see idt_intr_tsq).
68 *
69 * Bugs:
70 *
71 * 1. Function idt_detach() is unusuable because idt_release_mem() is
72 * incomplete. The mbufs held in the free buffer queues can be
73 * recovered from the "mcheck" hash table.
74 * 2. The memory allocation could be cleaned up quite a bit.
75 *
76 ******************************************************************************
77 */
78
79 #include <sys/cdefs.h>
80 __FBSDID("$FreeBSD$");
81
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/conf.h>
85 #include <sys/mbuf.h>
86 #include <sys/protosw.h>
87 #include <sys/socket.h>
88 #include <sys/sysctl.h>
89
90 #include <sys/sockio.h>
91
92 #include <sys/errno.h>
93 #include <sys/malloc.h>
94 #include <sys/kernel.h>
95 #include <sys/proc.h>
96 #include <sys/signalvar.h>
97 #include <sys/mman.h>
98 #include <machine/clock.h>
99 #include <machine/cpu.h> /* bootverbose */
100
101 #include <sys/bus.h>
102 #include <machine/bus.h>
103 #include <sys/rman.h>
104 #include <machine/resource.h>
105
106 #include <net/if.h>
107 #include <net/if_arp.h>
108
109 /* Gross kludge to make lint compile again. This sucks, but oh well */
110 #ifdef COMPILING_LINT
111 #undef MCLBYTES
112 #undef MCLSHIFT
113 #define MCLBYTES 2048
114 #define MCLSHIFT 11
115 #endif
116
117 #if MCLBYTES != 2048
118 #error "This nicstar driver depends on 2048 byte mbuf clusters."
119 #endif
120
121 #include <netatm/port.h>
122 #include <netatm/queue.h>
123 #include <netatm/atm.h>
124 #include <netatm/atm_sys.h>
125 #include <netatm/atm_sap.h>
126 #include <netatm/atm_cm.h>
127 #include <netatm/atm_if.h>
128 #include <netatm/atm_stack.h>
129 #include <netatm/atm_pcb.h>
130 #include <netatm/atm_var.h>
131 #include <netatm/atm_vc.h>
132
133 #include <vm/vm.h>
134 #include <vm/vm_kern.h>
135 #include <vm/vm_param.h>
136 #include <vm/pmap.h>
137 #include <vm/vm_extern.h>
138
139 #include <dev/idt/idtreg.h>
140 #include <dev/idt/idtvar.h>
141
142 #define MAXCARDS 10 /* set to impossibly high */
143
144 /******************************************************************************
145 *
146 * You may change IDT_LBUFS and IDT_SBUFS if you wish.
147 */
148
149 #define NICSTAR_LRG_SIZE 2048 /* must be power of two */
150 #define IDT_LBUFS 100 /* default number of 2k buffers */
151 #define IDT_SBUFS 200 /* default number of 96-byte buffers */
152
153 #define IDT_TST_START 0x1c000 /* transmit schedule table start */
154 #define IDT_SCD_START 0x1d000 /* segmentation channel descriptors start */
155 #define IDT_SCD_SIZE 509 /* max number of SCD entries */
156
157 #define NICSTAR_FIXPAGES 10
158
159 static int idt_sysctl_logbufs = 0; /* periodic buffer status messages */
160 int idt_sysctl_logvcs = 0; /* log VC open & close events */
161 static int idt_sysctl_buflarge = IDT_LBUFS; /* desired large buffer queue */
162 static int idt_sysctl_bufsmall = IDT_SBUFS; /* desired small buffer queue */
163 static int idt_sysctl_curlarge = 0; /* current large buffer queue */
164 static int idt_sysctl_cursmall = 0; /* current small buffer queue */
165 static int idt_sysctl_qptrhold = 1; /* hold TX queue pointer back */
166 int idt_sysctl_vbriscbr = 0; /* use CBR slots for VBR VC's */
167
168 SYSCTL_NODE(_hw, OID_AUTO, idt, CTLFLAG_RW, 0, "IDT Nicstar");
169
170 SYSCTL_INT(_hw_idt, OID_AUTO, log_bufstat, CTLFLAG_RW,
171 &idt_sysctl_logbufs, 0, "Log buffer status");
172 SYSCTL_INT(_hw_idt, OID_AUTO, log_vcs, CTLFLAG_RW,
173 &idt_sysctl_logvcs, 0, "Log VC open/close");
174
175 SYSCTL_INT(_hw_idt, OID_AUTO, bufs_large, CTLFLAG_RW,
176 &idt_sysctl_buflarge, IDT_LBUFS, "Large buffer queue");
177 SYSCTL_INT(_hw_idt, OID_AUTO, bufs_small, CTLFLAG_RW,
178 &idt_sysctl_bufsmall, IDT_SBUFS, "Small buffer queue");
179 SYSCTL_INT(_hw_idt, OID_AUTO, cur_large, CTLFLAG_RD,
180 &idt_sysctl_curlarge, 0, "Current large queue");
181 SYSCTL_INT(_hw_idt, OID_AUTO, cur_small, CTLFLAG_RD,
182 &idt_sysctl_cursmall, 0, "Current small queue");
183 SYSCTL_INT(_hw_idt, OID_AUTO, qptr_hold, CTLFLAG_RW,
184 &idt_sysctl_qptrhold, 1, "Optimize TX queue ptr");
185 SYSCTL_INT(_hw_idt, OID_AUTO, vbr_is_cbr, CTLFLAG_RW,
186 &idt_sysctl_vbriscbr, 0, "Use CBR for VBR VC's");
187
188 /******************************************************************************
189 *
190 * common VCI values
191 *
192 * 0/0 Idle cells
193 * 0/1 Meta signalling
194 * x/1 Meta signalling
195 * 0/2 Broadcast signalling
196 * x/2 Broadcast signalling
197 * x/3 Segment OAM F4 flow
198 * x/4 End-end OAM F4 flow
199 * 0/5 p-p signalling
200 * x/5 p-p signalling
201 * x/6 rate management
202 * 0/14 SPANS
203 * 0/15 SPANS
204 * 0/16 ILMI
205 * 0/18 PNNI
206 */
207
208 /*******************************************************************************
209 *
210 * fixbuf memory map:
211 *
212 * 0000 - 1fff: TSQ Transmit status queue 1024 entries * 8 bytes each
213 * 2000 - 3fff: RSQ Receive status queue, 512 entries * 16 bytes each
214 * 4000 - 5fff: VBR segmentation channel queue (highest priority)
215 * 6000 - 7fff: ABR segmentation channel queue (middle priority)
216 * 8000 - 9fff: UBR segmentation channel queue (lowest priority)
217 *
218 * IDT device memory map:
219 *
220 * 1fc00: RX large buffer queue (4k)
221 * 1f800: RX small buffer queue (4k)
222 * 1e800: RX cells FIFO (16k)
223 * 1e7f4: SCD0 - VBR (12)
224 * 1e7e8: SCD1 - ABR (12)
225 * 1e7dc: SCD2 - UBR (12)
226 * 1e7db: CBR SCD end (last word)
227 * 1d000: CBR SCD start (509 entries)
228 * 1cfff: TST end (4095 available slots)
229 * 1c000: TST start (first CBR slot)
230 *
231 */
232
233 static u_long idt_found = 0;
234
235 /* -------- buffer management -------- */
236 static int nicstar_sram_wr(nicstar_reg_t * const, u_long,
237 int, u_long, u_long, u_long, u_long);
238 static int nicstar_sram_rd(nicstar_reg_t * const, u_long, u_long *);
239 static int nicstar_add_buf(nicstar_reg_t * const, struct mbuf *,
240 struct mbuf *, u_long);
241 static int nicstar_util_rd(nicstar_reg_t * const, u_long, u_long *);
242 static int nicstar_util_wr(nicstar_reg_t * const, int, u_long, u_long);
243 void nicstar_ld_rcv_buf(nicstar_reg_t * const);
244
245 /* -------- interface routines -------- */
246 int nicstar_output(struct ifnet *, struct mbuf *, struct sockaddr *,
247 struct rtentry *);
248 void nicstar_start(struct ifnet *);
249
250 /* -------- VCC open/close routines -------- */
251 static void nicstar_itrx(nicstar_reg_t *);
252
253 /* -------- receiving routines -------- */
254 static void nicstar_rawc(nicstar_reg_t *);
255 static void nicstar_recv(nicstar_reg_t *);
256 static void nicstar_phys(nicstar_reg_t *);
257
258 /*******************************************************************************
259 *
260 * New functions
261 */
262
263 static int idt_buffer_init(IDT *);
264 static struct mbuf *idt_mbufcl_get(void);
265
266 static int idt_connect_init(IDT *, int);
267 static void idt_connect_newvbr(IDT *);
268
269 static void idt_intr_tsq(IDT *);
270
271 static vm_offset_t idt_malloc_contig(int);
272
273 static int idt_mbuf_align(struct mbuf *, struct mbuf *);
274 static int idt_mbuf_append4(struct mbuf *, char *);
275 static struct mbuf *idt_mbuf_copy(IDT *, struct mbuf *);
276 static int idt_mbuf_prepend(struct mbuf *, char *, int);
277 static int idt_mbuf_used(struct mbuf *);
278
279 static int idt_mcheck_add(IDT *, struct mbuf *);
280 static int idt_mcheck_rem(IDT *, struct mbuf *);
281 static int idt_mcheck_init(IDT *);
282
283 static int idt_queue_flush(CONNECTION *);
284 static struct mbuf *idt_queue_get(TX_QUEUE *);
285 static int idt_queue_init(IDT *);
286 static int idt_queue_put(CONNECTION *, struct mbuf *);
287
288 static int idt_receive_aal5(IDT *, struct mbuf *, struct mbuf *);
289 static void idt_transmit_drop(IDT *, struct mbuf *);
290 static void idt_transmit_top(IDT *, TX_QUEUE *);
291
292 static int idt_slots_add(IDT *, TX_QUEUE *, int);
293 static int idt_slots_init(IDT *);
294 static int idt_slots_rem(IDT *, TX_QUEUE *);
295
296 static int idt_phys_detect(IDT *);
297 static void idt_status_bufs(IDT *);
298 static int idt_status_wait(IDT *);
299
300 /******************************************************************************
301 *
302 * VBR queue divisor table
303 */
304
305 static unsigned char vbr_div_m[] = {
306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2,
307 1, 2, 2, 2, 3, 1, 2, 1, 3, 2, 3, 3, 4, 3, 3, 2, 4, 1, 3, 3,
308 1, 5, 5, 4, 4, 5, 4, 4, 6, 5, 1, 5, 4, 6, 2, 6, 7, 7, 4, 1,
309 3, 5, 7, 7, 5, 5, 7, 7, 7, 2, 7, 7, 7, 7, 2, 3, 6, 1, 6, 3,
310 2, 3, 5, 1, 7, 4, 5, 2, 3, 4, 7, 1, 7, 4, 3, 2, 7, 7, 5, 7,
311 1, 7, 5, 7, 5, 2, 7, 3, 4, 6, 7, 1, 1, 7, 4, 7, 5, 7, 2, 5,
312 3, 4, 5, 7, 1, 1, 1, 7, 5, 4, 7, 3, 7, 2, 7, 5, 3, 7, 4, 5,
313 7, 7, 1, 1, 1, 7, 7, 5, 4, 7, 3, 5, 7, 7, 2, 7, 5, 5, 3, 7,
314 4, 5, 6, 7, 7, 1, 1, 1, 1, 7, 7, 7, 5, 5, 4, 7, 3, 3, 5, 5,
315 7, 2, 2, 2, 7, 5, 5, 3, 3, 7, 4, 4, 5, 6, 7, 7, 7, 7, 1, 1,
316 1, 1, 1, 7, 7, 7, 7, 6, 5, 5, 4, 4, 7, 7, 3, 3, 5, 5, 5, 7,
317 7, 2, 2, 2, 2, 7, 7, 5, 5, 5, 3, 3, 3, 7, 7, 4, 4, 5, 5, 5,
318 6, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7,
319 7, 6, 6, 5, 5, 4, 4, 4, 7, 7, 7, 3, 3, 3, 3, 3, 5, 5, 5, 7,
320 7, 7, 7, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 5, 5, 5, 5, 5, 3, 3,
321 3, 3, 3, 7, 7, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7,
322 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
323 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5,
324 5, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3,
325 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2,
326 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5,
327 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7,
328 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
329 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
330 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
332 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
333 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5,
334 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7,
335 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3,
336 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
337 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7,
338 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2,
339 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
340 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
341 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
342 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3,
343 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
344 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
345 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
346 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
347 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
348 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
349 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
350 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
351 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
352 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1,
353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
356 };
357
358 static unsigned char vbr_div_n[] = {
359 127, 127, 127, 127, 127, 127, 127, 127, 125, 111, 100, 91, 83, 77, 71,
360 67, 125, 59, 111, 105, 50, 95, 91, 87, 125, 40, 77, 37, 107, 69,
361 100, 97, 125, 91, 88, 57, 111, 27, 79, 77, 25, 122, 119, 93, 91,
362 111, 87, 85, 125, 102, 20, 98, 77, 113, 37, 109, 125, 123, 69, 17,
363 50, 82, 113, 111, 78, 77, 106, 104, 103, 29, 100, 99, 97, 96, 27,
364 40, 79, 13, 77, 38, 25, 37, 61, 12, 83, 47, 58, 23, 34, 45,
365 78, 11, 76, 43, 32, 21, 73, 72, 51, 71, 10, 69, 49, 68, 48,
366 19, 66, 28, 37, 55, 64, 9, 9, 62, 35, 61, 43, 60, 17, 42,
367 25, 33, 41, 57, 8, 8, 8, 55, 39, 31, 54, 23, 53, 15, 52,
368 37, 22, 51, 29, 36, 50, 50, 7, 7, 7, 48, 48, 34, 27, 47,
369 20, 33, 46, 46, 13, 45, 32, 32, 19, 44, 25, 31, 37, 43, 43,
370 6, 6, 6, 6, 41, 41, 41, 29, 29, 23, 40, 17, 17, 28, 28,
371 39, 11, 11, 11, 38, 27, 27, 16, 16, 37, 21, 21, 26, 31, 36,
372 36, 36, 36, 5, 5, 5, 5, 5, 34, 34, 34, 34, 29, 24, 24,
373 19, 19, 33, 33, 14, 14, 23, 23, 23, 32, 32, 9, 9, 9, 9,
374 31, 31, 22, 22, 22, 13, 13, 13, 30, 30, 17, 17, 21, 21, 21,
375 25, 29, 29, 29, 29, 29, 4, 4, 4, 4, 4, 4, 4, 4, 4,
376 27, 27, 27, 27, 27, 27, 23, 23, 19, 19, 15, 15, 15, 26, 26,
377 26, 11, 11, 11, 11, 11, 18, 18, 18, 25, 25, 25, 25, 7, 7,
378 7, 7, 7, 7, 24, 24, 24, 24, 17, 17, 17, 17, 17, 10, 10,
379 10, 10, 10, 23, 23, 23, 23, 13, 13, 13, 13, 16, 16, 16, 16,
380 19, 19, 22, 22, 22, 22, 22, 22, 22, 22, 22, 3, 3, 3, 3,
381 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 20, 20, 20,
382 20, 20, 20, 20, 20, 20, 20, 17, 17, 17, 17, 14, 14, 14, 14,
383 14, 11, 11, 11, 11, 11, 11, 19, 19, 19, 19, 19, 8, 8, 8,
384 8, 8, 8, 8, 8, 13, 13, 13, 13, 13, 13, 13, 18, 18, 18,
385 18, 18, 18, 18, 18, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
386 5, 17, 17, 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12,
387 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 16,
388 16, 16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9,
389 11, 11, 11, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, 13,
390 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
391 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
392 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
393 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13,
394 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
395 13, 13, 11, 11, 11, 11, 11, 11, 11, 11, 11, 9, 9, 9, 9,
396 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7,
397 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12,
398 12, 12, 12, 12, 12, 12, 12, 5, 5, 5, 5, 5, 5, 5, 5,
399 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, 8,
400 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
401 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
402 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3,
403 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
404 3, 3, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10,
405 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
406 10, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
407 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4,
408 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
409 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9,
410 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
411 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5,
412 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
413 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
414 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
415 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
416 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
417 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
418 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
419 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
420 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
421 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
422 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
426 };
427
428 /******************************************************************************
429 *
430 * Stop the device (shutdown)
431 *
432 * in: IDT device
433 *
434 * Date first: 11/14/2000 last: 11/14/2000
435 */
436
437 void
438 idt_device_stop(IDT * idt)
439 {
440 u_long val;
441 int s;
442
443 s = splimp();
444
445 *(idt->reg_cfg) = 0x80000000; /* put chip into reset */
446 val = *(idt->reg_gp); /* wait... */
447 val |= *(idt->reg_gp); /* wait... */
448 val |= *(idt->reg_gp); /* wait... */
449 *(idt->reg_cfg) = 0; /* out of reset */
450
451 splx(s);
452
453 return;
454 }
455
456 /******************************************************************************
457 *
458 * Initialize the hardware
459 */
460
461 void
462 phys_init(nicstar_reg_t * const idt)
463 {
464 int i;
465 u_long t;
466
467 #ifdef NICSTAR_TESTSRAM
468 u_long z, s2, bad;
469 #endif
470 u_long x, s1;
471 volatile u_long *regCFG = (volatile u_long *)(idt->virt_baseaddr + REGCFG);
472 volatile u_long *regGP = (volatile u_long *)(idt->virt_baseaddr + REGGP);
473 volatile u_long stat_val;
474
475 /* clean status bits */
476 stat_val = *(volatile u_long *)idt->stat_reg;
477 *(volatile u_long *)idt->stat_reg = stat_val | 0xcc30; /* clear ints */
478
479 idt->flg_le25 = 0; /* is this FORE LE25 with 77105 PHY? */
480 idt->flg_igcrc = 0; /* ignore receive CRC errors? */
481 idt->hardware = "?";
482
483 /* start signalling SAR reset */
484 *regCFG = 0x80000000;
485
486 /* SAR reset--clear occurs at lease 2 PCI cycles after setting */
487 t = *regGP; /* wait */
488 t = *regCFG;
489 *regCFG = 0; /* clear reset */
490
491 *regGP = 0x00000000; /* clear PHYS reset */
492 *regGP = 0x00000008; /* start PHYS reset */
493 t = *regGP; /* wait */
494 t = *regCFG;
495 *regGP = 0x00000001; /* set while changing SUNI settings */
496 t = *regGP; /* wait */
497 t = *regCFG;
498
499 idt->flg_le25 = idt_phys_detect(idt);
500
501 if (idt->flg_le25) {
502 idt->cellrate_rmax = 59259;
503 idt->cellrate_tmax = 59259;
504 idt->cellrate_rcur = 0;
505 idt->cellrate_tcur = 0;
506 idt->txslots_max = 348; /* use n*348 for higher resolution */
507 idt->txslots_cur = 0;
508 nicstar_util_wr(idt, 0, 0x00, 0x00); /* synch (needed for
509 * 77105?) */
510 nicstar_util_wr(idt, 1, 0x00, 0x09); /* enable interrupts */
511 nicstar_util_wr(idt, 1, 0x02, 0x10); /* 77105 RFLUSH */
512 nicstar_util_rd(idt, 0x01, &t); /* read/clear interrupt flag */
513 } else {
514 idt->cellrate_rmax = 353207; /* 2075 slots of 1 DS0 each... */
515 idt->cellrate_tmax = 353207;
516 idt->cellrate_rcur = 0;
517 idt->cellrate_tcur = 0;
518 idt->txslots_max = 2075;
519 idt->txslots_cur = 0;
520
521 /* initialize the 155Mb SUNI */
522 nicstar_util_wr(idt, 0, 0x00, 0x00); /* sync utopia with SAR */
523 nicstar_util_wr(idt, 1, 0x00, 0x00); /* clear SW reset */
524 *regGP = 0x00000000; /* clear when done with SUNI changes */
525 }
526
527 #ifdef NICSTAR_TESTSRAM
528 /*
529 * this will work with 32K and 128K word RAM because the pattern
530 * repeats every 4 words
531 */
532 for (i = 0; i < 0x20000; i += 4)
533 (void)nicstar_sram_wr(idt, i, 4, 0xa5a5a5a5, 0x5a5a5a5a,
534 0xa5a5a5a5, 0x5a5a5a5a);
535 for (i = 0; i < 0x20000; i += 2) {
536 s1 = nicstar_sram_rd(idt, i, &x);
537 s2 = nicstar_sram_rd(idt, i + 1, &z);
538 if (s1 || s2 || x != 0xa5a5a5a5 || z != 0x5a5a5a5a) {
539 printf("sram fail1 %d 0x%08x 0x%08x\n", i, x, z);
540 break;
541 }
542 }
543 for (i = 0; i < 0x20000; i += 4)
544 (void)nicstar_sram_wr(idt, i, 4, 0x5a5a5a5a, 0xa5a5a5a5,
545 0x5a5a5a5a, 0xa5a5a5a5);
546 for (i = 0; i < 0x20000; i += 2) {
547 s1 = nicstar_sram_rd(idt, i, &z);
548 s2 = nicstar_sram_rd(idt, i + 1, &x);
549 if (s1 || s2 || x != 0xa5a5a5a5 || z != 0x5a5a5a5a) {
550 printf("sram fail2 %d 0x%08x 0x%08x\n", i, x, z);
551 break;
552 }
553 }
554 #endif
555
556 /* flush SRAM */
557 for (i = 0; i < 0x20000; i += 4)
558 (void)nicstar_sram_wr(idt, i, 4, 0, 0, 0, 0);
559
560 /*
561 * the memory map for the 32K word card has the
562 * addresses 0x8000, 0x10000, 0x18000 mapped back
563 * to address 0, and 0x8001, ..., 0x18001 is mapped
564 * to address 1. address 0x4000 is mapped to 0x1c000
565 */
566
567 /* write in the 0 word, see if we read it at 0x10000 */
568 (void)nicstar_sram_wr(idt, 0x0, 1, 0xa5a5a5a5, 0, 0, 0);
569 s1 = nicstar_sram_rd(idt, 0x10000, &x);
570 (void)nicstar_sram_wr(idt, 0x0, 1, 0, 0, 0, 0);
571 if (!s1 && x == 0xa5a5a5a5) {
572 device_printf(idt->dev, "32K words of RAM\n");
573 idt->sram = 0x4000;
574 } else {
575 device_printf(idt->dev, "128K words of RAM\n");
576 idt->sram = 0x10000;
577 }
578 #ifdef NICSTAR_FORCE32K
579 idt->sram = 0x4000;
580 device_printf(idt->dev, "forced to 32K words of RAM\n");
581 #endif
582
583 return;
584 }
585
586 /* Cellrate notes:
587 * The cellrate for OC3 is 353207.55, rounded down above. This makes
588 * 2075 slots of one DS0 (64003) each.
589 *
590 * The ATM25 rate is calculated from 25.6mb divided by 424 bits for
591 * cell plus 8 bits for "opcode" == 432 bits. 59259 * 432 = 25599888.
592 * This provides a 47-byte AAL1 bitrate of 22,281,384 bits/sec, or
593 * 348 slots of one DS0 (64027) each. If 8khz synch events are to
594 * be sent, then only 347 slots are available.
595 *
596 ******************************************************************************
597 *
598 * Physical layer detect
599 *
600 * in: IDT device
601 * out: zero = LE155, NZ = LE25
602 *
603 * Date first: 10/30/2000 last: 06/08/2001
604 */
605
606 int
607 idt_phys_detect(IDT * idt)
608 {
609 u_long t;
610 int retval;
611
612 retval = 0;
613
614 nicstar_util_wr(idt, 0, 0x00, 0x00); /* synch (needed for 77105?) */
615 nicstar_util_rd(idt, 0x00, &t); /* get Master Control Register */
616
617 switch (t) {
618 /* 25.6 Mbps ATM PHY with TC & PMD */
619 /* http://www.idt.com/products/pages/ATM_Products-77105.html */
620 case 0x09:
621 device_printf(idt->dev, "ATM card is Fore LE25, PHY=77105\n");
622 idt->hardware = "ATM25/77105";
623 retval = 1;
624 break;
625
626 /* S/UNI-155-LITE */
627 /* http://www.pmc-sierra.com/products/details/pm5346/index.html */
628 case 0x30:
629 device_printf(idt->dev, "ATM card is Fore LE155 or IDT, PHY=PM5346\n");
630 idt->hardware = "ATM155/PM5346";
631 break;
632
633 /* S/UNI-155-ULTRA */
634 /* http://www.pmc-sierra.com/products/details/pm5350/index.html */
635 case 0x31:
636 case 0x70:
637 case 0x78:
638 device_printf(idt->dev, "ATM card is Fore LE155, PHY=PM5350\n");
639 idt->hardware = "ATM155/PM5350";
640 break;
641
642 default:
643 device_printf(idt->dev,
644 "cannot figure out card type, assuming LE155 (reg=%d).\n",
645 (int)t);
646 idt->hardware = "unknown (LE155?)";
647 break;
648 }
649 return (retval);
650 }
651
652 /* Register 0 values:
653 * 77105 = 0x09
654 * PM5346 = 0x30
655 * PM5250 = 0x31 (actually observed)
656 * PM5350 = 0x70 or 0x78 (according to docs)
657 *
658 ******************************************************************************
659 *
660 * Initialize the data structures
661 */
662
663 void
664 nicstar_init(nicstar_reg_t * const idt)
665 {
666 int i;
667 vm_offset_t buf;
668 u_long *p;
669
670 idt_connect_init(idt, 0); /* initialize for 0 VPI bits (12 VCI
671 * bits) */
672
673 /* allocate space for TSQ, RSQ, SCD for VBR,ABR, UBR */
674 idt->fixbuf = (vm_offset_t)contigmalloc(NICSTAR_FIXPAGES * PAGE_SIZE,
675 M_DEVBUF, M_NOWAIT | M_ZERO, 0x100000, 0xffffffff, 0x2000, 0);
676 if (idt->fixbuf == 0)
677 return; /* no space card disabled */
678
679 if (idt_buffer_init(idt)) /* allocate large buffers */
680 goto freemem; /* free memory and return */
681
682 if (idt_mcheck_init(idt))
683 goto freemem;
684
685 idt_found++; /* number of cards found on machine */
686
687 if (bootverbose) {
688 printf("nicstar: buffer size %d\n", 0);
689 }
690 idt_queue_init(idt); /* initialize all TX_QUEUE structures */
691 idt_slots_init(idt); /* initialize CBR table slots */
692
693 /* initialize variable rate mbuf queues */
694
695 /* TSQ initialization */
696 for (p = (u_long *)idt->fixbuf; p < (u_long *)(idt->fixbuf + 0x2000);) {
697 *p++ = 0x00000000;
698 *p++ = 0x80000000; /* set empty bit */
699 }
700
701 buf = vtophys(idt->fixbuf);
702 /* Transmit Status Queue Base */
703 *(volatile u_long *)(idt->virt_baseaddr + REGTSQB) = buf;
704 /* Transmit Status Queue Head */
705 *(volatile u_long *)(idt->virt_baseaddr + REGTSQH) = 0; /* 8k aligned */
706 idt->tsq_base = (u_long *)idt->fixbuf;
707 idt->tsq_head = (u_long *)idt->fixbuf;
708 idt->tsq_size = 1024;
709
710 /* Recieve Status Queue Base */
711 *(volatile u_long *)(idt->virt_baseaddr + REGRSQB) = buf + 0x2000;
712 /* Transmit Status Queue Head */
713 *(volatile u_long *)(idt->virt_baseaddr + REGRSQH) = 0; /* 8k aligned */
714 idt->rsqh = 0;
715
716
717 /* Now load receive buffers into SRAM */
718 nicstar_ld_rcv_buf(idt);
719
720 /* load variable SCQ */
721 (void)nicstar_sram_wr(idt, 0x1e7dc, 4, (u_long)(buf + 0x8000), 0,
722 0xffffffff, 0); /* SD2 */
723 (void)nicstar_sram_wr(idt, 0x1e7e0, 4, 0, 0, 0, 0);
724 (void)nicstar_sram_wr(idt, 0x1e7e4, 4, 0, 0, 0, 0);
725
726 (void)nicstar_sram_wr(idt, 0x1e7e8, 4, (u_long)(buf + 0x6000), 0,
727 0xffffffff, 0); /* SD1 */
728 (void)nicstar_sram_wr(idt, 0x1e7ec, 4, 0, 0, 0, 0);
729 (void)nicstar_sram_wr(idt, 0x1e7f0, 4, 0, 0, 0, 0);
730
731 (void)nicstar_sram_wr(idt, 0x1e7f4, 4, (u_long)(buf + 0x4000), 0,
732 0xffffffff, 0); /* SD0 */
733 (void)nicstar_sram_wr(idt, 0x1e7f8, 4, 0, 0, 0, 0);
734 (void)nicstar_sram_wr(idt, 0x1e7fc, 4, 0, 0, 0, 0);
735
736 /* initialize RCT */
737 for (i = 0; i < idt->sram; i += 4) { /* XXX ifdef table size */
738 nicstar_sram_wr(idt, i, 4, 0x0, 0x0, 0x0, 0xffffffff);
739 }
740
741 /* VPI/VCI mask is 0 */
742 *(volatile u_long *)(idt->virt_baseaddr + REGVMSK) = 0;
743
744 /* Set the Transmit Schedule Table base address */
745 *(volatile u_long *)(idt->virt_baseaddr + REGTSTB) = IDT_TST_START;
746
747
748 /* Configuration Register settings:
749 * Bit(s) Meaning value
750 * 31 Software reset 0
751 * 30 RESERVED 0
752 * 29 Recieve Enabled 1
753 * 28-27 Small Buffer Size (host memory) 01 (96 bytes)
754 * 26-25 Large Buffer Size (host memory) 00 (2048 bytes)
755 * 24 Interrupt on empty free buffer queue 1
756 *
757 * 23-22 Recieve Status Queue Size (host memory) 10 (8192 bytes)
758 * 21 Accpect Invalid cells into Raw Queue 1
759 * 20 Ignore General Flow control 1
760 *
761 * 19-18 VPI/VCI Select 00
762 * 17-16 Recieve Connect Table Size 00 (32K SRAM)
763 * 10 (128K SRAM)
764 *
765 * 15 Accpect non-open VPI/VCI to Raw Queue 1
766 * 14-12 time to delay after Rx and interrupt 001 (0us)
767 *
768 * 11 Interrupt when a Raw Cell is added 1
769 * 10 Interrupt when Recieve Queue near full 1
770 * 9 Recieve RM (PTI = 110 or 111) 1
771 * 8 RESERVED 0
772 *
773 * 7 Interrupt on Timer rollover 1
774 * 6 RESERVED 0
775 * 5 Transmit Enabled 1
776 * 4 Interrupt on Transmit Status Indicator 1
777 *
778 * 3 Interrupt on transmit underruns 1
779 * 2 UTOPIA cell/byte mode 0 (cell)
780 * 1 Interrupt on nearly full TSQ 1
781 * 0 Enable Physical Interrupt 1
782 */
783
784 /* original values: 0x31b09ebb and 0x31b29eb */
785 /*
786 * 11/01/2000: changed from 0x31b09eb to 0x29b09eb for 96-byte
787 * sm-buf
788 */
789
790 if (idt->sram == 0x4000)/* 32K */
791 *(volatile u_long *)(idt->virt_baseaddr + REGCFG) = 0x29b09ebb;
792 else /* 128K */
793 *(volatile u_long *)(idt->virt_baseaddr + REGCFG) = 0x29b29ebb;
794
795 return;
796
797 freemem:
798 /* free memory and return */
799 idt_release_mem(idt);
800 device_printf(idt->dev, "cannot allocate memory\n");
801 return; /* no space card disabled */
802 }
803
804 /******************************************************************************
805 *
806 * Release all allocated memory
807 *
808 * in: IDT device
809 *
810 * Date first: 11/14/2000 last: 11/14/2000
811 */
812
813 void
814 idt_release_mem(IDT * idt)
815 {
816 if (idt->fixbuf != 0)
817 kmem_free(kernel_map, idt->fixbuf,
818 (NICSTAR_FIXPAGES * PAGE_SIZE));
819
820 if (idt->cbr_base != 0)
821 kmem_free(kernel_map, (vm_offset_t)idt->cbr_base, idt->cbr_size);
822
823 printf("%s() is NOT SAFE!\n", __func__);
824
825 /* we also have idt->connection and idt->mcheck to do as well... */
826 }
827
828 /******************************************************************************
829 *
830 * Write one to four words to SRAM
831 *
832 * writes one to four words into sram starting at "sram_location"
833 *
834 * returns -1 if sram location is out of range.
835 * returns count, if count is not in the range from 1-4.
836 * returns 0 if parameters were acceptable
837 */
838
839 static int
840 nicstar_sram_wr(nicstar_reg_t * const idt, u_long address, int count,
841 u_long data0, u_long data1, u_long data2, u_long data3)
842 {
843 if (address >= 0x20000) /* bad address */
844 return (-1);
845
846 if (idt_status_wait(idt)) /* 12/06/2000 */
847 return (-1);
848
849 switch (--count) {
850 case 3:
851 *(idt->reg_data + 3) = data3; /* drop down to do others */
852 case 2:
853 *(idt->reg_data + 2) = data2; /* drop down to do others */
854 case 1:
855 *(idt->reg_data + 1) = data1; /* drop down to do others */
856 case 0:
857 *idt->reg_data = data0; /* load last data item */
858 break; /* done loading values */
859 default:
860 return (count); /* nothing to do */
861 }
862 /* write the word(s) */
863 *idt->reg_cmd = 0x40000000 | (address << 2) | count;
864
865 return (0);
866 }
867
868 /* 05/31/2001: Removed wait between data register(s) and write command.
869 * The docs do not state it is helpful, and the example only has one
870 * wait, before the data register load. The wait time is very high -
871 * aproximately 6 microseconds per wait.
872 *
873 ******************************************************************************
874 *
875 * Read one word from SRAM
876 *
877 * reads one word of sram at "sram_location" and places the value
878 * in "answer_pointer"
879 *
880 * returns -1 if sram location is out of range.
881 * returns 0 if parameters were acceptable
882 */
883 static int
884 nicstar_sram_rd(nicstar_reg_t * const idt, u_long address, u_long *data0)
885 {
886 if (address >= 0x20000) /* bad address */
887 return (-1);
888
889 if (idt_status_wait(idt))
890 return (-1);
891
892 *idt->reg_cmd = 0x50000000 | (address << 2); /* read a word */
893
894 if (idt_status_wait(idt))
895 return (-1);
896
897 *data0 = *idt->reg_data;/* save word */
898
899 return (0);
900 }
901
902 /*******************************************************************************
903 *
904 * Open or Close connection in IDT Receive Connection Table
905 *
906 * in: IDT device, VPI, VCI, opflag (0 = close, 1 = open)
907 * out: zero = success
908 *
909 * Date first: 12/14/2000 last: 12/14/2000
910 */
911
912 int
913 idt_connect_opencls(IDT * idt, CONNECTION * connection, int opflag)
914 {
915 int address;
916 int word1;
917
918 if (connection->vpi >= idt->conn_maxvpi ||
919 connection->vci >= idt->conn_maxvci)
920 return (1);
921
922 address = connection->vpi * idt->conn_maxvci + connection->vci;
923 address <<= 2; /* each entry is 4 words */
924
925 if (opflag) {
926 switch (connection->aal) {
927 case ATM_AAL0:
928 word1 = 0x00038000;
929 break; /* raw cell queue */
930 case ATM_AAL1:
931 word1 = 0x00008000;
932 break; /* Nicstar "AAL0" */
933 case ATM_AAL3_4:
934 word1 = 0x00018000;
935 break;
936 case ATM_AAL5:
937 word1 = 0x00028000;
938 break;
939 default:
940 return (1);
941 }
942 nicstar_sram_wr(idt, address, 4, word1, 0, 0, 0xffffffff);
943 opflag = 0x00080000; /* bit-19 set or clear */
944 }
945 if (idt_status_wait(idt))
946 return (1);
947
948 *idt->reg_cmd = 0x20000000 | opflag | address << 2;
949 return (0);
950 }
951
952 /*******************************************************************************
953 *
954 * nicstar_add_buf ( card, mbuf1, mbuf2, which_queue)
955 *
956 * This adds two buffers to the specified queue. This uses the
957 * mbuf address as handle and the buffer physical address must be
958 * the DMA address.
959 *
960 * returns -1 if queue is full, the address is not word aligned, or
961 * an invalid queue is specified.
962 * returns 0 if parameters were acceptable.
963 */
964
965 int
966 nicstar_add_buf(nicstar_reg_t * const idt, struct mbuf * buf0,
967 struct mbuf * buf1, u_long islrg)
968 {
969 u_long stat_val;
970 u_long val0, val1, val2, val3;
971
972 if (islrg > 1) /* bad buffer size */
973 return (-1);
974
975 stat_val = *idt->reg_stat;
976
977 if (islrg) {
978 if (stat_val & 0x80) /* large queue is full */
979 return (-1);
980 } else if (stat_val & 0x100) /* small queue is full */
981 return (-1);
982
983 if (!buf0 || !buf1 || ((u_long)(buf0->m_data) & 0x7)
984 || ((u_long)(buf1->m_data) & 0x7)) {
985 return (-1); /* buffers must word aligned */
986 }
987 if (idt->raw_headm == NULL) /* raw cell buffer pointer not
988 * initialized */
989 if (islrg) {
990 idt->raw_headm = buf0;
991 idt->raw_headp = vtophys(buf0->m_data);
992 }
993 if (idt_status_wait(idt)) /* 12/06/2000 */
994 return (-1);
995
996 val0 = (u_long)buf0; /* mbuf address is handle */
997 val1 = vtophys(buf0->m_data); /* DMA addr of buff1 */
998 val2 = (u_long)buf1; /* mbuf address is handle */
999 val3 = vtophys(buf1->m_data); /* DMA addr of buff2 */
1000
1001 *(idt->reg_data + 0) = val0;
1002 *(idt->reg_data + 1) = val1;
1003 *(idt->reg_data + 2) = val2;
1004 *(idt->reg_data + 3) = val3;
1005
1006 *idt->reg_cmd = 0x60000000 | islrg;
1007
1008 idt_mcheck_add(idt, buf0);
1009 idt_mcheck_add(idt, buf1);
1010
1011 return (0);
1012 }
1013
1014 /******************************************************************************
1015 *
1016 * nicstar_util_rd ( card, util_location, answer_pointer )
1017 *
1018 * reads one byte from the utility bus at "util_location" and places the
1019 * value in "answer_pointer"
1020 *
1021 * returns -1 if util location is out of range.
1022 * returns 0 if parameters were acceptable
1023 */
1024 static int
1025 nicstar_util_rd(nicstar_reg_t * const idt, u_long address, u_long *data)
1026 {
1027
1028 if (address >= 0x81) /* bad address */
1029 return (-1);
1030
1031 if (idt_status_wait(idt))
1032 return (-1);
1033
1034 *idt->reg_cmd = 0x80000200 | address; /* read a word */
1035
1036 if (idt_status_wait(idt))
1037 return (-1);
1038
1039 *data = *idt->reg_data & 0xff; /* save word */
1040
1041 return (0);
1042 }
1043
1044 /******************************************************************************
1045 *
1046 * nicstar_util_wr ( card, util location, data )
1047 *
1048 * writes one byte to the utility bus at "util_location"
1049 *
1050 * returns -1 if util location is out of range.
1051 * returns 0 if parameters were acceptable
1052 */
1053 static int
1054 nicstar_util_wr(nicstar_reg_t * const idt, int cs, u_long address, u_long data)
1055 {
1056
1057 if (address >= 0x81) /* bad address */
1058 return (-1);
1059 if (cs > 1)
1060 return (-1);
1061
1062 if (idt_status_wait(idt))
1063 return (-1);
1064
1065 *idt->reg_data = data & 0xff; /* load last data item */
1066
1067 if (cs == 0)
1068 *idt->reg_cmd = 0x90000100 | address; /* write the byte, CS1 */
1069 else
1070 *idt->reg_cmd = 0x90000200 | address; /* write the byte, CS2 */
1071
1072 return (0);
1073 }
1074
1075 /******************************************************************************
1076 *
1077 * nicstar_eeprom_rd ( card , byte_location )
1078 *
1079 * reads one byte from the utility bus at "byte_location" and return the
1080 * value as an integer. this routint is only used to read the MAC address
1081 * from the EEPROM at boot time.
1082 */
1083 int
1084 nicstar_eeprom_rd(nicstar_reg_t * const idt, u_long address)
1085 {
1086 volatile u_long *regGP = (volatile u_long *)(idt->virt_baseaddr + REGGP);
1087 volatile u_long gp = *regGP & 0xfffffff0;
1088 int i, value = 0;
1089
1090 DELAY(5); /* make sure idle */
1091 *regGP = gp | 0x06; /* CS and Clock high */
1092 DELAY(5);
1093 *regGP = gp; /* CS and Clock low */
1094 DELAY(5);
1095 /* toggle in READ CMD (00000011) */
1096 *regGP = gp | 0x04; /* Clock high (data 0) */
1097 DELAY(5);
1098 *regGP = gp; /* CS and Clock low */
1099 DELAY(5);
1100 *regGP = gp | 0x04; /* Clock high (data 0) */
1101 DELAY(5);
1102 *regGP = gp; /* CS and Clock low */
1103 DELAY(5);
1104 *regGP = gp | 0x04; /* Clock high (data 0) */
1105 DELAY(5);
1106 *regGP = gp; /* CS and Clock low */
1107 DELAY(5);
1108 *regGP = gp | 0x04; /* Clock high (data 0) */
1109 DELAY(5);
1110 *regGP = gp; /* CS and Clock low */
1111 DELAY(5);
1112 *regGP = gp | 0x04; /* Clock high (data 0) */
1113 DELAY(5);
1114 *regGP = gp; /* CS and Clock low */
1115 DELAY(5);
1116 *regGP = gp | 0x04; /* Clock high (data 0) */
1117 DELAY(5);
1118 *regGP = gp | 0x01; /* CS and Clock low data 1 */
1119 DELAY(5);
1120 *regGP = gp | 0x05; /* Clock high (data 1) */
1121 DELAY(5);
1122 *regGP = gp | 0x01; /* CS and Clock low data 1 */
1123 DELAY(5);
1124 *regGP = gp | 0x05; /* Clock high (data 1) */
1125 DELAY(5);
1126 /* toggle in the address */
1127 for (i = 7; i >= 0; i--) {
1128 *regGP = (gp | ((address >> i) & 1)); /* Clock low */
1129 DELAY(5);
1130 *regGP = (gp | 0x04 | ((address >> i) & 1)); /* Clock high */
1131 DELAY(5);
1132 }
1133 /* read EEPROM data */
1134 for (i = 7; i >= 0; i--) {
1135 *regGP = gp; /* Clock low */
1136 DELAY(5);
1137 value |= ((*regGP & 0x10000) >> (16 - i));
1138 *regGP = gp | 0x04; /* Clock high */
1139 DELAY(5);
1140 }
1141 *regGP = gp; /* CS and Clock low */
1142 return (value);
1143 }
1144
1145 /*******************************************************************************
1146 *
1147 * Load the card receive buffers
1148 *
1149 * in: IDT device
1150 *
1151 * Date first: 11/01/2000 last: 05/25/2000
1152 */
1153
1154 void
1155 nicstar_ld_rcv_buf(IDT * idt)
1156 {
1157 struct mbuf *m1, *m2;
1158 u_long stat_reg;
1159 int card_small;
1160 int card_large;
1161 int s;
1162
1163 s = splimp();
1164
1165 stat_reg = *(volatile u_long *)idt->stat_reg;
1166
1167 card_small = (stat_reg & 0xff000000) >> 23; /* reg is number of
1168 * pairs */
1169 card_large = (stat_reg & 0x00ff0000) >> 15;
1170
1171 if (idt_sysctl_bufsmall > 510)
1172 idt_sysctl_bufsmall = 510;
1173 if (idt_sysctl_buflarge > 510)
1174 idt_sysctl_buflarge = 510;
1175 if (idt_sysctl_bufsmall < 10)
1176 idt_sysctl_bufsmall = 10;
1177 if (idt_sysctl_buflarge < 10)
1178 idt_sysctl_buflarge = 10;
1179
1180 while (card_small < idt_sysctl_bufsmall) { /* 05/25/2001 from fixed */
1181 MGETHDR(m1, M_DONTWAIT, MT_DATA);
1182 if (m1 == NULL)
1183 break;
1184 MGETHDR(m2, M_DONTWAIT, MT_DATA);
1185 if (m2 == NULL) {
1186 m_free(m1);
1187 break;
1188 }
1189 MH_ALIGN(m1, 96); /* word align & allow lots of
1190 * prepending */
1191 MH_ALIGN(m2, 96);
1192 if (nicstar_add_buf(idt, m1, m2, 0)) {
1193 device_printf(idt->dev,
1194 "Cannot add small buffers, size=%d.\n",
1195 card_small);
1196 m_free(m1);
1197 m_free(m2);
1198 break;
1199 }
1200 card_small += 2;
1201 }
1202
1203 while (card_large < idt_sysctl_buflarge) { /* 05/25/2001 from fixed */
1204 m1 = idt_mbufcl_get();
1205 if (m1 == NULL)
1206 break;
1207 m2 = idt_mbufcl_get();
1208 if (m2 == NULL) {
1209 m_free(m1);
1210 break;
1211 }
1212 if (nicstar_add_buf(idt, m1, m2, 1)) {
1213 device_printf(idt->dev,
1214 "Cannot add large buffers, size=%d.\n",
1215 card_large);
1216 m_free(m1);
1217 m_free(m2);
1218 break;
1219 }
1220 card_large += 2;
1221 }
1222 idt_sysctl_curlarge = card_large;
1223 idt_sysctl_cursmall = card_small;
1224
1225 splx(s);
1226 }
1227
1228 /*******************************************************************************
1229 *
1230 * Wait for command to finish
1231 *
1232 * in: IDT device
1233 * out: zero = success
1234 *
1235 * Date first: 12/06/2000 last: 12/16/2000
1236 */
1237
1238 int
1239 idt_status_wait(IDT * idt)
1240 {
1241 int timeout;
1242
1243 timeout = 33 * 100; /* allow 100 microseconds timeout */
1244
1245 while (*idt->reg_stat & 0x200)
1246 if (--timeout == 0) {
1247 device_printf(idt->dev,
1248 "timeout waiting for device status.\n");
1249 idt->stats_cmderrors++;
1250 return (1);
1251 }
1252 return (0);
1253 }
1254
1255 /*******************************************************************************
1256 *
1257 * Log status of system buffers
1258 *
1259 * in: IDT device
1260 *
1261 * Date first: 10/31/2000 last: 05/25/2001
1262 */
1263
1264 void
1265 idt_status_bufs(IDT * idt)
1266 {
1267 u_long stat_reg;
1268 int card_small;
1269 int card_large;
1270 int s;
1271
1272 s = splimp();
1273
1274 stat_reg = *(volatile u_long *)idt->stat_reg;
1275
1276 card_small = (stat_reg & 0xff000000) >> 23; /* reg is number of
1277 * pairs */
1278 card_large = (stat_reg & 0x00ff0000) >> 15;
1279
1280 splx(s);
1281
1282 device_printf(idt->dev, "BUFFER STATUS: small=%d/%d, large=%d/%d.\n",
1283 card_small, idt_sysctl_bufsmall,
1284 card_large, idt_sysctl_buflarge);
1285 }
1286
1287 /* Since this is called when the card timer wraps, we should only see
1288 * this 16 times (LE155) or 10 (LE25) per hour.
1289 *
1290 *******************************************************************************
1291 *
1292 * Add mbuf into "owned" list
1293 *
1294 * in: IDT device, mbuf
1295 * out: zero = success
1296 *
1297 * Date first: 11/13/2000 last: 11/13/2000
1298 */
1299
1300 int
1301 idt_mcheck_add(IDT * idt, struct mbuf * m)
1302 {
1303 int hpos;
1304 int s;
1305
1306 hpos = (((int)m) >> 8) & 1023;
1307 s = splimp();
1308
1309 m->m_next = idt->mcheck[hpos];
1310 idt->mcheck[hpos] = m;
1311
1312 splx(s);
1313 return (0);
1314 }
1315
1316 /******************************************************************************
1317 *
1318 * Remove mbuf from "owned" list
1319 *
1320 * in: IDT device, mbuf
1321 * out: zero = success
1322 *
1323 * Date first: 11/13/2000 last: 11/13/2000
1324 */
1325
1326 int
1327 idt_mcheck_rem(IDT * idt, struct mbuf * m)
1328 {
1329 struct mbuf *nbuf;
1330 int hpos;
1331 int s;
1332
1333 hpos = (((int)m) >> 8) & 1023;
1334 s = splimp();
1335
1336 nbuf = idt->mcheck[hpos];
1337
1338 if (nbuf == m) {
1339 idt->mcheck[hpos] = m->m_next;
1340 splx(s);
1341 m->m_next = NULL;
1342 return (0);
1343 }
1344 while (nbuf != NULL) {
1345 if (nbuf->m_next != m) {
1346 nbuf = nbuf->m_next;
1347 continue;
1348 }
1349 nbuf->m_next = m->m_next;
1350 splx(s);
1351 m->m_next = NULL;
1352 return (0);
1353 }
1354
1355 splx(s);
1356 device_printf(idt->dev, "Card should not have this mbuf! %x\n", (int)m);
1357 return (1);
1358 }
1359
1360 /******************************************************************************
1361 *
1362 * Initialize mbuf "owned" list
1363 *
1364 * in: IDT device
1365 * out: zero = success
1366 *
1367 * Date first: 11/13/2000 last: 05/26/2001
1368 */
1369
1370 int
1371 idt_mcheck_init(IDT * idt)
1372 {
1373 int size;
1374 int x;
1375
1376 size = round_page(sizeof(struct mbuf *) * 1024);
1377 idt->mcheck = contigmalloc(size, M_DEVBUF, M_NOWAIT,
1378 0x100000, 0xffffffff, 0x2000, 0);
1379 if (idt->mcheck == NULL)
1380 return (1);
1381
1382 for (x = 0; x < 1024; x++)
1383 idt->mcheck[x] = NULL;
1384
1385 return (0);
1386 }
1387
1388 /******************************************************************************
1389 *
1390 * Allocate contiguous, fixed memory
1391 *
1392 * in: number of pages
1393 * out: pointer, NULL = failure
1394 *
1395 * Date first: 11/29/2000 last: 11/29/2000
1396 */
1397
1398 vm_offset_t
1399 idt_malloc_contig(int pages)
1400 {
1401 vm_offset_t retval;
1402
1403 retval = (vm_offset_t)contigmalloc(pages * PAGE_SIZE,
1404 M_DEVBUF, M_NOWAIT, 0x100000, 0xffffffff, 0x2000, 0);
1405 #ifdef UNDEF
1406 printf("idt: vm_offset_t allocated %d pages at %x\n", pages, retval);
1407 #endif
1408
1409 return (retval);
1410 }
1411
1412 /*******************************************************************************
1413 *
1414 * Initialize all TX_QUEUE structures
1415 *
1416 * in: IDT device
1417 * out: zero = succes
1418 *
1419 * Date first: 11/29/2000 last: 11/29/2000
1420 */
1421 static int
1422 idt_queue_init(IDT * idt)
1423 {
1424 TX_QUEUE *txqueue;
1425 vm_offset_t scqbase;
1426 int x;
1427
1428 idt->cbr_size = IDT_MAX_CBRQUEUE * 16 * 64;
1429 idt->cbr_base = idt_malloc_contig(idt->cbr_size / PAGE_SIZE);
1430 scqbase = idt->cbr_base;
1431 if (scqbase == 0)
1432 return (1);
1433 idt->cbr_freect = idt->cbr_size / (16 * 64);
1434
1435 for (x = 0; x < idt->cbr_freect; x++) {
1436 txqueue = &idt->cbr_txqb[x];
1437 txqueue->mget = NULL;
1438 txqueue->mput = NULL;
1439 txqueue->scd = IDT_SCD_START + x * 12;
1440 txqueue->scq_base = (u_long *)scqbase;
1441 txqueue->scq_next = txqueue->scq_base;
1442 txqueue->scq_last = txqueue->scq_next;
1443 txqueue->scq_len = 64; /* all CBR queues use 64 entries */
1444 txqueue->scq_cur = 0;
1445 txqueue->rate = 0;
1446 txqueue->vbr_m = 0; /* m & n set to zero for CBR */
1447 txqueue->vbr_n = 0;
1448 idt->cbr_free[x] = txqueue;
1449 scqbase += 64 * 16;
1450 nicstar_sram_wr(idt, txqueue->scd, 4,
1451 vtophys(txqueue->scq_base), 0, 0xffffffff, 0);
1452 }
1453
1454 txqueue = &idt->queue_vbr; /* VBR queue */
1455 txqueue->mget = NULL;
1456 txqueue->mput = NULL;
1457 txqueue->scd = 0x1e7f4;
1458 txqueue->scq_base = (u_long *)(idt->fixbuf + 0x4000);
1459 txqueue->scq_next = txqueue->scq_base;
1460 txqueue->scq_last = txqueue->scq_next;
1461 txqueue->scq_len = 512; /* all VBR queues use 512 entries */
1462 txqueue->scq_cur = 0;
1463 txqueue->rate = 0;
1464 txqueue->vbr_m = 1;
1465 txqueue->vbr_n = 1;
1466 nicstar_sram_wr(idt, txqueue->scd, 4,
1467 vtophys(txqueue->scq_base), 0, 0xffffffff, 0);
1468
1469 txqueue = &idt->queue_abr; /* ABR queue (not currently used) */
1470 txqueue->mget = NULL;
1471 txqueue->mput = NULL;
1472 txqueue->scd = 0x1e7e8;
1473 txqueue->scq_base = (u_long *)(idt->fixbuf + 0x6000);
1474 txqueue->scq_next = txqueue->scq_base;
1475 txqueue->scq_last = txqueue->scq_next;
1476 txqueue->scq_len = 512;
1477 txqueue->scq_cur = 0;
1478 txqueue->rate = 0;
1479 txqueue->vbr_m = 1;
1480 txqueue->vbr_n = 1;
1481 nicstar_sram_wr(idt, txqueue->scd, 4,
1482 vtophys(txqueue->scq_base), 0, 0xffffffff, 0);
1483
1484 txqueue = &idt->queue_ubr; /* UBR queue */
1485 txqueue->mget = NULL;
1486 txqueue->mput = NULL;
1487 txqueue->scd = 0x1e7dc;
1488 txqueue->scq_base = (u_long *)(idt->fixbuf + 0x8000);
1489 txqueue->scq_next = txqueue->scq_base;
1490 txqueue->scq_last = txqueue->scq_next;
1491 txqueue->scq_len = 512;
1492 txqueue->scq_cur = 0;
1493 txqueue->rate = 0;
1494 txqueue->vbr_m = 1; /* since the ABR queue is lowest priority, */
1495 txqueue->vbr_n = 1; /* these factors should never change */
1496 nicstar_sram_wr(idt, txqueue->scd, 4,
1497 vtophys(txqueue->scq_base), 0, 0xffffffff, 0);
1498
1499 return (0);
1500 }
1501
1502 /*******************************************************************************
1503 *
1504 * Get mbuf chain from TX_QUEUE
1505 *
1506 * in: CONNECTION
1507 * out: mbuf, NULL = empty
1508 *
1509 * Date first: 12/03/2000 last: 12/03/2000
1510 */
1511 static struct mbuf *
1512 idt_queue_get(TX_QUEUE * txqueue)
1513 {
1514 struct mbuf *m1, *m2;
1515 int s;
1516
1517 if (txqueue == NULL)
1518 return (NULL);
1519
1520 s = splimp();
1521
1522 m1 = txqueue->mget;
1523 if (m1 != NULL) {
1524 m2 = m1->m_nextpkt;
1525 txqueue->mget = m2;
1526 if (m2 == NULL) /* is queue empty now? */
1527 txqueue->mput = NULL;
1528 }
1529 splx(s);
1530
1531 return (m1);
1532 }
1533
1534 /*******************************************************************************
1535 *
1536 * Add mbuf chain to connection TX_QUEUE
1537 *
1538 * in: CONNECTION, mbuf chain
1539 * out: zero = succes
1540 *
1541 * Date first: 12/03/2000 last: 06/01/2001
1542 */
1543 static int
1544 idt_queue_put(CONNECTION * connection, struct mbuf * m)
1545 {
1546 TX_QUEUE *txqueue;
1547 int s;
1548
1549 if (connection == NULL) {
1550 m_freem(m);
1551 return (1);
1552 }
1553 txqueue = connection->queue;
1554 if (txqueue == NULL) {
1555 m_freem(m);
1556 return (1);
1557 }
1558 m->m_nextpkt = NULL;
1559 m->m_pkthdr.rcvif = (struct ifnet *) connection;
1560
1561 s = splimp();
1562
1563 if (txqueue->mput != NULL) {
1564 *txqueue->mput = m;
1565 txqueue->mput = &m->m_nextpkt;
1566 } else { /* queue is empty */
1567 txqueue->mget = m;
1568 txqueue->mput = &m->m_nextpkt;
1569 }
1570 splx(s);
1571
1572 return (0);
1573 }
1574
1575 /*******************************************************************************
1576 *
1577 * Flush all connection mbufs from TX_QUEUE
1578 *
1579 * in: CONNECTION
1580 * out: zero = succes
1581 *
1582 * Date first: 12/03/2000 last: 12/03/2000
1583 */
1584 static int
1585 idt_queue_flush(CONNECTION * connection)
1586 {
1587 TX_QUEUE *txqueue;
1588 struct mbuf **m0, *m1;
1589 int s;
1590
1591 if (connection == NULL)
1592 return (1);
1593 txqueue = connection->queue;
1594 if (txqueue == NULL)
1595 return (1);
1596
1597 s = splimp();
1598
1599 m0 = &txqueue->mget;
1600 m1 = *m0;
1601 while (m1 != NULL) {
1602 if (m1->m_pkthdr.rcvif == (struct ifnet *) connection) {
1603 *m0 = m1->m_nextpkt;
1604 m_freem(m1);
1605 m1 = *m0;
1606 continue;
1607 }
1608 m0 = &m1->m_nextpkt;
1609 m1 = *m0;
1610 }
1611 txqueue->mput = m0;
1612 splx(s);
1613
1614 return (0);
1615 }
1616
1617 /*******************************************************************************
1618 *
1619 * Calculate number of table positions for CBR connection
1620 *
1621 * in: IDT device, PCR (cells/second)
1622 * out: table positions needed (minimum = 1)
1623 *
1624 * Date first: 11/29/2000 last: 06/12/2001
1625 */
1626 int
1627 idt_slots_cbr(IDT * idt, int pcr)
1628 {
1629 unsigned int bitrate;
1630 unsigned int slots;
1631 unsigned int rem;
1632
1633 if (pcr == 171) {
1634 if (idt_sysctl_logvcs)
1635 device_printf(idt->dev,
1636 "idt_slots_cbr: CBR channel=64000, 1 slot\n");
1637 return (1);
1638 }
1639 if (pcr < 171) {
1640 if (idt_sysctl_logvcs)
1641 device_printf(idt->dev,
1642 "idt_slots_cbr: CBR pcr %d rounded up to 1 slot\n", pcr);
1643 return (1);
1644 }
1645 bitrate = pcr * 47 * 8;
1646 slots = bitrate / 64000;
1647 rem = bitrate % 64000;
1648 if (rem && idt_sysctl_logvcs)
1649 device_printf(idt->dev,
1650 "idt_slots_cbr: CBR cell rate rounded down to %d from %d\n",
1651 ((slots * 64000) / 376), pcr); /* slots++; */
1652
1653 if (idt_sysctl_logvcs)
1654 device_printf(idt->dev,
1655 "idt_slots_cbr: CBR pcr=%d, slots=%d.\n", pcr, slots);
1656 return (slots);
1657 }
1658
1659 /* The original algorithm rounded up or down by 32k, the goal being to
1660 * map 64000 requests exactly. Unfortunately, this caused one particular
1661 * SVC to be set one slot too low, causing mbuf cluster starvation.
1662 * We can still handle the single 64k channel with a special case, and
1663 * let all others fall where they may.
1664 *
1665 *******************************************************************************
1666 *
1667 * Add TX QUEUE pointer to slots in CBR table
1668 *
1669 * in: IDT device, TX_QUEUE, number slots
1670 * out: zero = success
1671 *
1672 * Date first: 11/29/2000 last: 06/11/2001
1673 */
1674 static int
1675 idt_slots_add(IDT * idt, TX_QUEUE * queue, int slots)
1676 {
1677 TX_QUEUE *curval;
1678 int p_max; /* extra precision slots maximum */
1679 int p_spc; /* extra precision spacing value */
1680 int p_ptr; /* extra precision pointer */
1681 int qptr, qmax;
1682 int qlast;
1683 int scdval;
1684
1685 if (slots < 1)
1686 return (1);
1687
1688 qmax = idt->txslots_max;
1689 p_max = qmax << 8;
1690 p_spc = p_max / slots;
1691 p_ptr = p_spc >> 1; /* use half spacing for start point */
1692 qptr = p_ptr >> 8;
1693 qlast = qptr;
1694
1695 scdval = 0x20000000 | queue->scd;
1696
1697 if (CBR_VERBOSE) {
1698 printf("idt_slots_add: p_max = %d\n", p_max);
1699 printf("idt_slots_add: p_spc = %d\n", p_spc);
1700 printf("idt_slots_add: p_ptr = %d\n", p_ptr);
1701 printf("idt_slots_add: qptr = %d\n", qptr);
1702 }
1703 while (slots) {
1704 if (qptr >= qmax) /* handle wrap for empty slot choosing */
1705 qptr -= qmax;
1706 curval = idt->cbr_slot[qptr];
1707 if (curval != NULL) { /* this slot has CBR, so try next */
1708 qptr++; /* next slot */
1709 continue;
1710 }
1711 if (CBR_VERBOSE) {
1712 printf("idt_slots_add: using qptr %d (%d)\n", qptr, qptr - qlast);
1713 qlast = qptr;
1714 }
1715 idt->cbr_slot[qptr] = queue;
1716 nicstar_sram_wr(idt, qptr + IDT_TST_START, 1, scdval, 0, 0, 0);
1717 slots--;
1718 p_ptr += p_spc;
1719 if (p_ptr >= p_max) /* main pointer wrap */
1720 p_ptr -= p_max;
1721 qptr = p_ptr >> 8;
1722 }
1723 return (0);
1724 }
1725
1726 /* 06/11/2001: Extra precision pointer is used in order to handle cases where
1727 * fractional slot spacing causes a large area of slots to be filled.
1728 * This can cause further CBR circuits to get slots that have very
1729 * poor spacing.
1730 *
1731 *******************************************************************************
1732 *
1733 * Remove TX QUEUE pointer from slots in CBR table
1734 *
1735 * in: IDT device, TX_QUEUE
1736 * out: number of CBR slots released
1737 *
1738 * Date first: 12/03/2000 last: 12/03/2000
1739 */
1740 static int
1741 idt_slots_rem(IDT * idt, TX_QUEUE * queue)
1742 {
1743 int qptr, qmax;
1744 int slots;
1745
1746 qmax = idt->txslots_max;
1747 slots = 0;
1748
1749 for (qptr = 0; qptr < qmax; qptr++) {
1750 if (idt->cbr_slot[qptr] != queue)
1751 continue;
1752 idt->cbr_slot[qptr] = NULL;
1753 nicstar_sram_wr(idt, qptr + IDT_TST_START, 1, 0x40000000, 0, 0, 0);
1754 slots++;
1755 }
1756 return (slots);
1757 }
1758
1759 /*******************************************************************************
1760 *
1761 * Initialize slots in CBR table
1762 *
1763 * in: IDT device
1764 * out: zero = success
1765 *
1766 * Date first: 11/29/2000 last: 11/29/2000
1767 */
1768 static int
1769 idt_slots_init(IDT * idt)
1770 {
1771 int start; /* table start pointer */
1772 int qptr;
1773
1774 start = IDT_TST_START;
1775
1776 /* first, fill up the TX CBR table with 'VBR' entries */
1777
1778 for (qptr = 0; qptr < idt->txslots_max; qptr++) {
1779 idt->cbr_slot[qptr] = NULL;
1780 nicstar_sram_wr(idt, qptr + start, 1, 0x40000000, 0, 0, 0);
1781 }
1782
1783 /* now write the jump back to the table start */
1784
1785 nicstar_sram_wr(idt, qptr + start, 1, 0x60000000 | start, 0, 0, 0);
1786
1787 return (0);
1788 }
1789
1790 /*******************************************************************************
1791 *
1792 * Open output queue for connection
1793 *
1794 * in: IDT device, connection (class, traf_pcr, & traf_scr fields valid)
1795 * out: zero = success
1796 *
1797 * Date first: 11/29/2000 last: 06/13/2001
1798 */
1799
1800 int
1801 idt_connect_txopen(IDT * idt, CONNECTION * connection)
1802 {
1803 TX_QUEUE *txqueue;
1804 int cellrate;
1805 int cbr_slots;
1806 int s;
1807
1808 cellrate = connection->traf_scr; /* 06/13/2001 use SCR instead
1809 * of PCR */
1810
1811 if (connection->class == T_ATM_UBR) { /* UBR takes whatever is left
1812 * over */
1813 connection->queue = &idt->queue_ubr;
1814 if (idt_sysctl_logvcs)
1815 printf("idt_connect_txopen: UBR connection for %d/%d\n",
1816 connection->vpi, connection->vci);
1817 return (0);
1818 }
1819 if (connection->class == T_ATM_ABR) { /* ABR treated as UBR-plus */
1820 connection->queue = &idt->queue_abr;
1821 if (idt_sysctl_logvcs)
1822 printf("idt_connect_txopen: UBR+ connection for %d/%d\n",
1823 connection->vpi, connection->vci);
1824 return (0);
1825 }
1826 if (connection->class == T_ATM_CBR) {
1827 cbr_slots = idt_slots_cbr(idt, cellrate);
1828 s = splimp();
1829 if (cbr_slots > (idt->txslots_max - idt->txslots_cur) ||
1830 idt->cbr_freect < 1) {
1831 splx(s);
1832 return (1); /* requested rate not available */
1833 }
1834 idt->txslots_cur += cbr_slots;
1835 idt->cellrate_tcur += cellrate;
1836 idt->cbr_freect--;
1837 txqueue = idt->cbr_free[idt->cbr_freect];
1838 txqueue->rate = cellrate; /* was connection->traf_pcr */
1839
1840 if (idt_slots_add(idt, txqueue, cbr_slots)) {
1841 idt->txslots_cur -= cbr_slots; /* cannot add CBR slots */
1842 idt->cellrate_tcur -= cellrate;
1843 idt->cbr_free[idt->cbr_freect] = txqueue;
1844 idt->cbr_freect++;
1845 splx(s);
1846 return (1);
1847 }
1848 splx(s);
1849 if (idt_sysctl_logvcs)
1850 printf("idt_connect_txopen: CBR connection for %d/%d\n",
1851 connection->vpi, connection->vci);
1852 connection->queue = txqueue;
1853 }
1854 if (connection->class == T_ATM_VBR) {
1855 txqueue = &idt->queue_vbr;
1856 connection->queue = txqueue;
1857 txqueue->rate += connection->traf_scr; /* from traf_pcr
1858 * 12/17/2000 */
1859 if (idt_sysctl_logvcs)
1860 printf("idt_connect_txopen: VBR connection for %d/%d\n",
1861 connection->vpi, connection->vci);
1862 }
1863 idt_connect_newvbr(idt);/* recalculate VBR divisor values */
1864
1865 if (connection->class == T_ATM_CBR ||
1866 connection->class == T_ATM_VBR)
1867 return (0);
1868
1869 return (1); /* unknown class */
1870 }
1871
1872 /*******************************************************************************
1873 *
1874 * Close connection output queue
1875 *
1876 * in: IDT device, connection (class, traf_pcr, & traf_scr fields valid)
1877 * out: zero = success
1878 *
1879 * Date first: 12/03/2000 last: 12/03/2000
1880 */
1881 int
1882 idt_connect_txclose(IDT * idt, CONNECTION * connection)
1883 {
1884 TX_QUEUE *txqueue;
1885 int cellrate;
1886 int slots;
1887 int s;
1888
1889 cellrate = connection->traf_pcr;
1890 txqueue = connection->queue;
1891 if (idt_sysctl_logvcs)
1892 printf("idt_connect_txclose: closing connection for %d/%d\n",
1893 connection->vpi, connection->vci);
1894
1895 idt_queue_flush(connection); /* flush all connection mbufs */
1896
1897 if (connection->class == T_ATM_UBR || /* UBR takes whatever is left
1898 * over */
1899 connection->class == T_ATM_ABR) { /* ABR not supported, use UBR */
1900 connection->queue = NULL;
1901 return (0);
1902 }
1903 if (connection->class == T_ATM_CBR) {
1904 slots = idt_slots_rem(idt, txqueue); /* remove this queue
1905 * from CBR slots */
1906 s = splimp();
1907 idt->txslots_cur -= slots;
1908 idt->cellrate_tcur -= cellrate;
1909 if (txqueue != NULL) { /* 06/12/2001 check for failure on
1910 * open */
1911 idt->cbr_free[idt->cbr_freect] = txqueue;
1912 idt->cbr_freect++;
1913 }
1914 splx(s);
1915 connection->queue = NULL;
1916 }
1917 if (connection->class == T_ATM_VBR) {
1918 txqueue = &idt->queue_vbr;
1919 connection->queue = NULL;
1920 txqueue->rate -= connection->traf_scr; /* from traf_pcr
1921 * 12/17/2000 */
1922 }
1923 idt_connect_newvbr(idt);/* recalculate VBR divisor values */
1924
1925 if (connection->class == T_ATM_CBR ||
1926 connection->class == T_ATM_VBR)
1927 return (0);
1928
1929 return (1); /* unknown class */
1930 }
1931
1932 /*******************************************************************************
1933 *
1934 * Calculate new VBR divisor values
1935 *
1936 * in: IDT device
1937 *
1938 * Date first: 12/03/2000 last: 12/03/2000
1939 */
1940 static void
1941 idt_connect_newvbr(IDT * idt)
1942 {
1943 TX_QUEUE *txqueue;
1944 int rate_newvbr;
1945 int rate_noncbr;
1946 int divisor;
1947
1948 txqueue = &idt->queue_vbr;
1949
1950 rate_newvbr = txqueue->rate;
1951 rate_noncbr = idt->cellrate_tmax - idt->cellrate_tcur;
1952
1953 if (rate_newvbr < 1) /* keep sane and prevent divide by zero */
1954 rate_newvbr = 1;
1955
1956 if (rate_newvbr >= rate_noncbr) {
1957 txqueue->vbr_m = 1;
1958 txqueue->vbr_n = 1;
1959 return;
1960 }
1961 divisor = rate_newvbr * 1000; /* size of lookup table */
1962 divisor += rate_newvbr >> 1; /* apply rounding to divide */
1963 divisor /= rate_noncbr; /* always < 1000, since newvbr < noncbr */
1964
1965 if (idt_sysctl_logvcs)
1966 printf("idt_connect_newvbr: divisor=%d\n", divisor);
1967 txqueue->vbr_m = vbr_div_m[divisor];
1968 txqueue->vbr_n = vbr_div_n[divisor];
1969 if (idt_sysctl_logvcs)
1970 printf("idt_connect_newvbr: m=%d, n=%d\n", txqueue->vbr_m, txqueue->vbr_n);
1971 }
1972
1973 /* For VBR, we track the sum of all the VBR peak cellrates, and divide
1974 * that from the "remaining" bandwidth, which is total minus current CBR.
1975 *
1976 * We will need to adjust the VBR divisor whenever we add a CBR or VBR.
1977 *
1978 * Because of the integer scalign (1000) preload, the cellrate for the
1979 * VBR channel should not exceed 2 million (aprox 5 OC3s). This is
1980 * protected by the check for rate_newvbr >= rate_noncbr.
1981 *
1982 *******************************************************************************
1983 *
1984 * Initialize large buffers, indexes, and reference counts
1985 *
1986 * in: IDT device
1987 * out: zero = success
1988 *
1989 * Date first: 11/01/2000 last: 05/25/2001
1990 */
1991
1992 int
1993 idt_buffer_init(IDT * idt)
1994 {
1995
1996 idt->raw_headm = NULL; /* nicstar_add_buf() will initialize */
1997 idt->raw_headp = 0;
1998
1999 return (0);
2000 }
2001
2002 /*******************************************************************************
2003 *
2004 * Get large buffer from kernel pool
2005 *
2006 * out: mbuf, NULL = error
2007 *
2008 * Date first: 05/25/2001 last: 05/25/2001
2009 */
2010
2011 struct mbuf *
2012 idt_mbufcl_get(void)
2013 {
2014 struct mbuf *m;
2015
2016 MGETHDR(m, M_DONTWAIT, MT_DATA);
2017 if (m == NULL)
2018 return (NULL);
2019
2020 MCLGET(m, M_DONTWAIT);
2021 if (m->m_flags & M_EXT)
2022 return (m);
2023
2024 m_freem(m);
2025 return (NULL);
2026 }
2027
2028 /*******************************************************************************
2029 *
2030 * Initialize connection table
2031 *
2032 * in: IDT, number of VPI bits (0, 1, or 2)
2033 * out: zero = success
2034 *
2035 * Date first: 10/29/2000 last: 12/10/2000
2036 */
2037
2038 int
2039 idt_connect_init(IDT * idt, int vpibits)
2040 {
2041 CONNECTION *connection;
2042 int pages;
2043 int vpi;
2044 int vci;
2045
2046 switch (vpibits) {
2047 case 1:
2048 idt->conn_maxvpi = 2;
2049 idt->conn_maxvci = 2048;
2050 break;
2051 case 2:
2052 idt->conn_maxvpi = 4;
2053 idt->conn_maxvci = 1024;
2054 break;
2055 default:
2056 idt->conn_maxvpi = 1;
2057 idt->conn_maxvci = 4096;
2058 }
2059
2060 pages = (sizeof(CONNECTION) * MAX_CONNECTION) + PAGE_SIZE - 1;
2061 pages /= PAGE_SIZE;
2062 idt->connection = contigmalloc(pages * PAGE_SIZE, M_DEVBUF, M_NOWAIT,
2063 0x100000, 0xffffffff, 0x2000, 0);
2064 if (idt->connection == NULL)
2065 return (1);
2066
2067 for (vpi = 0; vpi < idt->conn_maxvpi; vpi++)
2068 for (vci = 0; vci < idt->conn_maxvci; vci++) {
2069 connection = &idt->connection[vpi * idt->conn_maxvci + vci];
2070 connection->vccinf = NULL; /* may want to change to
2071 * "unclaimed" */
2072 connection->status = 0; /* closed */
2073 connection->vpi = vpi;
2074 connection->vci = vci;
2075 connection->queue = NULL; /* no current TX queue */
2076 connection->recv = NULL; /* no current receive
2077 * mbuf */
2078 connection->rlen = 0;
2079 connection->maxpdu = 0;
2080 connection->traf_pcr = 0;
2081 connection->traf_scr = 0;
2082 connection->aal = 0;
2083 connection->class = 0;
2084 connection->flg_mpeg2ts = 0;
2085 connection->flg_clp = 0;
2086 }
2087
2088 return (0);
2089 }
2090
2091 /*******************************************************************************
2092 *
2093 * Look up a connection
2094 *
2095 * in: IDT, vpi, vci
2096 * out: CONNECTION, NULL=invalid vpi/vci
2097 *
2098 * Date first: 10/29/2000 last: 10/29/2000
2099 */
2100
2101 CONNECTION *
2102 idt_connect_find(IDT * idt, int vpi, int vci)
2103 {
2104 if (vpi >= idt->conn_maxvpi)
2105 return (NULL);
2106 if (vci >= idt->conn_maxvci)
2107 return (NULL);
2108
2109 return (&idt->connection[vpi * idt->conn_maxvci + vci]);
2110 }
2111
2112 /******************************************************************************
2113 *
2114 * MBUF SECTION
2115 *
2116 ******************************************************************************
2117 *
2118 * Align data in mbuf (to 32-bit boundary)
2119 *
2120 * in: mbuf
2121 * out: zero = success
2122 *
2123 * Date first: 11/08/2000 last: 11/15/2000
2124 */
2125
2126 int
2127 idt_mbuf_align(struct mbuf * m, struct mbuf * prev)
2128 {
2129 caddr_t buf_base;
2130 int buf_size;
2131 int offset;
2132 int newlen;
2133 int count;
2134
2135 if (m == NULL)
2136 return (1);
2137 if (((int)m->m_data & 3) == 0)
2138 return (0);
2139
2140 if (m->m_flags & M_EXT) { /* external storage */
2141 buf_base = m->m_ext.ext_buf;
2142 buf_size = m->m_ext.ext_size;
2143
2144 /*
2145 * we should really bail out at this point, since we cannot
2146 * just shift the data in an external mbuf
2147 */
2148
2149 } else {
2150 if (m->m_flags & M_PKTHDR) { /* internal storage, packet
2151 * header */
2152 buf_base = m->m_pktdat;
2153 buf_size = MHLEN;
2154 } else {
2155 buf_base = m->m_dat; /* internal storage, no packet
2156 * header */
2157 buf_size = MLEN;
2158 }
2159 }
2160 offset = 4 - ((int)buf_base & 3);
2161 offset &= 3;
2162 buf_base += offset; /* new (aligned) buffer base */
2163
2164 if (m->m_len + offset > buf_size) /* not enough space to just
2165 * move */
2166 if (prev != NULL)
2167 if (idt_mbuf_append4(prev, m->m_data) == 0) { /* give word to prev
2168 * mbuf */
2169 m->m_data += 4;
2170 m->m_len -= 4;
2171 }
2172 if (m->m_len + offset > buf_size) /* still not enough space */
2173 if (m->m_next != NULL) {
2174 newlen = buf_size - offset; /* maximum new length */
2175 newlen &= 0xfffffc; /* fix the length too... */
2176 count = buf_size - newlen; /* bytes we have to get
2177 * rid of */
2178 if (idt_mbuf_prepend(m->m_next, m->m_data + newlen, count) == 0)
2179 m->m_len = newlen;
2180 }
2181 if (m->m_len + offset > buf_size) /* we're stuck... */
2182 return (1);
2183
2184 bcopy(m->m_data, buf_base, m->m_len); /* move data to aligned
2185 * position */
2186 m->m_data = buf_base;
2187 return (0);
2188 }
2189
2190 /*******************************************************************************
2191 *
2192 * Append 4 bytes to mbuf
2193 *
2194 * in: mbuf, data pointer
2195 * out: zero = success
2196 *
2197 * Date first: 11/08/2000 last: 12/13/2000
2198 */
2199
2200 int
2201 idt_mbuf_append4(struct mbuf * m, char *newdata)
2202 {
2203 caddr_t buf_base;
2204 int buf_size;
2205 int align;
2206 int space;
2207
2208 if (m == NULL)
2209 return (1);
2210
2211 if (m->m_flags & M_EXT) /* external storage */
2212 return (1); /* 12/13/2000 we must not touch it */
2213
2214 if (m->m_flags & M_PKTHDR) { /* internal storage, packet header */
2215 buf_base = m->m_pktdat;
2216 buf_size = MHLEN;
2217 } else {
2218 buf_base = m->m_dat; /* internal storage, no packet header */
2219 buf_size = MLEN;
2220 }
2221
2222 align = (4 - ((int)buf_base & 3)) & 3;
2223 buf_base += align;
2224 buf_size -= align;
2225 buf_size &= 0xfffffc;
2226
2227 space = buf_size - m->m_len;
2228 if (space < 4) /* enough space to add 4 bytes? */
2229 return (1);
2230
2231 space -= m->m_data - buf_base; /* get space at end */
2232
2233 if (space < 4) {
2234 bcopy(m->m_data, buf_base, m->m_len);
2235 m->m_data = buf_base;
2236 }
2237 bcopy(newdata, m->m_data + m->m_len, 4);
2238 m->m_len += 4;
2239
2240 return (0);
2241 }
2242
2243 /*******************************************************************************
2244 *
2245 * Get current base of data storage
2246 *
2247 * in: mbuf
2248 * out: base
2249 *
2250 * Date first: 11/16/2000 last: 11/16/2000
2251 */
2252
2253 caddr_t
2254 idt_mbuf_base(struct mbuf * m)
2255 {
2256 if (m == NULL)
2257 return (NULL);
2258
2259 if (m->m_flags & M_EXT) /* external storage */
2260 return (m->m_ext.ext_buf);
2261
2262 if (m->m_flags & M_PKTHDR) /* internal storage, packet header */
2263 return (m->m_pktdat);
2264
2265 return (m->m_dat); /* internal storage, no packet header */
2266 }
2267
2268 /*******************************************************************************
2269 *
2270 * Copy mbuf chain to new chain (aligned)
2271 *
2272 * in: mbuf
2273 * out: new mbuf chain, NULL=error
2274 *
2275 * Date first: 11/19/2000 last: 05/25/2001
2276 */
2277
2278 struct mbuf *
2279 idt_mbuf_copy(IDT * idt, struct mbuf * m)
2280 {
2281 struct mbuf *nbuf, *dbuf, *sbuf;
2282 u_char *sptr;
2283 int slen;
2284 int clen;
2285
2286 nbuf = idt_mbufcl_get();
2287 if (nbuf == NULL)
2288 return (NULL);
2289 dbuf = nbuf;
2290 dbuf->m_len = 0;
2291
2292 for (sbuf = m; sbuf != NULL; sbuf = sbuf->m_next) {
2293 sptr = sbuf->m_data;
2294 slen = sbuf->m_len;
2295 while (slen) {
2296 clen = slen;
2297 if (clen > NICSTAR_LRG_SIZE - dbuf->m_len)
2298 clen = NICSTAR_LRG_SIZE - dbuf->m_len;
2299 bcopy(sptr, dbuf->m_data + dbuf->m_len, clen);
2300 sptr += clen;
2301 slen -= clen;
2302 dbuf->m_len += clen;
2303 if (dbuf->m_len >= NICSTAR_LRG_SIZE) {
2304 dbuf->m_next = idt_mbufcl_get();
2305 if (dbuf->m_next == NULL) {
2306 m_freem(nbuf);
2307 return (NULL);
2308 }
2309 dbuf = dbuf->m_next;
2310 dbuf->m_len = 0;
2311 } /* if need dest buf */
2312 } /* while(slen) */
2313 } /* for... source buf */
2314 m_freem(m);
2315 return (nbuf);
2316 }
2317
2318 /*******************************************************************************
2319 *
2320 * Prepend data to mbuf (no alignment done)
2321 *
2322 * in: mbuf, data pointer, data length
2323 * out: zero = success
2324 *
2325 * Date first: 11/15/2000 last: 12/13/2000
2326 */
2327
2328 int
2329 idt_mbuf_prepend(struct mbuf * m, char *newdata, int newlen)
2330 {
2331 caddr_t buf_base;
2332 int buf_size;
2333 int space;
2334
2335 if (m == NULL)
2336 return (1);
2337
2338 if (m->m_flags & M_EXT) /* external storage */
2339 return (1); /* 12/13/2000 we must not touch it */
2340
2341 if (m->m_flags & M_PKTHDR) { /* internal storage, packet header */
2342 buf_base = m->m_pktdat;
2343 buf_size = MHLEN;
2344 } else {
2345 buf_base = m->m_dat; /* internal storage, no packet header */
2346 buf_size = MLEN;
2347 }
2348
2349 space = m->m_data - buf_base;
2350
2351 if (space >= newlen) { /* already space at head of mbuf */
2352 m->m_data -= newlen;
2353 m->m_len += newlen;
2354 bcopy(newdata, m->m_data, newlen);
2355 return (0);
2356 }
2357 space = buf_size - m->m_len; /* can we get the space by shifting? */
2358 if (space < newlen)
2359 return (1);
2360
2361 bcopy(m->m_data, m->m_data + newlen, m->m_len);
2362 bcopy(newdata, m->m_data, newlen);
2363 m->m_len += newlen;
2364
2365 return (0);
2366 }
2367
2368 /*******************************************************************************
2369 *
2370 * Get amount of data used in mbuf chain
2371 *
2372 * in: mbuf chain
2373 * out: used space
2374 *
2375 * Date first: 11/10/2000 last: 11/10/2000
2376 */
2377
2378 int
2379 idt_mbuf_used(struct mbuf * mfirst)
2380 {
2381 struct mbuf *m1;
2382 int mbuf_used;
2383
2384 mbuf_used = 0; /* used mbuf space */
2385
2386 for (m1 = mfirst; m1 != NULL; m1 = m1->m_next)
2387 mbuf_used += m1->m_len;
2388
2389 return (mbuf_used);
2390 }
2391
2392 /*******************************************************************************
2393 *
2394 * Notes on transmit buffers:
2395 *
2396 * According to the IDT Nicstar User Manual (version 1.0 2/26/1997), we must
2397 * follow these rules for the transmit buffers (page 66):
2398 *
2399 * 1. The buffer length must not be zero.
2400 * 2. The buffer length must be a multiple of four bytes.
2401 * 3. The sum of the buffer lengths must be a multiple of 48 bytes if
2402 * it is a CS-PDU (eg AAL5).
2403 * 4. All buffers for a CS-PDU must be contiguous and grouped (no other
2404 * PDU buffers or even TSRs).
2405 * 5. For AAL5 PDUs, the buffer lengths must include 8 bytes for the
2406 * AAL5 length/control and CRC fields.
2407 * 6. For AAL5 PDUs, the buffer length of the last buffer must be > 8 bytes.
2408 * 7. For AAL5 PDUs, all buffers containing bytes for the last cell must
2409 * have the END_CS_PDU bit set to 1.
2410 *
2411 * Also, from the IDT applications note ("FAQ") 77211_AN_97088.pdf file:
2412 * Page 5, under "General Technical Questions" (copied EXACTLY):
2413 *
2414 * 5). Can the NicStar begin segmentation from a non-word aligned buffer?
2415 * No, the transmit buffer must point to a word aligned buffer.
2416 *
2417 * Since the buffers MUST be word aligned and MUST be word lengths, we have
2418 * two potential problems with M_EXT mbufs:
2419 *
2420 * 1. If the M_EXT mbuf has a non word aligned address, we have to copy
2421 * the whole thing to a fresh buffer. Unless - the previous mbuf is
2422 * not M_EXT, and it is short by exactly the same amount. Unlikely.
2423 *
2424 * 2. If the M_EXT mbuf has a non word length, we have to push those bytes
2425 * to the next mbuf. If the next mbuf is also M_EXT, we are stuck.
2426 * Unless - the extra bytes from both mbufs are exactly 4 bytes. Then
2427 * we can MGET an empty buf to splice in between.
2428 *
2429 * Also, these rules mean that if any buffer is not word-length, all of the
2430 * following buffers will need to be copied/shifted, unless one or more have
2431 * lengths off by the right amount to fix the earlier buffer.
2432 *
2433 *******************************************************************************
2434 *
2435 * Put mbuf chain on transmit queue
2436 *
2437 * in: IDT device, mbuf chain, vpi, vci, flags (2 MPEG2 TS == 8 AAL5 cells)
2438 * out: (nothing)
2439 *
2440 * Date first: 11/08/2000 last: 05/30/2000
2441 */
2442
2443 void
2444 idt_transmit(IDT * idt, struct mbuf * mfirst, int vpi, int vci, int flags)
2445 {
2446 CONNECTION *connection;
2447 struct mbuf *m1, *m0, *malign, *msend;
2448 int tot_size, tot_scq, x;
2449 int this_len;
2450 int padding;
2451
2452 connection = idt_connect_find(idt, vpi, vci);
2453 if (connection == NULL) { /* this VPI/VCI not open */
2454 idt_transmit_drop(idt, mfirst);
2455 return;
2456 }
2457 if (connection->queue == NULL) {
2458 idt_transmit_drop(idt, mfirst);
2459 connection->vccinf->vc_oerrors++;
2460 return;
2461 }
2462 if (flags)
2463 connection->flg_mpeg2ts = 1;
2464 else
2465 connection->flg_mpeg2ts = 0;
2466
2467 /*
2468 * New strategy: assume that all the buffers are aligned and word
2469 * length. Drop out and handle exceptions below.
2470 */
2471
2472 tot_size = 0;
2473 tot_scq = 1;
2474 malign = NULL;
2475
2476 for (m1 = mfirst; m1 != NULL; m1 = m1->m_next) {
2477 this_len = m1->m_len;
2478 tot_size += this_len;
2479 tot_scq++;
2480 if (malign != NULL)
2481 continue;
2482 if ((int)(m1->m_data) & 3) { /* bad alignment */
2483 malign = m1;
2484 continue;
2485 }
2486 if ((this_len & 3) == 0) /* mbuf length is ok */
2487 continue;
2488 if (m1->m_next != NULL) { /* bad length (in middle) */
2489 malign = m1;
2490 continue;
2491 }
2492 padding = 4 - (this_len & 3);
2493 tot_size += padding;
2494 m1->m_len += padding;
2495 break; /* last mbuf, so avoid the loop test */
2496 }
2497 if (malign == NULL) { /* perfect packet, no copy needed */
2498 mfirst->m_pkthdr.len = tot_size;
2499 if (connection->flg_mpeg2ts)
2500 tot_scq += tot_size / 376; /* more entries needed
2501 * for split */
2502 mfirst->m_pkthdr.csum_data = tot_scq;
2503
2504 if (idt_queue_put(connection, mfirst)) /* put packet on TX
2505 * queue */
2506 device_printf(idt->dev, "Cannot queue packet for %d/%d.\n", vpi, vci);
2507 if (connection->queue->mget == mfirst) /* was the queue empty? */
2508 idt_transmit_top(idt, connection->queue); /* IFF empty, prime it
2509 * now */
2510 return;
2511 }
2512 /*
2513 * Bad alignment or length, so fall through to old code... The first
2514 * alignment problem is at 'malign'
2515 */
2516 if (idt_sysctl_logvcs)
2517 device_printf(idt->dev, "Bad TX buf alignment, len=%d.\n", tot_size);
2518
2519 if (idt_mbuf_align(mfirst, NULL)) {
2520 printf("idt_transmit: cannot align first mbuf.\n");
2521 idt_transmit_drop(idt, mfirst);
2522 connection->vccinf->vc_oerrors++;
2523 return;
2524 }
2525 /* find first mbuf with bad alignment (if any) */
2526
2527 m0 = mfirst;
2528 for (m1 = mfirst->m_next; m1 != NULL; m0 = m1, m1 = m1->m_next) {
2529 if (m1->m_len & 3)
2530 break;
2531 if ((int)(m1->m_data) & 3)
2532 break;
2533 }
2534 if (m1 != NULL) {
2535 m1 = idt_mbuf_copy(idt, m1); /* copy the rest into new
2536 * mbufs */
2537 m0->m_next = m1;
2538 if (m1 == NULL) {
2539 printf("idt_transmit: could not copy buffers.\n");
2540 idt_transmit_drop(idt, mfirst);
2541 connection->vccinf->vc_oerrors++;
2542 return; /* FIX THIS - this path has been taken */
2543 }
2544 }
2545 msend = mfirst;
2546
2547 /* The mbuf chain is aligned, now we need to pad to word length */
2548
2549 tot_size = idt_mbuf_used(msend); /* forget the pkthdr length... */
2550 msend->m_pkthdr.len = tot_size;
2551
2552 padding = (4 - (tot_size & 3)) & 3;
2553 if (padding) {
2554 for (m1 = msend; m1->m_next != NULL; m1 = m1->m_next);
2555 m1->m_len += padding;
2556 }
2557 x = 1; /* now calculate the SCQ entries needed */
2558 for (m1 = msend; m1 != NULL; m1 = m1->m_next)
2559 x++;
2560 if (connection->flg_mpeg2ts)
2561 x += tot_size / 376; /* more entries needed for split */
2562 msend->m_pkthdr.csum_data = x;
2563
2564 /* now we have an mbuf chain, from *msend to *m1 ready to go */
2565
2566 if (idt_queue_put(connection, msend)) /* put packet on TX queue */
2567 device_printf(idt->dev, "Cannot queue packet for %d/%d.\n", vpi, vci);
2568
2569 if (connection->queue->mget == msend) /* was the queue empty? */
2570 idt_transmit_top(idt, connection->queue); /* IFF empty, prime it
2571 * now */
2572 }
2573
2574 /* Notes on mbuf usage in the transmit queue:
2575 *
2576 * m_pkthdr.rcvif Connection pointer (set by idt_queue_put)
2577 * m_pkthdr.len Length of PDU
2578 * m_pkthdr.header TX queue pointer (06/01/2001)
2579 * m_pkthdr.csum_flags Unused, keep zero
2580 * m_pkthdr.csum_data Number of SCQ entries needed or used
2581 *
2582 *******************************************************************************
2583 *
2584 * Drop transmit mbuf chain and update counters
2585 *
2586 * in: IDT device, mbuf chain
2587 * out: (nothing)
2588 *
2589 * Date first: 11/08/2000 last: 11/08/2000
2590 */
2591
2592 void
2593 idt_transmit_drop(IDT * idt, struct mbuf * mfirst)
2594 {
2595 struct mbuf *next;
2596 int mesglen;
2597
2598 mesglen = 0;
2599 while (mfirst != NULL) {
2600 mesglen += mfirst->m_len;
2601 next = m_free(mfirst);
2602 mfirst = next;
2603 }
2604 device_printf(idt->dev, "dropping transmit packet, size=%d\n", mesglen);
2605 idt->stats_oerrors++; /* 12/15/2000 */
2606 }
2607
2608 /*******************************************************************************
2609 *
2610 * Put mbuf chain on transmit queue
2611 *
2612 * in: IDT device, TX_QUEUE
2613 * out: (nothing)
2614 *
2615 * Date first: 12/03/2000 last: 06/01/2001
2616 */
2617
2618 void
2619 idt_transmit_top(IDT * idt, TX_QUEUE * txqueue)
2620 {
2621 CONNECTION *connection;
2622 struct mbuf *top, *m;
2623 static int padding[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2624 int scq_space;
2625 int val, val1, val3, val4;
2626 int count, mlen, tlen, pad;
2627 char *mptr;
2628 int pdulen;
2629 int vci, vpi;
2630 int s;
2631
2632 if (txqueue == NULL) /* 12/12/2000 */
2633 return;
2634 if (txqueue->mget == NULL) /* check for empty queue */
2635 return;
2636
2637 s = splimp();
2638
2639 scq_space = txqueue->scq_len - txqueue->scq_cur;
2640
2641 /* Now we can add the queue entries for the PDUs */
2642
2643 count = 0;
2644
2645 for (;;) {
2646 top = txqueue->mget; /* next available mbuf */
2647 if (top == NULL)
2648 break;
2649
2650 if (top->m_pkthdr.csum_data + 4 > scq_space)
2651 break; /* not enough space for this PDU */
2652
2653 top = idt_queue_get(txqueue);
2654 if (top == NULL)
2655 break;
2656 connection = (CONNECTION *) top->m_pkthdr.rcvif;
2657 vpi = connection->vpi;
2658 vci = connection->vci;
2659 top->m_pkthdr.header = (void *)connection->queue;
2660
2661 top->m_pkthdr.csum_data = 0; /* track actual number of SCQ
2662 * entries used */
2663
2664 tlen = top->m_pkthdr.len;
2665 switch (connection->aal) {
2666 case ATM_AAL0:
2667 val = 0;
2668 break;
2669 case ATM_AAL3_4:
2670 val = 0x04000000;
2671 break;
2672 case ATM_AAL5:
2673 val = 0x08000000;
2674 break;
2675 default:
2676 device_printf(idt->dev, "bad AAL for %d/%d\n", vpi, vci);
2677 m_freem(top);
2678 connection->vccinf->vc_oerrors++;
2679 continue;
2680 }
2681 val |= txqueue->vbr_m << 23;
2682 val |= txqueue->vbr_n << 16;
2683 val4 = (vpi << 20) | (vci << 4);
2684 if (connection->flg_clp)
2685 val4 |= 1; /* set CLP flag */
2686
2687 /*
2688 * Now we are ready to start mapping the mbuf(s) to transmit
2689 * buffer descriptors. If the MPEG2TS flag is set, we want
2690 * to create AAL5 PDUs of exactly 384 data bytes each.
2691 */
2692
2693 pdulen = top->m_pkthdr.len; /* default case: don't split
2694 * PDU */
2695 pad = 0;
2696 if (connection->flg_mpeg2ts) {
2697 if ((pdulen % 376) == 0) { /* correct multiple */
2698 pdulen = 376; /* cut off every pdu at 374
2699 * data bytes */
2700 pad = 8;
2701 } else
2702 device_printf(idt->dev, "Bad MPEG2 PDU buffer (%d bytes).\n", pdulen);
2703 }
2704 val3 = pdulen; /* actual (unpadded) PDU length */
2705
2706 pdulen += (4 - (pdulen & 3)) & 3;
2707
2708 if (pad == 0) { /* normal padding (PDU not split) */
2709 pad = pdulen;
2710 if (connection->aal == ATM_AAL5)
2711 pad += 8;
2712 pad = 48 - (pad % 48);
2713 if (pad == 48)
2714 pad = 0;
2715 if (connection->aal == ATM_AAL5)
2716 pad += 8; /* pad of up to 52 is
2717 * possible/neccessary */
2718 }
2719 tlen = 0;
2720 for (m = top; m != NULL; m = m->m_next) {
2721 while ((mlen = m->m_len)) {
2722 if (mlen + tlen > pdulen)
2723 mlen = pdulen - tlen; /* how much of this
2724 * buffer can we use? */
2725 mptr = m->m_data;
2726 tlen += mlen; /* length of this PDU */
2727 m->m_len -= mlen; /* bytes remaining in
2728 * mbuf */
2729 m->m_data += mlen; /* new data pointer */
2730
2731 val1 = val;
2732 if (tlen > pdulen + pad - 48) /* is this buffer in the
2733 * last cell? */
2734 val1 |= 0x40000000; /* last buffer in PDU */
2735
2736 if (tlen == pdulen) { /* end of PDU, so figure
2737 * padding needed */
2738 idt->stats_opdus++; /* 12/15/2000 */
2739 idt->stats_obytes += pdulen; /* 12/15/2000 */
2740 connection->vccinf->vc_opdus++;
2741 connection->vccinf->vc_obytes += pdulen;
2742 tlen = 0;
2743 if (pad <= 8)
2744 mlen += pad; /* just "add" padding to
2745 * this buffer */
2746 }
2747 *txqueue->scq_next++ = val1 | mlen;
2748 *txqueue->scq_next++ = vtophys(mptr);
2749 *txqueue->scq_next++ = val3;
2750 *txqueue->scq_next++ = val4;
2751 if (txqueue->scq_next - txqueue->scq_base >= txqueue->scq_len * 4)
2752 txqueue->scq_next = txqueue->scq_base;
2753 scq_space--;
2754 top->m_pkthdr.csum_data++; /* 12/22/2000 */
2755
2756 /*
2757 * if we need more than 8 bytes of padding,
2758 * use the zero-filled buffer defined above.
2759 */
2760 if (tlen == 0 && pad > 8) { /* end of PDU, do we
2761 * need padding? */
2762 val1 |= 0x40000000; /* last buffer in PDU */
2763 *txqueue->scq_next++ = val1 | pad;
2764 *txqueue->scq_next++ = vtophys(padding);
2765 *txqueue->scq_next++ = val3;
2766 *txqueue->scq_next++ = val4;
2767 if (txqueue->scq_next - txqueue->scq_base >= txqueue->scq_len * 4)
2768 txqueue->scq_next = txqueue->scq_base;
2769 scq_space--;
2770 top->m_pkthdr.csum_data++; /* 12/22/2000 */
2771 }
2772 }
2773 }
2774
2775 /*
2776 * Now that we have set up the descriptors, add the entry
2777 * for Transmit Status Request so we know when the PDU(s)
2778 * are done.
2779 */
2780
2781 *txqueue->scq_next++ = 0xa0000000; /* TSR with interrupt */
2782 *txqueue->scq_next++ = (u_long)top;
2783 *txqueue->scq_next++ = 0;
2784 *txqueue->scq_next++ = 0;
2785
2786 if (txqueue->scq_next - txqueue->scq_base >= txqueue->scq_len * 4)
2787 txqueue->scq_next = txqueue->scq_base;
2788 scq_space--;
2789 top->m_pkthdr.csum_data++; /* 12/22/2000 */
2790 count++;
2791
2792 txqueue->scq_cur += top->m_pkthdr.csum_data;
2793 }
2794
2795 /*
2796 * 05/31/2001: Optimization: Since writing to SRAM is very
2797 * expensive, we will only do this when the pointer is stale (half
2798 * of the queue). If the queue is less than 1/4 full, then write the
2799 * pointer anyway.
2800 */
2801
2802 if (idt_sysctl_qptrhold) {
2803 scq_space = txqueue->scq_next - txqueue->scq_last; /* number pending */
2804 scq_space /= 4;
2805 if (scq_space < 0)
2806 scq_space += txqueue->scq_len;
2807 if (scq_space * 2 < txqueue->scq_len && /* less than half
2808 * pending */
2809 txqueue->scq_cur > txqueue->scq_len / 4) /* and queue is active */
2810 count = 0;
2811 }
2812 if (count) { /* we need to update the queue pointer */
2813 nicstar_sram_wr(idt, txqueue->scd, 1, vtophys(txqueue->scq_next), 0, 0, 0);
2814 txqueue->scq_last = txqueue->scq_next;
2815 }
2816 splx(s);
2817
2818 return;
2819 }
2820
2821 /* Once a packet has been put in the Segmentation Channel Queue, it will
2822 * be sent, and then the mbuf will harvested by idt_intr_tsq(). While it
2823 * is in the SCQ, m_pkthdr.header is the pointer to the TX queue. This is
2824 * important because if the connection is closed while there are still
2825 * mbufs in the SCQ, idt_intr_tsq() still needs to update the TX queue.
2826 *
2827 ******************************************************************************
2828 *
2829 * Handle entries in Transmit Status Queue (end of PDU interrupt or TSQ full)
2830 *
2831 * in: IDT device
2832 *
2833 * Date first: 12/04/2000 last: 06/10/2001
2834 */
2835 static void
2836 idt_intr_tsq(IDT * idt)
2837 {
2838 CONNECTION *connection;
2839 TX_QUEUE *txqueue;
2840 u_long *tsq_ptr;
2841 u_long val;
2842 struct mbuf *m;
2843 int count, s;
2844
2845 s = splimp();
2846
2847 tsq_ptr = idt->tsq_head;
2848
2849 count = 0;
2850 while ((tsq_ptr[1] & 0x80000000) == 0) {
2851 m = (struct mbuf *) tsq_ptr[0];
2852 if (m != NULL) {/* first test for timer rollover entry */
2853 if (((int)m & 0x000000ff)) /* now do sanity check
2854 * on the mbuf ptr */
2855 device_printf(idt->dev,
2856 "DANGER! bad mbuf (%x), stamp=%x\n",
2857 (int)m, (int)tsq_ptr[1]);
2858 else {
2859 connection = (CONNECTION *) m->m_pkthdr.rcvif;
2860 txqueue = (TX_QUEUE *) m->m_pkthdr.header;
2861 txqueue->scq_cur -= m->m_pkthdr.csum_data;
2862 if (txqueue->scq_cur < 0 || txqueue->scq_cur > txqueue->scq_len)
2863 device_printf(idt->dev, "DANGER! scq_cur is %d\n", txqueue->scq_len);
2864 m->m_pkthdr.header = NULL;
2865 m_freem(m);
2866 idt_transmit_top(idt, txqueue); /* move more into queue */
2867 }
2868 }
2869 tsq_ptr[0] = 0;
2870 tsq_ptr[1] = 0x80000000; /* reset TSQ entry */
2871 tsq_ptr += 2;
2872 if (tsq_ptr >= idt->tsq_base + idt->tsq_size * 2)
2873 tsq_ptr = idt->tsq_base;
2874 count++;
2875 }
2876 idt->tsq_head = tsq_ptr;
2877
2878 if (count) {
2879 val = (int)tsq_ptr - (int)idt->tsq_base;
2880 val -= 8; /* always stay one behind */
2881 val &= 0x001ff8;
2882 *idt->reg_tsqh = val;
2883 }
2884 splx(s);
2885 }
2886
2887 /* There is a problem with the pointer rollover where the SAR will think the
2888 * TSQ buffer is full (forever?) unless we hold the head pointer back.
2889 * This is not mentioned in the 77211 docs, but is a resolved issue in
2890 * revision D of the 77252 chips (see 77252 errata).
2891 *
2892 * If a connection is closed while there are still mbufs in the TX queue,
2893 * the connection TX queue pointer will be NULL. That is why we have a
2894 * special copy of the pointer in m_pkthdr.header. Also, idt_transmit_top()
2895 * will allow the TX queue for that connection to empty properly.
2896 *
2897 * It is possible for a TSQ entry to be 0x00ffffff/0x00ffffff, which is
2898 * obviously not an mbuf and not a timer rollover entry. We now have an
2899 * mbuf sanity check for this.
2900 *
2901 ******************************************************************************
2902 *
2903 * nicstar_itrx ( card )
2904 *
2905 * service error in transmitting PDU interrupt.
2906 *
2907 */
2908 static void
2909 nicstar_itrx(nicstar_reg_t * idt)
2910 {
2911 /* trace mbuf and release */
2912 }
2913
2914 /******************************************************************************
2915 *
2916 * Raw cell receive interrupt
2917 *
2918 * service raw cell reception interrupt.
2919 *
2920 */
2921
2922 static void
2923 nicstar_rawc(nicstar_reg_t * idt)
2924 {
2925 u_long ptr_tail;
2926 struct mbuf *qmbuf;
2927 u_long *qptr;
2928 u_long next_mbuf;
2929 u_long next_phys;
2930
2931 if (idt->raw_headm == NULL ||
2932 idt->raw_headp == 0) {
2933 device_printf(idt->dev,
2934 "RAW cell received, buffers not ready (%x/%x).\n",
2935 (int)idt->raw_headm, (int)idt->raw_headp);
2936 return;
2937 }
2938 ptr_tail = *(volatile u_long *)(idt->virt_baseaddr + REGRAWT);
2939 if ((ptr_tail & 0xfffff800) == idt->raw_headp)
2940 return; /* still in the same large buffer */
2941
2942 if ((ptr_tail & 0x7ff) < 64) /* wait until something in new buffer */
2943 return;
2944
2945 qmbuf = idt->raw_headm;
2946 qptr = (u_long *)qmbuf->m_data;
2947
2948 next_mbuf = qptr[31 * 16 + 1]; /* next handle (virtual) */
2949 next_phys = qptr[31 * 16 + 0]; /* next physical address */
2950
2951 /* if we want to do anything with the raw data, this is the place */
2952
2953 idt_mcheck_rem(idt, qmbuf);
2954 m_free(qmbuf);
2955
2956 idt->raw_headm = (struct mbuf *) next_mbuf;
2957 idt->raw_headp = next_phys;
2958 }
2959
2960 /*****************************************************************************
2961 *
2962 * Handle AAL5 PDU length
2963 *
2964 * in: IDT device, first mbuf in chain, last mbuf
2965 * out: zero = success, nz = failure (mbuf chain freed)
2966 *
2967 * Date first: 11/18/2000 last: 12/14/2000
2968 */
2969
2970 int
2971 idt_receive_aal5(IDT * idt, struct mbuf * mfirst, struct mbuf * mdata)
2972 {
2973 struct mbuf *m2;
2974 unsigned char *aal5len;
2975 int plen;
2976 int diff;
2977
2978 aal5len = mdata->m_data + mdata->m_len - 6; /* aal5 length = 16 bits */
2979 plen = aal5len[0] * 256 + aal5len[1];
2980 diff = mfirst->m_pkthdr.len - plen; /* number of bytes to trim */
2981
2982 if (diff == 0)
2983 return (0);
2984
2985 if (diff < 0) {
2986 device_printf(idt->dev,
2987 "AAL5 PDU length (%d) greater than cells (%d), discarding\n",
2988 plen, mfirst->m_pkthdr.len);
2989 m_freem(mfirst);
2990 return (1);
2991 }
2992 while (mdata->m_len < diff) { /* last mbuf not big enough */
2993 diff -= mdata->m_len;
2994 m2 = mdata;
2995 m_free(mdata);
2996 if (mdata == mfirst) { /* we just tossed the whole PDU */
2997 device_printf(idt->dev, "AAL5 PDU length failed, discarding.\n");
2998 return (1); /* the packetheadr length was bad! */
2999 }
3000 for (mdata = mfirst; mdata->m_next != m2; mdata = mdata->m_next);
3001 mdata->m_next = NULL; /* remove old link to free'd mbuf */
3002 }
3003 mdata->m_len -= diff; /* trim last mbuf */
3004 mfirst->m_pkthdr.len = plen;
3005
3006 return (0);
3007 }
3008
3009 /* 12/14/2000: Removed "pruning" log message.
3010 *
3011 *****************************************************************************
3012 *
3013 * nicstar_recv ( card )
3014 *
3015 * rebuilds PDUs from entries in the Recieve Status Queue.
3016 *
3017 */
3018 struct rsq_entry {
3019 u_long vpivci;
3020 struct mbuf *mdata;
3021 u_long crc;
3022 u_long flags;
3023 };
3024
3025 static void
3026 nicstar_recv(nicstar_reg_t * idt)
3027 {
3028 CONNECTION *connection;
3029 volatile u_long *regh = (volatile u_long *)(idt->virt_baseaddr + REGRSQH);
3030 struct rsq_entry *rsq;
3031 struct mbuf *mdata, *mptr;
3032 u_long flags;
3033 u_long crc;
3034 int vpi;
3035 int vci;
3036 int clen;
3037 int x, s;
3038
3039 s = splimp();
3040
3041 rsq = (struct rsq_entry *) (idt->fixbuf + 0x2000 + (idt->rsqh & 0x1ffc));
3042
3043 if ((rsq->flags & 0x80000000) == 0) {
3044 splx(s);
3045 return;
3046 }
3047 while (rsq->flags & 0x80000000) {
3048 vpi = rsq->vpivci >> 16; /* first, grab the RSQ data */
3049 vci = rsq->vpivci & 0xffff;
3050 mdata = rsq->mdata;
3051 crc = rsq->crc;
3052 flags = rsq->flags;
3053 clen = (flags & 0x1ff) * 48;
3054
3055 rsq->vpivci = 0;/* now recycle the RSQ entry */
3056 rsq->mdata = NULL;
3057 rsq->crc = 0;
3058 rsq->flags = 0; /* turn off valid bit */
3059 rsq++;
3060 if (rsq == (struct rsq_entry *) (idt->fixbuf + 0x4000))
3061 rsq = (struct rsq_entry *) (idt->fixbuf + 0x2000);
3062
3063 idt_mcheck_rem(idt, mdata);
3064
3065 connection = idt_connect_find(idt, vpi, vci);
3066 if (connection == NULL) { /* we don't want this PDU */
3067 printf("nicstar_recv: No connection %d/%d - discarding packet.\n",
3068 vpi, vci);
3069 m_free(mdata); /* throw mbuf away */
3070 continue;
3071 }
3072 mdata->m_len = clen;
3073
3074 mptr = connection->recv;
3075 if (mptr == NULL) {
3076 if (mdata->m_flags & M_PKTHDR)
3077 connection->recv = mdata;
3078 else {
3079 idt->stats_ierrors++; /* 12/15/2000 */
3080 connection->vccinf->vc_ierrors++;
3081 m_free(mdata);
3082 continue;
3083 }
3084 } else {
3085 x = 0;
3086 while (mptr->m_next != NULL) { /* find last mbuf in
3087 * chain */
3088 mptr = mptr->m_next;
3089 x++;
3090 if (x > 25)
3091 break;
3092 }
3093 if (x > 25) {
3094 mptr = connection->recv;
3095 printf("nicstar_recv: invalid mbuf chain - probable corruption!\n");
3096 m_free(mdata);
3097 idt->stats_ierrors++; /* 12/15/2000 */
3098 connection->vccinf->vc_ierrors++;
3099 connection->recv = NULL;
3100 connection->rlen = 0;
3101 continue;
3102 }
3103 mptr->m_next = mdata;
3104 }
3105 connection->rlen += clen;
3106
3107 if (flags & 0x2000) { /* end of PDU */
3108 mptr = connection->recv; /* one or more mbufs
3109 * will be here */
3110 clen = connection->rlen; /* length based on cell
3111 * count */
3112 connection->recv = NULL;
3113 connection->rlen = 0;
3114
3115 mptr->m_pkthdr.len = clen;
3116 mptr->m_pkthdr.rcvif = NULL;
3117 mptr->m_nextpkt = NULL;
3118
3119 if (mptr->m_pkthdr.csum_flags) {
3120 device_printf(idt->dev,
3121 "received pkthdr.csum_flags=%x\n",
3122 mptr->m_pkthdr.csum_flags);
3123 mptr->m_pkthdr.csum_flags = 0;
3124 }
3125 if (flags & 0x200 && /* bad CRC */
3126 idt->flg_igcrc == 0) {
3127 printf("nicstar_recv: Bad CRC - discarding PDU: %d/%d\n", vpi, vci);
3128 idt->stats_ierrors++; /* 12/15/2000 */
3129 connection->vccinf->vc_ierrors++;
3130 m_freem(mptr);
3131 continue;
3132 }
3133 if (connection->aal == ATM_AAL5) {
3134 if (idt_receive_aal5(idt, mptr, mdata)) /* adjust for AAL5
3135 * length */
3136 continue;
3137 }
3138 idt->stats_ipdus++; /* 12/15/2000 */
3139 idt->stats_ibytes += mptr->m_pkthdr.len; /* 12/15/2000 */
3140 connection->vccinf->vc_ipdus++;
3141 connection->vccinf->vc_ibytes += mptr->m_pkthdr.len;
3142 idt_receive(idt, mptr, vpi, vci);
3143 } else if (connection->rlen > connection->maxpdu) { /* this packet is insane */
3144 printf("nicstar_recv: Bad packet, len=%d - discarding.\n",
3145 connection->rlen);
3146 connection->recv = NULL;
3147 connection->rlen = 0;
3148 idt->stats_ierrors++; /* 12/15/2000 */
3149 connection->vccinf->vc_ierrors++;
3150 m_freem(mptr);
3151 } /* end of PDU */
3152 }
3153
3154 idt->rsqh = vtophys((u_long)rsq) & 0x1ffc;
3155 *regh = (idt->rsqh - sizeof(struct rsq_entry)) & 0x1ff0;
3156
3157 splx(s);
3158 }
3159
3160 /******************************************************************************
3161 *
3162 * Physical Interrupt handler
3163 *
3164 * service phyical interrupt.
3165 *
3166 */
3167
3168 static void
3169 nicstar_phys(nicstar_reg_t * idt)
3170 {
3171 u_long t;
3172
3173 if (idt->flg_le25) {
3174 nicstar_util_rd(idt, 0x01, &t); /* get interrupt cause */
3175 if (t & 0x01) {
3176 nicstar_util_wr(idt, 1, 0x02, 0x10); /* reset rx fifo */
3177 device_printf(idt->dev, "PHY cleared.\n");
3178 }
3179 } else
3180 device_printf(idt->dev, "Physical interrupt.\n");
3181 }
3182
3183 /******************************************************************************
3184 *
3185 * Status register values
3186 */
3187
3188 #define STAT_REG_RSQAF 0x0002 /* receive status queue almost full */
3189 #define STAT_REG_LBMT 0x0004 /* large buffer queue empty */
3190 #define STAT_REG_SBMT 0x0008 /* small buffer queue empty */
3191 #define STAT_REG_RAWC 0x0010 /* raw cell interrupt */
3192 #define STAT_REG_EPDU 0x0020 /* end of PDU interrupt */
3193 #define STAT_REG_PHY 0x0400 /* physical interrupt */
3194 #define STAT_REG_TIME 0x0800 /* timer overflow interrupt */
3195 #define STAT_REG_TSQAF 0x1000 /* transmit status queue almost full */
3196 #define STAT_REG_TXIN 0x4000 /* TX PDU incomplete */
3197 #define STAT_REG_TXOK 0x8000 /* TX status indicator */
3198
3199 /******************************************************************************
3200 *
3201 * Interrupt handler
3202 *
3203 * service card interrupt.
3204 *
3205 * nicstar_intr ( card )
3206 */
3207
3208 void
3209 nicstar_intr(void *arg)
3210 {
3211 IDT *idt;
3212 volatile u_long stat_val, config_val;
3213 int int_flags;
3214 volatile int i;
3215 int s;
3216
3217 idt = (IDT *) arg;
3218
3219 i = 0;
3220
3221 s = splnet();
3222
3223 config_val = *idt->reg_cfg;
3224 stat_val = *idt->reg_stat;
3225
3226 int_flags =
3227 STAT_REG_TSQAF | /* transmit status queue almost full */
3228 STAT_REG_RSQAF | /* receive status queue almost full */
3229 STAT_REG_RAWC | /* raw cell interrupt */
3230 STAT_REG_EPDU | /* end of PDU interrupt */
3231 STAT_REG_TIME | /* timer overflow interrupt */
3232 STAT_REG_TXIN | /* TX PDU incomplete */
3233 STAT_REG_TXOK; /* TX status indicator */
3234
3235 if (idt->flg_le25)
3236 int_flags |= STAT_REG_PHY; /* include flag for physical
3237 * interrupt */
3238
3239 if (stat_val & (STAT_REG_LBMT | STAT_REG_SBMT)) { /* buffer queue(s) empty */
3240 if (stat_val & STAT_REG_SBMT)
3241 device_printf(idt->dev, "small free buffer queue empty.\n");
3242 if (stat_val & STAT_REG_LBMT)
3243 device_printf(idt->dev, "large free buffer queue empty.\n");
3244 nicstar_ld_rcv_buf(idt);
3245
3246 if (*idt->reg_stat & STAT_REG_LBMT) { /* still empty, so
3247 * disable IRQ */
3248 config_val &= ~0x01000000;
3249 *idt->reg_cfg = config_val;
3250 }
3251 }
3252 /* loop until no more interrupts to service */
3253
3254 while (stat_val & int_flags) {
3255 i++;
3256 if (i < 0 || i > 100)
3257 break;
3258
3259 *idt->reg_stat = stat_val & int_flags; /* clear status bits */
3260
3261 if (stat_val & STAT_REG_EPDU) { /* receive PDU */
3262 nicstar_recv(idt);
3263 nicstar_ld_rcv_buf(idt); /* replace buffers,
3264 * moved here 11/14/2000 */
3265 }
3266 if (stat_val & STAT_REG_RAWC) { /* raw cell */
3267 nicstar_rawc(idt);
3268 }
3269 if (stat_val & STAT_REG_TXOK) { /* transmit complete */
3270 idt_intr_tsq(idt);
3271 }
3272 if (stat_val & STAT_REG_TXIN) { /* bad transmit */
3273 nicstar_itrx(idt);
3274 device_printf(idt->dev, "Bad transmit.\n");
3275 }
3276 if (stat_val & STAT_REG_TIME) { /* timer wrap */
3277 idt->timer_wrap++;
3278 idt_intr_tsq(idt); /* check the TSQ */
3279 nicstar_recv(idt); /* check the receive queue */
3280 if (idt_sysctl_logbufs)
3281 idt_status_bufs(idt); /* show the buffer
3282 * status */
3283 }
3284 if (stat_val & STAT_REG_PHY) { /* physical interrupt */
3285 nicstar_phys(idt);
3286 *idt->reg_stat = STAT_REG_PHY; /* clear the int flag */
3287 }
3288 if (stat_val & STAT_REG_RSQAF) { /* RSQ almost full */
3289 nicstar_recv(idt);
3290 device_printf(idt->dev, "warning, RSQ almost full.\n");
3291 if (*idt->reg_stat & STAT_REG_RSQAF) { /* RSQ full */
3292 printf("RSQ is full, disabling interrupt.\n");
3293 config_val &= 0x00000800;
3294 *idt->reg_cfg = config_val;
3295 }
3296 }
3297 if (stat_val & STAT_REG_TSQAF) { /* TSQ almost full */
3298 idt_intr_tsq(idt);
3299 device_printf(idt->dev, "warning, TSQ almost full.\n");
3300 if (*idt->reg_stat & STAT_REG_TSQAF) {
3301 printf("TSQ is full, disabling interrupt.\n");
3302 config_val &= ~0x00000002;
3303 *idt->reg_cfg = config_val;
3304 }
3305 }
3306 stat_val = *idt->reg_stat;
3307 }
3308
3309 splx(s);
3310 if (i < 1 || i > 50)
3311 device_printf(idt->dev, "i=%3d, status=%08x\n", i, (int)stat_val);
3312 }
Cache object: 02f1ad81d7014b0b2f756a4707dd2c90
|