From ddde99135e151b07529f525a438b7f0c832a72bb Mon Sep 17 00:00:00 2001 From: ross Date: Wed, 23 Sep 1998 21:14:58 +0000 Subject: [PATCH] A12 crossbar switch driver. --- sys/arch/alpha/a12/if_xb.c | 781 +++++++++++++++++++++++++++++++++++++ sys/arch/alpha/a12/if_xb.h | 82 ++++ 2 files changed, 863 insertions(+) create mode 100644 sys/arch/alpha/a12/if_xb.c create mode 100644 sys/arch/alpha/a12/if_xb.h diff --git a/sys/arch/alpha/a12/if_xb.c b/sys/arch/alpha/a12/if_xb.c new file mode 100644 index 000000000000..1b3fb7bae198 --- /dev/null +++ b/sys/arch/alpha/a12/if_xb.c @@ -0,0 +1,781 @@ +/* $NetBSD: if_xb.c,v 1.1 1998/09/23 21:14:58 ross Exp $ */ + +/* [Notice revision 2.2] + * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc. + * All rights reserved. + * + * Author: Ross Harvey + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright and + * author notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. This copyright will be assigned to The NetBSD Foundation on + * 1/1/2000 unless these terms (including possibly the assignment + * date) are updated in writing by Avalon prior to the latest specified + * assignment date. + * + * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Notes. + * + * Since the NetBSD build rules force the use of function prototypes, even on + * functions that are defined before they are called, I've taken advantage of + * the opportunity and organized this module in top down fashion, with + * functions generally calling down the page rather than up. It's different. + * I think I'm getting to like it this way. + * + * The crossbar interface is not exactly a peripheral device, and it cannot + * appear on anything other than an alpha-based Avalon A12. The crossbar + * controller is built into the core logic. + * + * If this version of the driver supports MPS transport, it may have some + * large static data declarations. Don't worry about it, as Avalon a12 + * support should not appear in a GENERIC or INSTALL kernel. + * + * (Every A12 ever shipped had 512 MB per CPU except one site, which had 256 + * MB. Partly has a result of this, it is unlikely that a kernel configured + * for an A12 would be exactly the thing to use on most workstations, so we + * don't really need to worry that we might be configured in a generic or + * site-wide kernel image.) + * + * This preliminary crossbar driver supports IP transport using PIO. Although + * it would be nice to have a DMA driver, do note that the crossbar register + * port is 128 bits wide, so we have 128-bit PIO. (The 21164 write buffer + * will combine two 64-bit stores before they get off-chip.) Also, the rtmon + * driver wasn't DMA either, so at least the NetBSD driver is as good as any + * other that exists now. + * + * We'll do DMA and specialized transport ops later. Given the high speed of + * the PIO mode, no current applications require DMA bandwidth, but everyone + * benefits from low latency. The PIO mode is actually lower in latency + * anyway. + */ + +#include "opt_avalon_a12.h" /* Config options headers */ +#include /* RCS ID & Copyright macro defns */ + +__KERNEL_RCSID(0, "$NetBSD: if_xb.c,v 1.1 1998/09/23 21:14:58 ross Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 1 +#define XB_DEBUG xb_debug +#else +#define XB_DEBUG 0 +#endif + +#undef Static +#if 1 +#define Static +#else +#define Static static +#endif + +#define IF_XB() /* Generate ctags(1) key */ + +#define XBAR_MTU (9*1024) /* Quite an arbitrary number */ +#define XBAR_MAXFRAMEHDR 48 /* Used to compute if_mtu */ + +#define XB_DEFAULT_MTU() (XBAR_MTU - XBAR_MAXFRAMEHDR) + +#define FIFO_WORDCOUNT 60 + +static int xb_put_blk __P((struct mbuf *)); +static int xb_put __P((struct mbuf *)); +static long xb_fifo_empty(void); + +int xbmatch __P((struct device *, struct cfdata *, void *)); +void xbattach __P((struct device *, struct device *, void *)); + +struct xb_softc { + struct device d; +} xb_softc; + +struct cfattach xb_ca = { + sizeof(struct xb_softc), xbmatch, xbattach, +}; + +extern struct cfdriver xb_cd; + +long *xb_incoming; +int xb_incoming_max = XBAR_MTU; + +typedef struct ccode_struct { + int64_t lo64, /* magic channel address s-word, high part*/ + hi64; /* magic channel address s-word, low part */ +} ccode_type; +/* + * Switch channel codes. Prepending one of these words will get you through + * the switch, which will eat the word, open the addressed channel, and + * forward the rest of the switch frame. Obviously, this helps if the second + * switch word in the frame is the address word for a cascaded switch. (This + * can be repeated for an arbitrary depth of MSN.) The words aren't quite as + * wierd as they look: the switch is really lots of narrow switches in an + * array, and they don't switch an even number of hex digits. Also, there is + * a parity bit on most of the subunits. + */ +ccode_type channel[]={ + { 0x0000000000000000, 0x0000000000000000 }, + { 0x8882108421084210, 0x1104210842108421 }, + { 0x4441084210842108, 0x2208421084210842 }, + { 0xccc318c6318c6318, 0x330c6318c6318c63 }, + { 0x2220842108421084, 0x4410842108421084 }, + { 0xaaa294a5294a5294, 0x5514a5294a5294a5 }, + { 0x66618c6318c6318c, 0x6618c6318c6318c6 }, + { 0xeee39ce739ce739c, 0x771ce739ce739ce7 }, + { 0x1110421084210842, 0x8821084210842108 }, + { 0x99925294a5294a52, 0x9925294a5294a529 }, + { 0x55514a5294a5294a, 0xaa294a5294a5294a }, + { 0xddd35ad6b5ad6b5a, 0xbb2d6b5ad6b5ad6b }, + { 0x3330c6318c6318c6, 0xcc318c6318c6318c }, + { 0xbbb2d6b5ad6b5ad6, 0xdd35ad6b5ad6b5ad } +}; + +Static enum xb_intr_rcv_state_t { + XBIR_PKTHDR = 0, XBIR_TRANS +} xb_intr_rcv_state; + +struct xb_config { int am_i_used; } xb_configuration; + +Static struct ifnet xbi; + +Static int frame_len; +static int xb_debug; + +Static void xb_start __P((struct ifnet *)); +Static void xb_mcrp_write __P((long *, int, int)); +static __inline void xb_onefree __P((void)); +static long set_interrupt_on_fifo_empty(void); +static void xb_init(struct ifnet *); +static int xb_intr __P((void *)); +static void xb_intr_rcv __P((void)); +Static void quickload __P((volatile long *, long *)); +static void xb_init_config __P((struct xb_config *, int)); +static int xb_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); +static int xb_ioctl __P((struct ifnet *, u_long, caddr_t)); +static void xb_stop __P((void)); +static void a12_xbar_setup __P((void)); + +/* There Can Be Only One */ + +int xbfound; + +int +xbmatch(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pcibus_attach_args *pba = aux; + + return cputype == ST_AVALON_A12 + && strcmp(pba->pba_busname, xb_cd.cd_name) == 0 + && !xbfound; +} + +void +xbattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct xb_config *ccp; + + bcopy(self->dv_xname, xbi.if_xname, IFNAMSIZ); + xbfound = 1; + ccp = &xb_configuration; + xb_init_config(ccp, 1); + printf(": driver %s mtu %d\n", "$Revision: 1.1 $", xbi.if_mtu); +} + +static void +xb_init_config(ccp, mallocsafe) + struct xb_config *ccp; + int mallocsafe; +{ + /* + * The driver actually only needs about 64 bytes of buffer but with a + * nice contiguous frame we can call m_devget() + */ + if (mallocsafe && xb_incoming == NULL) { + xb_incoming = malloc(xb_incoming_max, M_DEVBUF, M_NOWAIT); + if (xb_incoming == NULL) + DIE(); + } + a12_xbar_setup(); + a12_intr_register_xb(xb_intr); +} + +/* + * From The A12 Theory of Operation. Used with permission. + * --- --- ------ -- --------- + * + * Message Channel Status Register + * + * 31 0 + * | | + * 10987654 32109876 54321098 76543210 + * + * ........ ........ 0oiefaAr TR...... MCSR + * + * Field Type Name Function + * + * R R,W1C RBC Receive Block Complete + * T R,W1C TBC Transmit Block Complete + * r R IMP Incoming message pending + * A R IMFAE Incoming message fifo almost empty + * a R OMFAF Outgoing message fifo almost full + * f R OMFF Outgoing message fifo full + * e R OMFE Outgoing message fifo empty + * i R DMAin Incoming DMA channel armed + * o R DMAout Outgoing DMA channel armed + * + * Interrupts Generated from MCSR + * + * IMChInt <= (RBC or IMP) and not DMAin + * OMChInt <= ((TBC and not OMFAF) or (OMFE and OMR.E(6)) + * ) and not DMAout + * + */ +static int +xb_intr(p) + void *p; +{ + int n; + long mcsrval; + /* + * The actual conditions under which this interrupt is generated are + * a bit complicated, and no status flag is available that reads out + * the final values of the interrupt inputs. But, it doesn't really + * matter. Simply check for receive data and transmitter IFF_OACTIVE. + */ + while ((mcsrval = REGVAL(A12_MCSR)) & A12_MCSR_IMP) + for(n = mcsrval & A12_MCSR_IMFAE ? 1 : 5; n; --n) + xb_intr_rcv(); + + if (xbi.if_flags & IFF_OACTIVE + && mcsrval & A12_MCSR_OMFE) { + xbi.if_flags &= ~IFF_OACTIVE; + REGVAL(A12_OMR) &= ~A12_OMR_OMF_ENABLE; + alpha_wmb(); + xb_start(&xbi); + } + return 0; +} +/* + * The interface logic will shoot us down with MCE (Missing Close Error) or + * ECE (Embedded Close Error) if we aren't in sync with the hardware w.r.t. + * frame boundaries. As those are panic-level errors: Don't Get Them. + */ +static void +xb_intr_rcv() +{ +struct mbuf *m; +long frameword[2]; +static long *xb_ibp; +int s = 0; /* XXX gcc */ + + switch (xb_intr_rcv_state) { + case XBIR_PKTHDR: + xb_ibp = xb_incoming; + quickload(REGADDR(A12_FIFO), frameword); /* frame_len >= 16 */ + frame_len = frameword[0]; + if (!(20 <= frame_len && frame_len+16 <= xb_incoming_max)) + DIE(); + /* + * The extra word when frames are of an aligned size is due + * to the way the the output routines work. After the mbuf is + * sent xb_put_blk(NULL) is called. If there is a leftover + * 127-bit-or-less fragment then the close word rides on it, + * otherwise it gets an entire 128 bits of zeroes. + */ + if (frame_len & 0xf) + frame_len = (frame_len + 0xf) >> 4; + else frame_len = (frame_len >> 4) + 1; + --frame_len; /* we read the frame len + the first packet int64 */ + *xb_ibp++ = frameword[1]; + xb_intr_rcv_state = XBIR_TRANS; + break; + case XBIR_TRANS: + if (frame_len > 1) + quickload(REGADDR(A12_FIFO), frameword); + else if (frame_len == 1) { + quickload(REGADDR(A12_FIFO_LWE), frameword); + xb_intr_rcv_state = XBIR_PKTHDR; + } else if (XB_DEBUG) + DIE(); + --frame_len; + xb_ibp[0] = frameword[0]; + xb_ibp[1] = frameword[1]; + xb_ibp += 2; + if (xb_intr_rcv_state == XBIR_PKTHDR) { + if (XB_DEBUG) { + s = splimp(); + if (s != splimp()) + DIE(); + } + ++xbi.if_ipackets; + if (IF_QFULL(&ipintrq)) { + IF_DROP(&ipintrq); + ++xbi.if_iqdrops; + } else { + m = m_devget((caddr_t)xb_incoming, + (caddr_t)xb_ibp - (caddr_t)xb_incoming, + 0, &xbi, 0L); + if (m) { + xbi.if_ibytes += m->m_pkthdr.len; + IF_ENQUEUE(&ipintrq, m); + } else + ++xbi.if_ierrors; + } + if (XB_DEBUG) + splx(s); + } + break; + default: + DIE(); + } +} +/* + * Make it easy for gcc to load a[0..1] without interlocking between + * a[0] and a[1]. (If it did, that would be two external bus cycles.) + */ +Static void +quickload(volatile long *a, long *b) +{ +long t1,t2; + + t1 = a[0]; + t2 = a[1]; + b[0] = t1; + b[1] = t2; +} +/* + * Verify during debugging that we have not overflowed the FIFO + */ +static __inline void +xb_onefree() +{ + if (XB_DEBUG && REGVAL(A12_MCSR) & A12_MCSR_OMFF) + DIE(); +} + +static void +xb_init(ifp) + struct ifnet *ifp; +{ + ifp->if_flags |= IFF_RUNNING; +} + +static void +xb_stop() +{ +} + +static int +xb_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifaddr *ifa = (struct ifaddr *)data; + int s, error = 0; + + s = splimp(); + switch (cmd) { + case SIOCSIFADDR: + xbi.if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + xb_init(ifp); + break; +#endif + default: + xb_init(ifp); + } + break; + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + xb_stop(); + ifp->if_flags &= ~IFF_RUNNING; + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + xb_start(ifp); + } else + xb_init(ifp); + if (ifp->if_flags & IFF_DEBUG) + xb_debug = 1; + break; + default: + error = EINVAL; + break; + } + splx(s); + return error; +} +/* + * XXX - someday, keep a software copy of A12_OMR. We can execute up to + * 200 or 300 instructions in the time it takes to do the read part of an + * external bus cycle RMW op. (Or 10 - 20 cache cycles.) + */ +static __inline long +xb_fifo_empty(void) +{ + return REGVAL(A12_MCSR) & A12_MCSR_OMFE; +} +/* + * rtmon frames + * + * [ (... data) : commid : sourcepid : dstpid : ktype : length : frametype ] + * + * At the moment, NetBSD ip frames are not compatible with rtmon frames: + * + * [ ... data : length ] + */ +static int +xb_output(ifp, m0, dst, rt0) + struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; + struct rtentry *rt0; +{ + int i,s; + struct mbuf *m = m0; + char *lladdr; + caddr_t xbh; + long xbo_framesize; + struct sockaddr_dl *llsa; + int xbaddr; + +#ifdef DIAGNOSTIC + if (ifp != &xbi) + DIE(); +#endif + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { + m_freem(m); + return ENETDOWN; + } + ifp->if_lastchange = time; + /* + * We want an IP packet with a link level route, on a silver platter. + */ + if (rt0 == NULL + || (rt0->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) + || (llsa = (struct sockaddr_dl *)rt0->rt_gateway) == NULL + || llsa->sdl_family != AF_LINK + || llsa->sdl_slen != 0) { + ++ifp->if_oerrors; + m_freem(m); + return EHOSTUNREACH; + } + if (dst == NULL + || dst->sa_family != AF_INET) { + /* + * This is because we give all received packets to ipintrq + * right now. + */ + What(); + m_freem(m); + ++ifp->if_noproto; + return EAFNOSUPPORT; + } + /* + * The a12MppSwitch is a wormhole routed MSN consisting of a number + * (usually n==1) of 14 channel crossbar switches. Each route through + * a switch requires a 128 bit address word that specifies the channel + * to emerge on. The address word is eaten by the switch and the + * rest of the packet is routed through. + */ + lladdr = LLADDR(llsa); + if (llsa->sdl_alen != 1) /* XXX */ + DIE(); /* OK someday, but totally unexpected right now */ + /* + * Alternatively, we could lookup the address word and output + * it with PIO when the mbuf is dequeued + */ + xbo_framesize = m->m_pkthdr.len + 8; + M_PREPEND(m, 16 * llsa->sdl_alen + 8, M_DONTWAIT); + if (m == NULL) + return ENOBUFS; + xbh = mtod(m, caddr_t); + for (i=0; isdl_alen; ++i) { + xbaddr = (lladdr[i] & 0xff) - 1; + if (!(0 <= xbaddr && xbaddr <= 11)) /* XXX */ + DIE(); /* 12 or 13 will be OK later */ + bcopy(&channel[xbaddr].lo64, xbh, 16); + xbh += 16; + } + bcopy(&xbo_framesize, xbh, 8); + s = splimp(); + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + ++ifp->if_oerrors; + splx(s); + m_freem(m); + return ENOBUFS; + } + ifp->if_obytes += m->m_pkthdr.len; + ++ifp->if_opackets; + IF_ENQUEUE(&ifp->if_snd, m); + if ((ifp->if_flags & IFF_OACTIVE) == 0) + xb_start(ifp); + splx(s); + if (m->m_flags & M_MCAST) + ifp->if_omcasts++; + return 0; +} + +void +xb_start(ifp) + struct ifnet *ifp; +{ + struct mbuf *m; + + if ((xbi.if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + for (;;) { + IF_DEQUEUE(&xbi.if_snd, m); + if (m == 0) + return; + /* + * XXX The variable-length switch address words cause problems + * for bpf, for now, leave it out. XXX It's not too hard to + * fix, though, as there are lots of techniques that will + * identify the number of switch address words. + */ + if (!xb_put(m)) { + xbi.if_flags |= IFF_OACTIVE; + return; + } + } +} + +static int +xb_put(m) + struct mbuf *m; +{ + struct mbuf *n; + int len; + + if (XB_DEBUG && (alpha_pal_rdps() & 7) < 3) + DIE(); /* this "cannot happen", of course */ + for (; m; m = n) { + len = m->m_len; + if (len == 0 || xb_put_blk(m)) + MFREE(m, n); + else return 0; + } + xb_put_blk(NULL); + return 1; +} +/* + * Write a single mbuf to the transmit channel fifo. We can only write 128-bit + * words. Right now, we pad at the end. It is possible to pad at the + * beginning, especially since lots of games can be played at the receiver + * with the mbuf data pointer. Padding at the beginning requires a pad-count + * field in a header, but it means you can always DMA the data, regardless of + * alignment. Of course, we don't DMA at all, right now. + */ +static int +xb_put_blk(m) + struct mbuf *m; +{ + static long leftover[2]; /* 0-15 bytes from last xb_put_blk() */ + static int leftover_len; /* non-aligned amount from last call */ + long xfertmp[8]; /* aligned switch word buffer */ + int frag_len, /* fifo stream unit */ + fifo_len, /* space left in fifo */ + fillin, /* amount needed to complete a switch word */ + full, /* remember to restart on fifo full */ + len; /* amount of mbuf left to do */ + caddr_t blk; /* location we are at in mbuf */ + static int fifo_free; /* current # of switch words free in fifo */ + +#define XFERADJ() ((caddr_t)xfertmp+leftover_len) + + /* There is always room for the close word */ + + if (m == NULL) { + if (leftover_len) + leftover_len = 0; + else leftover[0] = leftover[1] = 0; + xb_mcrp_write(leftover, 1, 1); + --fifo_free; + return 1; + } + +restart: + if (fifo_free < 2) { + if (!xb_fifo_empty()) { + if(!set_interrupt_on_fifo_empty()) { + /* still empty */ + xbi.if_flags |= IFF_OACTIVE; + IF_PREPEND(&xbi.if_snd, m); + return 0; + } + } + fifo_free = FIFO_WORDCOUNT; + } + len = m->m_len; + if (len == 0) + return 1; /* clean finish, nothing left over */ + blk = mtod(m, caddr_t); + if (leftover_len) { + /* See function intro comment regarding padding */ + if (leftover_len + len < sizeof leftover) { + /* Heh, not even enough to write out */ + bcopy(blk, XFERADJ(), len); + leftover_len += len; + return 1; + } + xfertmp[0] = leftover[0]; + xfertmp[1] = leftover[1]; + fillin = sizeof leftover - leftover_len; + bcopy(blk, XFERADJ(), fillin); + blk += fillin; + len -= fillin; + xb_mcrp_write(xfertmp, 1, 0); + leftover_len = 0; + --fifo_free; + } + /* fifo_free is known to be >= 1 at this point */ + while (len >= 16) { + full = 0; + frag_len = sizeof xfertmp; + if (frag_len > len) + frag_len = len; + fifo_len = fifo_free * 16; + if (frag_len > fifo_len) { + frag_len = fifo_len; + full = 1; + } + frag_len &= ~0xf; + bcopy(blk, xfertmp, frag_len); + frag_len >>= 4; /* Round down to switch word size */ + xb_mcrp_write(xfertmp, frag_len, 0); + fifo_free -= frag_len; + frag_len <<= 4; + len -= frag_len; + blk += frag_len; + if (full) { + m_adj(m, blk - mtod(m, caddr_t)); + goto restart; + } + } + bcopy(blk, leftover, len); + leftover_len = len; + return 1; +} + +static long +set_interrupt_on_fifo_empty(void) +{ + REGVAL(A12_OMR) |= A12_OMR_OMF_ENABLE; + alpha_mb(); + if(xb_fifo_empty()) { + REGVAL(A12_OMR) &= ~A12_OMR_OMF_ENABLE; + alpha_mb(); + return 1; + } + return 0; +} +/* + * Write an aligned block of switch words to the FIFO + */ +Static void +xb_mcrp_write(d, n, islast) + long *d; +{ + volatile long *xb_fifo = islast ? REGADDR(A12_FIFO_LWE) + : REGADDR(A12_FIFO); + int i; + + if (XB_DEBUG && islast && n != 1) + DIE(); + n <<= 1; + for (i = 0; i < n; i += 2) { + xb_onefree(); + xb_fifo[0] = d[i]; + xb_fifo[1] = d[i+1]; + alpha_wmb(); + } +} + +/* +const +int32_t xbar_bc_addr = XBAR_BROADCAST; + */ + +static void +a12_xbar_setup() +{ + xbi.if_softc = &xb_softc; + xbi.if_start = xb_start; + xbi.if_ioctl = xb_ioctl; + xbi.if_flags = IFF_BROADCAST /* ha ha */ + | IFF_SIMPLEX; + + if_attach(&xbi); + + xbi.if_type = IFT_A12MPPSWITCH; + xbi.if_addrlen = 32; + xbi.if_hdrlen = 32; + xbi.if_mtu = XB_DEFAULT_MTU(); + xbi.if_output = xb_output; + /* xbi.if_broadcastaddr = (u_int8_t)&xbar_bc_addr; */ + +#if NBPFILTER > 0 + bpfattach(&xbi.if_bpf, &xbi, DLT_NULL, 0); +#endif +} diff --git a/sys/arch/alpha/a12/if_xb.h b/sys/arch/alpha/a12/if_xb.h new file mode 100644 index 000000000000..ee7bd9f004b3 --- /dev/null +++ b/sys/arch/alpha/a12/if_xb.h @@ -0,0 +1,82 @@ +/* $NetBSD: if_xb.h,v 1.1 1998/09/23 21:14:58 ross Exp $ */ + +/* [Notice revision 2.2] + * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc. + * All rights reserved. + * + * Author: Ross Harvey + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright and + * author notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. This copyright will be assigned to The NetBSD Foundation on + * 1/1/2000 unless these terms (including possibly the assignment + * date) are updated in writing by Avalon prior to the latest specified + * assignment date. + * + * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ALPHA_PCI_A12CVAR_H_ +#define _ALPHA_PCI_A12CVAR_H_ + +#define A12CVAR() /* generate ctags(1) key */ + +#include +#include +#include +/* + * A12 Core Logic -a12c- configuration. + */ +struct a12c_config { + int ac_initted; + + bus_space_tag_t ac_iot, ac_memt; + struct alpha_pci_chipset ac_pc; + + struct alpha_bus_dma_tag ac_dmat_direct; + struct alpha_bus_dma_tag ac_dmat_sgmap; + + struct alpha_sgmap ac_sgmap; + + u_int32_t ac_hae_mem; + u_int32_t ac_hae_io; + + struct extent *ac_io_ex, *ac_d_mem_ex, *ac_s_mem_ex; + int ac_mallocsafe; +}; + +struct a12c_softc { + struct device sc_dev; + + struct a12c_config *sc_ccp; +}; + +void a12c_init __P((struct a12c_config *, int)); +void a12c_pci_init __P((pci_chipset_tag_t, void *)); +void a12c_dma_init __P((struct a12c_config *)); + +bus_space_tag_t a12c_bus_io_init __P((void *)); +bus_space_tag_t a12c_bus_mem_init __P((void *)); + +void a12_xbar_intr __P((void)); + +#endif