Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / alpha / a12 / if_xb.c
blob0dfcdb5471f7167d99e0ffa9051fffa6ac2eaeb8
1 /* $NetBSD: if_xb.c,v 1.23 2009/03/17 18:19:15 dsl Exp $ */
3 /* [Notice revision 2.2]
4 * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
5 * All rights reserved.
7 * Author: Ross Harvey
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright and
13 * author notice, this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * 4. This copyright will be assigned to The NetBSD Foundation on
21 * 1/1/2000 unless these terms (including possibly the assignment
22 * date) are updated in writing by Avalon prior to the latest specified
23 * assignment date.
25 * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 /*
39 * Notes.
41 * Since the NetBSD build rules force the use of function prototypes, even on
42 * functions that are defined before they are called, I've taken advantage of
43 * the opportunity and organized this module in top down fashion, with
44 * functions generally calling down the page rather than up. It's different.
45 * I think I'm getting to like it this way.
47 * The crossbar interface is not exactly a peripheral device, and it cannot
48 * appear on anything other than an alpha-based Avalon A12. The crossbar
49 * controller is built into the core logic.
51 * If this version of the driver supports MPS transport, it may have some
52 * large static data declarations. Don't worry about it, as Avalon a12
53 * support should not appear in a GENERIC or INSTALL kernel.
55 * (Every A12 ever shipped had 512 MB per CPU except one site, which had 256
56 * MB. Partly has a result of this, it is unlikely that a kernel configured
57 * for an A12 would be exactly the thing to use on most workstations, so we
58 * don't really need to worry that we might be configured in a generic or
59 * site-wide kernel image.)
61 * This preliminary crossbar driver supports IP transport using PIO. Although
62 * it would be nice to have a DMA driver, do note that the crossbar register
63 * port is 128 bits wide, so we have 128-bit PIO. (The 21164 write buffer
64 * will combine two 64-bit stores before they get off-chip.) Also, the rtmon
65 * driver wasn't DMA either, so at least the NetBSD driver is as good as any
66 * other that exists now.
68 * We'll do DMA and specialized transport ops later. Given the high speed of
69 * the PIO mode, no current applications require DMA bandwidth, but everyone
70 * benefits from low latency. The PIO mode is actually lower in latency
71 * anyway.
74 #include "opt_avalon_a12.h" /* Config options headers */
75 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
77 __KERNEL_RCSID(0, "$NetBSD: if_xb.c,v 1.23 2009/03/17 18:19:15 dsl Exp $");
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/malloc.h>
83 #include <sys/device.h>
84 #include <sys/socket.h>
85 #include <sys/mbuf.h>
86 #include <sys/sockio.h>
88 #include <uvm/uvm_extern.h>
90 #include <net/if.h>
91 #include <net/if_dl.h>
92 #include <net/if_types.h>
93 #include <net/route.h>
94 #include <netinet/in.h>
95 #include <netinet/in_var.h>
97 #include <machine/autoconf.h>
98 #include <machine/rpb.h>
100 #include <dev/isa/isareg.h>
101 #include <dev/isa/isavar.h>
103 #include <dev/pci/pcireg.h>
104 #include <dev/pci/pcivar.h>
106 #include <alpha/pci/a12creg.h>
107 #include <alpha/pci/a12cvar.h>
108 #include <alpha/pci/pci_a12.h>
110 #if 1
111 #define XB_DEBUG xb_debug
112 #else
113 #define XB_DEBUG 0
114 #endif
116 #undef Static
117 #if 1
118 #define Static
119 #else
120 #define Static static
121 #endif
123 #define IF_XB() /* Generate ctags(1) key */
125 #define XBAR_MTU (9*1024) /* Quite an arbitrary number */
126 #define XBAR_MAXFRAMEHDR 48 /* Used to compute if_mtu */
128 #define XB_DEFAULT_MTU() (XBAR_MTU - XBAR_MAXFRAMEHDR)
130 #define FIFO_WORDCOUNT 60
132 static int xb_put_blk(struct mbuf *);
133 static int xb_put(struct mbuf *);
134 static long xb_fifo_empty(void);
136 int xbmatch(struct device *, struct cfdata *, void *);
137 void xbattach(struct device *, struct device *, void *);
139 struct xb_softc {
140 struct device d;
141 } xb_softc;
143 CFATTACH_DECL(xb, sizeof(struct xb_softc),
144 xbmatch, xbattach, NULL, NULL);
146 extern struct cfdriver xb_cd;
148 long *xb_incoming;
149 int xb_incoming_max = XBAR_MTU;
151 typedef struct ccode_struct {
152 int64_t lo64, /* magic channel address s-word, high part*/
153 hi64; /* magic channel address s-word, low part */
154 } ccode_type;
156 * Switch channel codes. Prepending one of these words will get you through
157 * the switch, which will eat the word, open the addressed channel, and
158 * forward the rest of the switch frame. Obviously, this helps if the second
159 * switch word in the frame is the address word for a cascaded switch. (This
160 * can be repeated for an arbitrary depth of MSN.) The words aren't quite as
161 * weird as they look: the switch is really lots of narrow switches in an
162 * array, and they don't switch an even number of hex digits. Also, there is
163 * a parity bit on most of the subunits.
165 ccode_type channel[]={
166 { 0x0000000000000000, 0x0000000000000000 },
167 { 0x8882108421084210, 0x1104210842108421 },
168 { 0x4441084210842108, 0x2208421084210842 },
169 { 0xccc318c6318c6318, 0x330c6318c6318c63 },
170 { 0x2220842108421084, 0x4410842108421084 },
171 { 0xaaa294a5294a5294, 0x5514a5294a5294a5 },
172 { 0x66618c6318c6318c, 0x6618c6318c6318c6 },
173 { 0xeee39ce739ce739c, 0x771ce739ce739ce7 },
174 { 0x1110421084210842, 0x8821084210842108 },
175 { 0x99925294a5294a52, 0x9925294a5294a529 },
176 { 0x55514a5294a5294a, 0xaa294a5294a5294a },
177 { 0xddd35ad6b5ad6b5a, 0xbb2d6b5ad6b5ad6b },
178 { 0x3330c6318c6318c6, 0xcc318c6318c6318c },
179 { 0xbbb2d6b5ad6b5ad6, 0xdd35ad6b5ad6b5ad }
182 Static enum xb_intr_rcv_state_t {
183 XBIR_PKTHDR = 0, XBIR_TRANS
184 } xb_intr_rcv_state;
186 struct xb_config { int am_i_used; } xb_configuration;
188 Static struct ifnet xbi;
190 Static int frame_len;
191 static int xb_debug;
193 Static void xb_start(struct ifnet *);
194 Static void xb_mcrp_write(long *, int, int);
195 static inline void xb_onefree(void);
196 static long set_interrupt_on_fifo_empty(void);
197 static void xb_init(struct ifnet *);
198 static int xb_intr(void *);
199 static void xb_intr_rcv(void);
200 Static void quickload(volatile long *, long *);
201 static void xb_init_config(struct xb_config *, int);
202 static int xb_output(struct ifnet *, struct mbuf *,
203 const struct sockaddr *, struct rtentry *);
204 static int xb_ioctl(struct ifnet *, u_long, void *);
205 static void xb_stop(void);
206 static void a12_xbar_setup(void);
208 /* There Can Be Only One */
210 int xbfound;
213 xbmatch(struct device *parent, struct cfdata *match, void *aux)
216 return cputype == ST_AVALON_A12
217 && !xbfound;
220 void
221 xbattach(struct device *parent, struct device *self, void *aux)
223 struct xb_config *ccp;
225 strcpy(xbi.if_xname, self->dv_xname);
226 xbfound = 1;
227 ccp = &xb_configuration;
228 xb_init_config(ccp, 1);
229 printf(": driver %s mtu %lu\n", "$Revision: 1.24 $", xbi.if_mtu);
232 static void
233 xb_init_config(struct xb_config *ccp, int mallocsafe)
236 * The driver actually only needs about 64 bytes of buffer but with a
237 * nice contiguous frame we can call m_devget()
239 if (mallocsafe && xb_incoming == NULL) {
240 xb_incoming = malloc(xb_incoming_max, M_DEVBUF, M_NOWAIT);
241 if (xb_incoming == NULL)
242 DIE();
244 a12_xbar_setup();
245 a12_intr_register_xb(xb_intr);
249 * From The A12 Theory of Operation. Used with permission.
250 * --- --- ------ -- ---------
252 * Message Channel Status Register
254 * 31 0
255 * | |
256 * 10987654 32109876 54321098 76543210
258 * ........ ........ 0oiefaAr TR...... MCSR
260 * Field Type Name Function
262 * R R,W1C RBC Receive Block Complete
263 * T R,W1C TBC Transmit Block Complete
264 * r R IMP Incoming message pending
265 * A R IMFAE Incoming message fifo almost empty
266 * a R OMFAF Outgoing message fifo almost full
267 * f R OMFF Outgoing message fifo full
268 * e R OMFE Outgoing message fifo empty
269 * i R DMAin Incoming DMA channel armed
270 * o R DMAout Outgoing DMA channel armed
272 * Interrupts Generated from MCSR
274 * IMChInt <= (RBC or IMP) and not DMAin
275 * OMChInt <= ((TBC and not OMFAF) or (OMFE and OMR.E(6))
276 * ) and not DMAout
279 static int
280 xb_intr(void *p)
282 int n;
283 long mcsrval;
285 * The actual conditions under which this interrupt is generated are
286 * a bit complicated, and no status flag is available that reads out
287 * the final values of the interrupt inputs. But, it doesn't really
288 * matter. Simply check for receive data and transmitter IFF_OACTIVE.
290 while ((mcsrval = REGVAL(A12_MCSR)) & A12_MCSR_IMP)
291 for(n = mcsrval & A12_MCSR_IMFAE ? 1 : 5; n; --n)
292 xb_intr_rcv();
294 if (xbi.if_flags & IFF_OACTIVE
295 && mcsrval & A12_MCSR_OMFE) {
296 xbi.if_flags &= ~IFF_OACTIVE;
297 REGVAL(A12_OMR) &= ~A12_OMR_OMF_ENABLE;
298 alpha_wmb();
299 xb_start(&xbi);
301 return 0;
304 * The interface logic will shoot us down with MCE (Missing Close Error) or
305 * ECE (Embedded Close Error) if we aren't in sync with the hardware w.r.t.
306 * frame boundaries. As those are panic-level errors: Don't Get Them.
308 static void
309 xb_intr_rcv(void)
311 struct mbuf *m;
312 long frameword[2];
313 static long *xb_ibp;
314 int s = 0; /* XXX gcc */
316 switch (xb_intr_rcv_state) {
317 case XBIR_PKTHDR:
318 xb_ibp = xb_incoming;
319 quickload(REGADDR(A12_FIFO), frameword); /* frame_len >= 16 */
320 frame_len = frameword[0];
321 if (!(20 <= frame_len && frame_len+16 <= xb_incoming_max))
322 DIE();
324 * The extra word when frames are of an aligned size is due
325 * to the way the output routines work. After the mbuf is
326 * sent xb_put_blk(NULL) is called. If there is a leftover
327 * 127-bit-or-less fragment then the close word rides on it,
328 * otherwise it gets an entire 128 bits of zeroes.
330 if (frame_len & 0xf)
331 frame_len = (frame_len + 0xf) >> 4;
332 else frame_len = (frame_len >> 4) + 1;
333 --frame_len; /* we read the frame len + the first packet int64 */
334 *xb_ibp++ = frameword[1];
335 xb_intr_rcv_state = XBIR_TRANS;
336 break;
337 case XBIR_TRANS:
338 if (frame_len > 1)
339 quickload(REGADDR(A12_FIFO), frameword);
340 else if (frame_len == 1) {
341 quickload(REGADDR(A12_FIFO_LWE), frameword);
342 xb_intr_rcv_state = XBIR_PKTHDR;
343 } else if (XB_DEBUG)
344 DIE();
345 --frame_len;
346 xb_ibp[0] = frameword[0];
347 xb_ibp[1] = frameword[1];
348 xb_ibp += 2;
349 if (xb_intr_rcv_state == XBIR_PKTHDR) {
350 if (XB_DEBUG) {
351 s = splnet();
352 if (s != splnet())
353 DIE();
355 ++xbi.if_ipackets;
356 if (IF_QFULL(&ipintrq)) {
357 IF_DROP(&ipintrq);
358 ++xbi.if_iqdrops;
359 } else {
360 m = m_devget((void *)xb_incoming,
361 (char *)xb_ibp - (char *)xb_incoming,
362 0, &xbi, 0L);
363 if (m) {
364 xbi.if_ibytes += m->m_pkthdr.len;
365 IF_ENQUEUE(&ipintrq, m);
366 } else
367 ++xbi.if_ierrors;
369 if (XB_DEBUG)
370 splx(s);
372 break;
373 default:
374 DIE();
378 * Make it easy for gcc to load a[0..1] without interlocking between
379 * a[0] and a[1]. (If it did, that would be two external bus cycles.)
381 Static void
382 quickload(volatile long *a, long *b)
384 long t1,t2;
386 t1 = a[0];
387 t2 = a[1];
388 b[0] = t1;
389 b[1] = t2;
392 * Verify during debugging that we have not overflowed the FIFO
394 static inline void
395 xb_onefree(void)
397 if (XB_DEBUG && REGVAL(A12_MCSR) & A12_MCSR_OMFF)
398 DIE();
401 static void
402 xb_init(struct ifnet *ifp)
404 ifp->if_flags |= IFF_RUNNING;
407 static void
408 xb_stop(void)
412 static int
413 xb_ioctl(struct ifnet *ifp, unsigned long cmd, void *data)
415 struct ifaddr *ifa = (struct ifaddr *)data;
416 int s, error = 0;
418 s = splnet();
419 switch (cmd) {
420 case SIOCINITIFADDR:
421 xbi.if_flags |= IFF_UP;
422 xb_init(ifp);
423 break;
424 case SIOCSIFFLAGS:
425 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
426 break;
427 if ((ifp->if_flags & IFF_UP) == 0 &&
428 (ifp->if_flags & IFF_RUNNING) != 0) {
429 xb_stop();
430 ifp->if_flags &= ~IFF_RUNNING;
431 } else if ((ifp->if_flags & IFF_UP) != 0 &&
432 (ifp->if_flags & IFF_RUNNING) == 0) {
433 xb_start(ifp);
434 } else
435 xb_init(ifp);
436 if (ifp->if_flags & IFF_DEBUG)
437 xb_debug = 1;
438 break;
439 default:
440 error = ifioctl_common(ifp, cmd, data);
441 break;
443 splx(s);
444 return error;
447 * XXX - someday, keep a software copy of A12_OMR. We can execute up to
448 * 200 or 300 instructions in the time it takes to do the read part of an
449 * external bus cycle RMW op. (Or 10 - 20 cache cycles.)
451 static inline long
452 xb_fifo_empty(void)
454 return REGVAL(A12_MCSR) & A12_MCSR_OMFE;
457 * rtmon frames
459 * [ (... data) : commid : sourcepid : dstpid : ktype : length : frametype ]
461 * At the moment, NetBSD ip frames are not compatible with rtmon frames:
463 * [ ... data : length ]
465 static int
466 xb_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, struct rtentry *rt0)
468 int i,s;
469 struct mbuf *m = m0;
470 const char *lladdr;
471 char *xbh;
472 long xbo_framesize;
473 const struct sockaddr_dl *llsa;
474 int xbaddr;
476 #ifdef DIAGNOSTIC
477 if (ifp != &xbi)
478 DIE();
479 #endif
480 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
481 m_freem(m);
482 return ENETDOWN;
485 * We want an IP packet with a link level route, on a silver platter.
487 if (rt0 == NULL
488 || (rt0->rt_flags & (RTF_GATEWAY | RTF_LLINFO))
489 || (llsa = satocsdl(rt0->rt_gateway)) == NULL
490 || llsa->sdl_family != AF_LINK
491 || llsa->sdl_slen != 0) {
492 ++ifp->if_oerrors;
493 m_freem(m);
494 return EHOSTUNREACH;
496 if (dst == NULL
497 || dst->sa_family != AF_INET) {
499 * This is because we give all received packets to ipintrq
500 * right now.
502 What();
503 m_freem(m);
504 ++ifp->if_noproto;
505 return EAFNOSUPPORT;
508 * The a12MppSwitch is a wormhole routed MSN consisting of a number
509 * (usually n==1) of 14 channel crossbar switches. Each route through
510 * a switch requires a 128 bit address word that specifies the channel
511 * to emerge on. The address word is eaten by the switch and the
512 * rest of the packet is routed through.
514 lladdr = CLLADDR(llsa);
515 if (llsa->sdl_alen != 1) /* XXX */
516 DIE(); /* OK someday, but totally unexpected right now */
518 * Alternatively, we could lookup the address word and output
519 * it with PIO when the mbuf is dequeued
521 xbo_framesize = m->m_pkthdr.len + 8;
522 M_PREPEND(m, 16 * llsa->sdl_alen + 8, M_DONTWAIT);
523 if (m == NULL)
524 return ENOBUFS;
525 xbh = mtod(m, char *);
526 for (i=0; i<llsa->sdl_alen; ++i) {
527 xbaddr = (lladdr[i] & 0xff) - 1;
528 if (!(0 <= xbaddr && xbaddr <= 11)) /* XXX */
529 DIE(); /* 12 or 13 will be OK later */
530 memcpy(xbh, &channel[xbaddr].lo64, 16);
531 xbh += 16;
533 memcpy(xbh, &xbo_framesize, 8);
534 s = splnet();
535 if (IF_QFULL(&ifp->if_snd)) {
536 IF_DROP(&ifp->if_snd);
537 ++ifp->if_oerrors;
538 splx(s);
539 m_freem(m);
540 return ENOBUFS;
542 ifp->if_obytes += m->m_pkthdr.len;
543 ++ifp->if_opackets;
544 IF_ENQUEUE(&ifp->if_snd, m);
545 if ((ifp->if_flags & IFF_OACTIVE) == 0)
546 xb_start(ifp);
547 splx(s);
548 if (m->m_flags & M_MCAST)
549 ifp->if_omcasts++;
550 return 0;
553 void
554 xb_start(struct ifnet *ifp)
556 struct mbuf *m;
558 if ((xbi.if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
559 return;
560 for (;;) {
561 IF_DEQUEUE(&xbi.if_snd, m);
562 if (m == 0)
563 return;
565 * XXX The variable-length switch address words cause problems
566 * for bpf, for now, leave it out. XXX It's not too hard to
567 * fix, though, as there are lots of techniques that will
568 * identify the number of switch address words.
570 if (!xb_put(m)) {
571 xbi.if_flags |= IFF_OACTIVE;
572 return;
577 static int
578 xb_put(struct mbuf *m)
580 struct mbuf *n;
581 int len;
583 if (XB_DEBUG && (alpha_pal_rdps() & 7) < 3)
584 DIE(); /* this "cannot happen", of course */
585 for (; m; m = n) {
586 len = m->m_len;
587 if (len == 0 || xb_put_blk(m))
588 MFREE(m, n);
589 else return 0;
591 xb_put_blk(NULL);
592 return 1;
595 * Write a single mbuf to the transmit channel fifo. We can only write 128-bit
596 * words. Right now, we pad at the end. It is possible to pad at the
597 * beginning, especially since lots of games can be played at the receiver
598 * with the mbuf data pointer. Padding at the beginning requires a pad-count
599 * field in a header, but it means you can always DMA the data, regardless of
600 * alignment. Of course, we don't DMA at all, right now.
602 static int
603 xb_put_blk(struct mbuf *m)
605 static long leftover[2]; /* 0-15 bytes from last xb_put_blk() */
606 static int leftover_len; /* non-aligned amount from last call */
607 long xfertmp[8]; /* aligned switch word buffer */
608 int frag_len, /* fifo stream unit */
609 fifo_len, /* space left in fifo */
610 fillin, /* amount needed to complete a switch word */
611 full, /* remember to restart on fifo full */
612 len; /* amount of mbuf left to do */
613 char *blk; /* location we are at in mbuf */
614 static int fifo_free; /* current # of switch words free in fifo */
616 #define XFERADJ() ((char *)xfertmp + leftover_len)
618 /* There is always room for the close word */
620 if (m == NULL) {
621 if (leftover_len)
622 leftover_len = 0;
623 else leftover[0] = leftover[1] = 0;
624 xb_mcrp_write(leftover, 1, 1);
625 --fifo_free;
626 return 1;
629 restart:
630 if (fifo_free < 2) {
631 if (!xb_fifo_empty()) {
632 if(!set_interrupt_on_fifo_empty()) {
633 /* still empty */
634 xbi.if_flags |= IFF_OACTIVE;
635 IF_PREPEND(&xbi.if_snd, m);
636 return 0;
639 fifo_free = FIFO_WORDCOUNT;
641 len = m->m_len;
642 if (len == 0)
643 return 1; /* clean finish, nothing left over */
644 blk = mtod(m, char *);
645 if (leftover_len) {
646 /* See function intro comment regarding padding */
647 if (leftover_len + len < sizeof leftover) {
648 /* Heh, not even enough to write out */
649 memcpy(XFERADJ(), blk, len);
650 leftover_len += len;
651 return 1;
653 xfertmp[0] = leftover[0];
654 xfertmp[1] = leftover[1];
655 fillin = sizeof leftover - leftover_len;
656 memcpy(XFERADJ(), blk, fillin);
657 blk += fillin;
658 len -= fillin;
659 xb_mcrp_write(xfertmp, 1, 0);
660 leftover_len = 0;
661 --fifo_free;
663 /* fifo_free is known to be >= 1 at this point */
664 while (len >= 16) {
665 full = 0;
666 frag_len = sizeof xfertmp;
667 if (frag_len > len)
668 frag_len = len;
669 fifo_len = fifo_free * 16;
670 if (frag_len > fifo_len) {
671 frag_len = fifo_len;
672 full = 1;
674 frag_len &= ~0xf;
675 memcpy(xfertmp, blk, frag_len);
676 frag_len >>= 4; /* Round down to switch word size */
677 xb_mcrp_write(xfertmp, frag_len, 0);
678 fifo_free -= frag_len;
679 frag_len <<= 4;
680 len -= frag_len;
681 blk += frag_len;
682 if (full) {
683 m_adj(m, blk - mtod(m, char *));
684 goto restart;
687 memcpy(leftover, blk, len);
688 leftover_len = len;
689 return 1;
692 static long
693 set_interrupt_on_fifo_empty(void)
695 REGVAL(A12_OMR) |= A12_OMR_OMF_ENABLE;
696 alpha_mb();
697 if(xb_fifo_empty()) {
698 REGVAL(A12_OMR) &= ~A12_OMR_OMF_ENABLE;
699 alpha_mb();
700 return 1;
702 return 0;
705 * Write an aligned block of switch words to the FIFO
707 Static void
708 xb_mcrp_write(long *d, int n, int islast)
710 volatile long *xb_fifo = islast ? REGADDR(A12_FIFO_LWE)
711 : REGADDR(A12_FIFO);
712 int i;
714 if (XB_DEBUG && islast && n != 1)
715 DIE();
716 n <<= 1;
717 for (i = 0; i < n; i += 2) {
718 xb_onefree();
719 xb_fifo[0] = d[i];
720 xb_fifo[1] = d[i+1];
721 alpha_wmb();
726 const
727 int32_t xbar_bc_addr = XBAR_BROADCAST;
730 static void
731 a12_xbar_setup()
733 xbi.if_softc = &xb_softc;
734 xbi.if_start = xb_start;
735 xbi.if_ioctl = xb_ioctl;
736 xbi.if_flags = IFF_BROADCAST /* ha ha */
737 | IFF_SIMPLEX;
739 xbi.if_type = IFT_A12MPPSWITCH;
740 xbi.if_addrlen = 32;
741 xbi.if_hdrlen = 32;
742 xbi.if_mtu = XB_DEFAULT_MTU();
743 xbi.if_output = xb_output;
744 /* xbi.if_broadcastaddr = (u_int8_t)&xbar_bc_addr; */
746 if_attach(&xbi);
747 if_alloc_sadl(&xbi);
749 #if NBPFILTER > 0
750 bpfattach(&xbi, DLT_NULL, 0);
751 #endif