diff options
author | peter <peter@FreeBSD.org> | 1995-11-21 02:32:04 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1995-11-21 02:32:04 +0000 |
commit | 0b1628b7d8f2592efaa27f43319a9d6c4ab0b384 (patch) | |
tree | 5bf1a873469abae59f573b1494fc32399804dd69 /sys/i386 | |
parent | f83677214fa99948389eae05dfcfd8a042c3b595 (diff) | |
parent | 19429531170933a13c7c26f0ce49e3a096586bba (diff) | |
download | FreeBSD-src-0b1628b7d8f2592efaa27f43319a9d6c4ab0b384.zip FreeBSD-src-0b1628b7d8f2592efaa27f43319a9d6c4ab0b384.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r12437,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/isa/ic/hd64570.h | 366 | ||||
-rw-r--r-- | sys/i386/isa/if_ar.c | 1455 | ||||
-rw-r--r-- | sys/i386/isa/if_arregs.h | 141 |
3 files changed, 1962 insertions, 0 deletions
diff --git a/sys/i386/isa/ic/hd64570.h b/sys/i386/isa/ic/hd64570.h new file mode 100644 index 0000000..706e33a --- /dev/null +++ b/sys/i386/isa/ic/hd64570.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1995 John Hay. All rights reserved. + * + * 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 + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by [your name] + * and [any other names deserving credit ] + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY [your name] 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 THE REGENTS OR 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. + * + * $Id: hd64570.h,v 1.2 1995/11/08 16:20:35 jhay Exp $ + */ +#ifndef _HD64570_H_ +#define _HD64570_H_ + +typedef struct msci_channel + { + union + { + unsigned short us_trb; /* rw */ + struct + { + unsigned char uc_trbl; + unsigned char uc_trbh; + }uc_trb; + }u_trb; + unsigned char st0; /* ro */ + unsigned char st1; /* rw */ + unsigned char st2; /* rw */ + unsigned char st3; /* ro */ + unsigned char fst; /* rw */ + unsigned char unused0; + unsigned char ie0; /* rw */ + unsigned char ie1; /* rw */ + unsigned char ie2; /* rw */ + unsigned char fie; /* rw */ + unsigned char cmd; /* wo */ + unsigned char unused1; + unsigned char md0; /* rw */ + unsigned char md1; /* rw */ + unsigned char md2; /* rw */ + unsigned char ctl; /* rw */ + unsigned char sa0; /* rw */ + unsigned char sa1; /* rw */ + unsigned char idl; /* rw */ + unsigned char tmc; /* rw */ + unsigned char rxs; /* rw */ + unsigned char txs; /* rw */ + unsigned char trc0; /* rw */ + unsigned char trc1; /* rw */ + unsigned char rrc; /* rw */ + unsigned char unused2; + unsigned char cst0; /* rw */ + unsigned char cst1; /* rw */ + unsigned char unused3[2]; + }msci_channel; + +#define trb u_trb.us_trb +#define trbl u_trb.uc_trb.uc_trbl +#define trbh u_trb.uc_trb.uc_trbh + +typedef struct timer_channel + { + unsigned short tcnt; /* rw */ + unsigned short tconr; /* wo */ + unsigned char tcsr; /* rw */ + unsigned char tepr; /* rw */ + unsigned char unused[2]; + }timer_channel; + +typedef struct dmac_channel + { + unsigned short dar; /* rw */ + unsigned char darb; /* rw */ + unsigned char unused0; + unsigned short sar; /* rw On odd numbered dmacs (tx) only */ + unsigned char sarb; /* rw */ +#define cpb sarb; + unsigned char unused1; + unsigned short cda; /* rw */ + unsigned short eda; /* rw */ + unsigned short bfl; /* rw On even numbered dmacs (rx) only */ + unsigned short bcr; /* rw */ + unsigned char dsr; /* rw */ + unsigned char dmr; /* rw */ + unsigned char unused2; + unsigned char fct; /* rw */ + unsigned char dir; /* rw */ + unsigned char dcr; /* rw */ + unsigned char unused3[10]; + }dmac_channel; + +/* x is the channel number. rx channels are even numbered and tx, odd. */ +#define DMAC_RXCH(x) ((x*2) + 0) +#define DMAC_TXCH(x) ((x*2) + 1) + +typedef struct sca_regs + { + unsigned char lpr; /* rw */ + unsigned char unused0; /* -- */ + /* Wait system */ + unsigned char pabr0; /* rw */ + unsigned char pabr1; /* rw */ + unsigned char wcrl; /* rw */ + unsigned char wcrm; /* rw */ + unsigned char wcrh; /* rw */ + unsigned char unused1; + /* DMAC */ + unsigned char pcr; /* rw */ + unsigned char dmer; /* rw */ + unsigned char unused2[6]; + /* Interrupt */ + unsigned char isr0; /* ro */ + unsigned char isr1; /* ro */ + unsigned char isr2; /* ro */ + unsigned char unused3; + unsigned char ier0; /* rw */ + unsigned char ier1; /* rw */ + unsigned char ier2; /* rw */ + unsigned char unused4; + unsigned char itcr; /* rw */ + unsigned char unused5; + unsigned char ivr; /* rw */ + unsigned char unused6; + unsigned char imvr; /* rw */ + unsigned char unused7[3]; + /* MSCI Channel 0 */ + msci_channel msci[2]; + timer_channel timer[4]; + dmac_channel dmac[4]; + }sca_regs; + +#define SCA_CMD_TXRESET 0x01 +#define SCA_CMD_TXENABLE 0x02 +#define SCA_CMD_TXDISABLE 0x03 +#define SCA_CMD_TXCRCINIT 0x04 +#define SCA_CMD_TXCRCEXCL 0x05 +#define SCA_CMS_TXEOM 0x06 +#define SCA_CMD_TXABORT 0x07 +#define SCA_CMD_MPON 0x08 +#define SCA_CMD_TXBCLEAR 0x09 + +#define SCA_CMD_RXRESET 0x11 +#define SCA_CMD_RXENABLE 0x12 +#define SCA_CMD_RXDISABLE 0x13 +#define SCA_CMD_RXCRCINIT 0x14 +#define SCA_CMD_RXMSGREJ 0x15 +#define SCA_CMD_MPSEARCH 0x16 +#define SCA_CMD_RXCRCEXCL 0x17 +#define SCA_CMD_RXCRCCALC 0x18 + +#define SCA_CMD_NOP 0x00 +#define SCA_CMD_RESET 0x21 +#define SCA_CMD_SEARCH 0x31 + +#define SCA_MD0_CRC_1 0x01 +#define SCA_MD0_CRC_CCITT 0x02 +#define SCA_MD0_CRC_ENABLE 0x04 +#define SCA_MD0_AUTO_ENABLE 0x10 +#define SCA_MD0_MODE_ASYNC 0x00 +#define SCA_MD0_MODE_BYTESYNC1 0x20 +#define SCA_MD0_MODE_BISYNC 0x40 +#define SCA_MD0_MODE_BYTESYNC2 0x60 +#define SCA_MD0_MODE_HDLC 0x80 + +#define SCA_MD1_NOADDRCHK 0x00 +#define SCA_MD1_SNGLADDR1 0x40 +#define SCA_MD1_SNGLADDR2 0x80 +#define SCA_MD1_DUALADDR 0xC0 + +#define SCA_MD2_DUPLEX 0x00 +#define SCA_MD2_ECHO 0x01 +#define SCA_MD2_LOOPBACK 0x03 +#define SCA_MD2_ADPLLx8 0x00 +#define SCA_MD2_ADPLLx16 0x08 +#define SCA_MD2_ADPLLx32 0x10 +#define SCA_MD2_NRZ 0x00 +#define SCA_MD2_NRZI 0x20 +#define SCA_MD2_MANCHESTER 0x80 +#define SCA_MD2_FM0 0xC0 +#define SCA_MD2_FM1 0xA0 + +#define SCA_CTL_RTS 0x01 +#define SCA_CTL_IDLPAT 0x10 +#define SCA_CTL_UDRNC 0x20 + +#define SCA_RXS_DIV_MASK 0x0F +#define SCA_RXS_DIV1 0x00 +#define SCA_RXS_DIV2 0x01 +#define SCA_RXS_DIV4 0x02 +#define SCA_RXS_DIV8 0x03 +#define SCA_RXS_DIV16 0x04 +#define SCA_RXS_DIV32 0x05 +#define SCA_RXS_DIV64 0x06 +#define SCA_RXS_DIV128 0x07 +#define SCA_RXS_DIV256 0x08 +#define SCA_RXS_DIV512 0x09 +#define SCA_RXS_CLK_RXC0 0x00 +#define SCA_RXS_CLK_RXC1 0x20 +#define SCA_RXS_CLK_INT 0x40 +#define SCA_RXS_CLK_ADPLL_OUT 0x60 +#define SCA_RXS_CLK_ADPLL_IN 0x70 + +#define SCA_TXS_DIV_MASK 0x0F +#define SCA_TXS_DIV1 0x00 +#define SCA_TXS_DIV2 0x01 +#define SCA_TXS_DIV4 0x02 +#define SCA_TXS_DIV8 0x03 +#define SCA_TXS_DIV16 0x04 +#define SCA_TXS_DIV32 0x05 +#define SCA_TXS_DIV64 0x06 +#define SCA_TXS_DIV128 0x07 +#define SCA_TXS_DIV256 0x08 +#define SCA_TXS_DIV512 0x09 +#define SCA_TXS_CLK_TXC 0x00 +#define SCA_TXS_CLK_INT 0x40 +#define SCA_TXS_CLK_RX 0x60 + +#define SCA_ST0_RXRDY 0x01 +#define SCA_ST0_TXRDY 0x02 +#define SCA_ST0_RXINT 0x40 +#define SCA_ST0_TXINT 0x80 + +#define SCA_ST1_IDLST 0x01 +#define SCA_ST1_ABTST 0x02 +#define SCA_ST1_DCDCHG 0x04 +#define SCA_ST1_CTSCHG 0x08 +#define SCA_ST1_FLAG 0x10 +#define SCA_ST1_TXIDL 0x40 +#define SCA_ST1_UDRN 0x80 + +/* ST2 and FST look the same */ +#define SCA_FST_CRCERR 0x04 +#define SCA_FST_OVRN 0x08 +#define SCA_FST_RESFRM 0x10 +#define SCA_FST_ABRT 0x20 +#define SCA_FST_SHRT 0x40 +#define SCA_FST_EOM 0x80 + +#define SCA_ST3_RXENA 0x01 +#define SCA_ST3_TXENA 0x02 +#define SCA_ST3_DCD 0x04 +#define SCA_ST3_CTS 0x08 +#define SCA_ST3_ADPLLSRCH 0x10 +#define SCA_ST3_TXDATA 0x20 + +#define SCA_FIE_EOMFE 0x80 + +#define SCA_IE0_RXRDY 0x01 +#define SCA_IE0_TXRDY 0x02 +#define SCA_IE0_RXINT 0x40 +#define SCA_IE0_TXINT 0x80 + +#define SCA_IE1_IDLDE 0x01 +#define SCA_IE1_ABTDE 0x02 +#define SCA_IE1_DCD 0x04 +#define SCA_IE1_CTS 0x08 +#define SCA_IE1_FLAG 0x10 +#define SCA_IE1_IDL 0x40 +#define SCA_IE1_UDRN 0x80 + +#define SCA_IE2_CRCERR 0x04 +#define SCA_IE2_OVRN 0x08 +#define SCA_IE2_RESFRM 0x10 +#define SCA_IE2_ABRT 0x20 +#define SCA_IE2_SHRT 0x40 +#define SCA_IE2_EOM 0x80 + +/* This is for RRC, TRC0 and TRC1. */ +#define SCA_RCR_MASK 0x1F + +#define SCA_IE1_ + +#define SCA_IV_CHAN0 0x00 +#define SCA_IV_CHAN1 0x20 + +#define SCA_IV_RXRDY 0x04 +#define SCA_IV_TXRDY 0x06 +#define SCA_IV_RXINT 0x08 +#define SCA_IV_TXINT 0x0A + +#define SCA_IV_DMACH0 0x00 +#define SCA_IV_DMACH1 0x08 +#define SCA_IV_DMACH2 0x20 +#define SCA_IV_DMACH3 0x28 + +#define SCA_IV_DMIA 0x14 +#define SCA_IV_DMIB 0x16 + +#define SCA_IV_TIMER0 0x1C +#define SCA_IV_TIMER1 0x1E +#define SCA_IV_TIMER2 0x3C +#define SCA_IV_TIMER3 0x3E + +/* + * DMA registers + */ +#define SCA_DSR_EOT 0x80 +#define SCA_DSR_EOM 0x40 +#define SCA_DSR_BOF 0x20 +#define SCA_DSR_COF 0x10 +#define SCA_DSR_DE 0x02 +#define SCA_DSR_DWE 0x01 + +#define SCA_DMR_TMOD 0x10 +#define SCA_DMR_NF 0x04 +#define SCA_DMR_CNTE 0x02 + +#define SCA_DMER_EN 0x80 + +#define SCA_DCR_ABRT 0x01 +#define SCA_DCR_FCCLR 0x02 /* Clear frame end intr counter */ + +#define SCA_DIR_EOT 0x80 +#define SCA_DIR_EOM 0x40 +#define SCA_DIR_BOF 0x20 +#define SCA_DIR_COF 0x10 + +typedef struct sca_descriptor + { + unsigned short cp; + unsigned short bp; + unsigned char bpb; + unsigned char unused0; + unsigned short len; + unsigned char stat; + unsigned char unused1; + }sca_descriptor; + +#define SCA_DESC_EOT 0x01 +#define SCA_DESC_CRC 0x04 +#define SCA_DESC_OVRN 0x08 +#define SCA_DESC_RESD 0x10 +#define SCA_DESC_ABORT 0x20 +#define SCA_DESC_SHRTFRM 0x40 +#define SCA_DESC_EOM 0x80 +#define SCA_DESC_ERRORS 0x7C + +/* +*************************************************************************** +** END +*************************************************************************** +**/ +#endif /* _HD64570_H_ */ + diff --git a/sys/i386/isa/if_ar.c b/sys/i386/isa/if_ar.c new file mode 100644 index 0000000..ce46405 --- /dev/null +++ b/sys/i386/isa/if_ar.c @@ -0,0 +1,1455 @@ +/* + * Copyright (c) 1995 John Hay. All rights reserved. + * + * 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 + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Hay. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY John Hay ``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 John Hay 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. + * + * $Id: if_ar.c,v 1.7 1995/11/16 20:16:34 jhay Exp $ + */ + +/* + * Programming assumptions and other issues. + * + * The descriptors of a DMA channel will fit in a 16K memory window. + * + * The buffers of a transmit DMA channel will fit in a 16K memory window. + * + * Only the ISA bus and V.35 is tested. + * + * When interface is going up, handshaking is set and it is only cleared + * when the interface is down'ed. + * + * There should be a way to set/reset Raw HDLC/PPP, Loopback, DCE/DTE, + * internal/external clock, etc..... + * + */ + +#include "ar.h" +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/conf.h> +#include <sys/errno.h> +#include <sys/malloc.h> + +#include <sys/syslog.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_sppp.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#include <sys/devconf.h> +#include <machine/clock.h> + +#include <i386/isa/if_arregs.h> +#include <i386/isa/ic/hd64570.h> + +#ifdef TRACE +#define TRC(x) x +#else +#define TRC(x) +#endif + +#define TRCL(x) x + +#define PPP_HEADER_LEN 4 + +#define ARC_GET_WIN(addr) ((addr >> ARC_WIN_SHFT) & AR_WIN_MSK) + +#define ARC_SET_MEM(iobase,win) outb(iobase+AR_MSCA_EN, AR_ENA_MEM | \ + ARC_GET_WIN(win)) +#define ARC_SET_SCA(iobase,ch) outb(iobase+AR_MSCA_EN, AR_ENA_MEM | \ + AR_ENA_SCA | (ch ? AR_SEL_SCA_1:AR_SEL_SCA_0)) +#define ARC_SET_OFF(iobase) outb(iobase+AR_MSCA_EN, 0) + +#define ARUNIT2SC(unit) ar_sc_ind[unit] + +static struct ar_hardc { + int cunit; + struct ar_softc *sc; + u_short iobase; + int startunit; + int numports; + caddr_t mem_start; + caddr_t mem_end; + + u_int memsize; /* in bytes */ + u_char bustype; /* ISA, MCA, PCI.... */ + u_char interface; /* X21, V.35, EIA-530.... */ + u_char revision; + u_char handshake; /* handshake lines supported by card. */ + + u_char txc_dtr[NPORT/NCHAN]; /* the register is write only */ + u_int txc_dtr_off[NPORT/NCHAN]; + + sca_regs *sca; + + struct kern_devconf kdc; +}ar_hardc[NAR]; + +struct ar_softc { + struct sppp ifsppp; + int unit; /* With regards to all ar devices */ + int subunit; /* With regards to this card */ + struct ar_hardc *hc; + caddr_t bpf; + + u_int txdesc; /* On card address */ + u_int txstart; /* On card address */ + u_int txend; /* On card address */ + u_int txtail; /* Index of first unused buffer */ + u_int txmax; /* number of usable buffers/descriptors */ + + u_int rxdesc; /* On card address */ + u_int rxstart; /* On card address */ + u_int rxend; /* On card address */ + u_int rxhind; /* Index to the head of the rx buffers. */ + u_int rxmax; /* number of usable buffers/descriptors */ + + int scano; + int scachan; + + struct kern_devconf kdc; +}; + +struct ar_softc *ar_sc_ind[NAR*NPORT]; + +int arprobe(struct isa_device *id); +int arattach(struct isa_device *id); + +/* + * This translate from irq numbers to + * the value that the arnet card needs + * in the lower part of the AR_INT_SEL + * register. + */ +static int irqtable[16] = { + 0, /* 0 */ + 0, /* 1 */ + 0, /* 2 */ + 1, /* 3 */ + 0, /* 4 */ + 2, /* 5 */ + 0, /* 6 */ + 3, /* 7 */ + 0, /* 8 */ + 0, /* 9 */ + 4, /* 10 */ + 5, /* 11 */ + 6, /* 12 */ + 0, /* 13 */ + 0, /* 14 */ + 7 /* 15 */ +}; + +struct isa_driver ardriver = {arprobe, arattach, "arc"}; + +static struct kern_devconf kdc_ar_template = { + 0, 0, 0, + "ar", 0, { MDDT_ISA, 0, "net" }, + isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, + &kdc_isa0, + 0, + DC_UNCONFIGURED, + "Arnet SYNC/570i Port", + DC_CLS_NETIF +}; + +static struct kern_devconf kdc_arc_template = { + 0, 0, 0, + "arc", 0, { MDDT_ISA, 0, "net" }, + isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, + &kdc_isa0, + 0, + DC_UNCONFIGURED, + "Arnet SYNC/570i Adapter", + DC_CLS_NETIF +}; + +void arstart(struct ifnet *ifp); +int arioctl(struct ifnet *ifp, int cmd, caddr_t data); +void arwatchdog(int port_number); +void arinit(int port_number); + +static void ar_up(struct ar_softc *sc); +static void ar_down(struct ar_softc *sc); +static void arc_init(struct isa_device *id); +static void ar_init_sca(struct ar_hardc *hc, int scano); +static void ar_init_msci(struct ar_softc *sc); +static void ar_init_rx_dmac(struct ar_softc *sc); +static void ar_init_tx_dmac(struct ar_softc *sc); +static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr); +static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr); +static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr); + +static inline void ar_registerdev(int ctlr, int unit) +{ + struct ar_softc *sc; + + sc = &ar_hardc[ctlr].sc[unit]; + sc->kdc = kdc_ar_template; + + sc->kdc.kdc_unit = ar_hardc[ctlr].startunit + unit; + sc->kdc.kdc_parentdata = &ar_hardc[ctlr].kdc; + dev_attach(&sc->kdc); +} + +static inline void arc_registerdev(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + struct ar_hardc *hc = &ar_hardc[dvp->id_unit]; + + hc->kdc = kdc_arc_template; + + hc->kdc.kdc_unit = unit; + hc->kdc.kdc_parentdata = dvp; + dev_attach(&hc->kdc); +} + + +/* + * Register the Adapter. + * Probe to see if it is there. + * Get its information and fill it in. + */ +int arprobe(struct isa_device *id) +{ + struct ar_hardc *hc = &ar_hardc[id->id_unit]; + u_int tmp; + u_short port; + + /* + * Register the card. + */ + arc_registerdev(id); + + /* + * Now see if the card is realy there. + * + * XXX For now I just check the undocumented ports + * for "570". We will probably have to do more checking. + */ + port = id->id_iobase; + + if((inb(port+AR_ID_5) != '5') || (inb(port+AR_ID_7) != '7') || + (inb(port+AR_ID_0) != '0')) + return 0; + /* + * We have a card here, fill in what we can. + */ + tmp = inb(port + AR_BMI); + hc->bustype = tmp & AR_BUS_MSK; + hc->memsize = (tmp & AR_MEM_MSK) >> AR_MEM_SHFT; + hc->memsize = 1 << hc->memsize; + hc->memsize <<= 16; + hc->interface = (tmp & AR_IFACE_MSK); + hc->revision = inb(port + AR_REV); + hc->numports = inb(port + AR_PNUM); + hc->handshake = inb(port + AR_HNDSH); + + id->id_msize = ARC_WIN_SIZ; + + hc->iobase = id->id_iobase; + hc->mem_start = id->id_maddr; + hc->mem_end = id->id_maddr + id->id_msize; + hc->cunit = id->id_unit; + + switch(hc->interface) { + case AR_IFACE_EIA_232: + printf("ar%d: The EIA 232 interface is not supported.\n", + id->id_unit); + return 0; + case AR_IFACE_V_35: + break; + case AR_IFACE_EIA_530: + printf("ar%d: WARNING: The EIA 530 interface is untested.\n", + id->id_unit); + break; + case AR_IFACE_X_21: + break; + case AR_IFACE_COMBO: + printf("ar%d: WARNING: The COMBO interface is untested.\n", + id->id_unit); + break; + } + + switch(hc->numports) { + case 2: + hc->kdc.kdc_description = "Arnet SYNC/570i 2 Port Adapter"; + break; + case 4: + hc->kdc.kdc_description = "Arnet SYNC/570i 4 Port Adapter"; + break; + } + + if(id->id_unit == 0) + hc->startunit = 0; + else + hc->startunit = ar_hardc[id->id_unit - 1].startunit + + ar_hardc[id->id_unit - 1].numports; + + /* + * Do a little sanity check. + */ + if((hc->numports > NPORT) || (hc->memsize > (512*1024))) + return 0; + + return ARC_IO_SIZ; /* return the amount of IO addresses used. */ +} + + +/* + * Malloc memory for the softc structures. + * Reset the card to put it in a known state. + * Register the ports on the adapter. + * Fill in the info for each port. + * Attach each port to sppp and bpf. + */ +int arattach(struct isa_device *id) +{ + struct ar_hardc *hc = &ar_hardc[id->id_unit]; + struct ar_softc *sc; + struct ifnet *ifp; + int unit; + char *iface; + + switch(hc->interface) { + default: iface = "UNKNOWN"; break; + case AR_IFACE_EIA_232: iface = "EIA-232"; break; + case AR_IFACE_V_35: iface = "EIA-232 or V.35"; break; + case AR_IFACE_EIA_530: iface = "EIA-530"; break; + case AR_IFACE_X_21: iface = "X.21"; break; + case AR_IFACE_COMBO: iface = "COMBO X.21 / EIA-530"; break; + } + + printf("arc%d: %uK RAM, %u ports, rev %u, " + "%s interface.\n", + id->id_unit, + hc->memsize/1024, + hc->numports, + hc->revision, + iface); + + hc->kdc.kdc_state = DC_BUSY; + + arc_init(id); + + sc = hc->sc; + + for(unit=0;unit<hc->numports;unit+=NCHAN) + ar_init_sca(hc, unit / NCHAN); + + /* + * Now configure each port on the card. + */ + for(unit=0;unit<hc->numports;sc++,unit++) { + sc->hc = hc; + sc->subunit = unit; + sc->unit = hc->startunit + unit; + sc->scano = unit / NCHAN; + sc->scachan = unit%NCHAN; + + ar_registerdev(id->id_unit, unit); + + ar_init_rx_dmac(sc); + ar_init_tx_dmac(sc); + ar_init_msci(sc); + + ifp = &sc->ifsppp.pp_if; + + ifp->if_unit = hc->startunit + unit; + ifp->if_name = "ar"; + ifp->if_mtu = PP_MTU; + ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + ifp->if_ioctl = arioctl; + ifp->if_start = arstart; + ifp->if_watchdog = arwatchdog; + ifp->if_init = arinit; + + sc->ifsppp.pp_flags = PP_KEEPALIVE; + + sc->kdc.kdc_state = DC_IDLE; + + printf("ar%d: Adapter %d, port %d.\n", + sc->unit, + hc->cunit, + sc->subunit); + + sppp_attach((struct ifnet *)&sc->ifsppp); + if_attach(ifp); + +#if NBPFILTER > 0 + bpfattach(&sc->bpf, ifp, DLT_PPP, PPP_HEADER_LEN); +#endif + } + + ARC_SET_OFF(hc->iobase); + + return 1; +} + +/* + * First figure out which SCA gave the interrupt. + * Process it. + * See if there is other interrupts pending. + * Repeat until there is no more interrupts. + */ +void arintr(int unit) +{ + struct ar_hardc *hc = &ar_hardc[unit]; + sca_regs *sca = hc->sca; + u_char isr0, isr1, isr2, arisr; + int scano; + static int intno = 0; + + arisr = inb(hc->iobase + AR_ISTAT); + + while(arisr & AR_BD_INT) { + if(arisr & AR_INT_0) + scano = 0; + else if(arisr & AR_INT_1) + scano = 1; + else { + /* XXX Oops this shouldn't happen. */ + printf("arc%d: Interrupted with no interrupt.\n", unit); + return; + } + + ARC_SET_SCA(hc->iobase, scano); + + isr0 = sca->isr0; + isr1 = sca->isr1; + isr2 = sca->isr2; + + /* + * Acknoledge all the interrupts pending. + */ + sca->isr0 = isr0; + sca->isr1 = isr1; + sca->isr2 = isr2; + + TRC(printf("ARINTR %d, isr0 %x, isr1 %x, isr2 %x\n", intno++, + isr0, + isr1, + isr2)); + if(isr0) + ar_msci_intr(hc, scano, isr0); + + if(isr1) + ar_dmac_intr(hc, scano, isr1); + + if(isr2) + ar_timer_intr(hc, scano, isr2); + + /* + * Proccess the second sca's interrupt if available. + * Else see if there are any new interrupts. + */ + if((arisr & AR_INT_0) && (arisr & AR_INT_1)) + arisr &= ~AR_INT_0; + else + arisr = inb(hc->iobase + AR_ISTAT); + } + + ARC_SET_OFF(hc->iobase); +} + + +/* + * This function will be called from the upper level when a user add a + * packet to be send, and from the interrupt handler after a finished + * transmit. + * + * NOTE: it should run at spl_imp(). + * + * Transmitter idle state is indicated by the IFF_OACTIVE flag. The function + * that clears that should ensure that the transmitter and it's DMA is + * in a "good" idle state. + */ +void arstart(struct ifnet *ifp) +{ + struct ar_softc *sc = ARUNIT2SC(ifp->if_unit); + int i, len, tlen; + struct mbuf *mtx; + u_char *txdata; + sca_descriptor *txdesc; + static int intno = 0; + + if(!(ifp->if_flags & IFF_RUNNING)) + return; + + mtx = sppp_dequeue(ifp); + if(!mtx) + return; + + intno++; + + /* + * It is OK to set the memory window outside the loop because + * all tx buffers and descriptors are assumed to be in the same + * 16K window. + */ + ARC_SET_MEM(sc->hc->iobase, sc->txdesc); + + /* + * We stay in this loop until there is nothing in the + * TX queue left or the tx buffer is full. + */ + i = 0; + txdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->txdesc & ARC_WIN_MSK)); + txdata = (u_char *)(sc->hc->mem_start + (sc->txstart & ARC_WIN_MSK)); + for(;;) { + len = mtx->m_pkthdr.len; + + TRC(printf("ar%d: ARstart %d, len %u\n", sc->unit, intno, len)); + + /* + * We can do this because the tx buffers don't wrap. + */ + m_copydata(mtx, 0, len, txdata); + tlen = len; + while(tlen > AR_BUF_SIZ) { + txdesc->stat = 0; + txdesc->len = AR_BUF_SIZ; + tlen -= AR_BUF_SIZ; + txdesc++; + txdata += AR_BUF_SIZ; + i++; + } + /* XXX Move into the loop? */ + txdesc->stat = SCA_DESC_EOM; + txdesc->len = tlen; + txdesc++; + txdata += AR_BUF_SIZ; + i++; + +#if NBPFILTER > 0 + if(sc->bpf) + bpf_mtap(sc->bpf, mtx); +#endif + m_freem(mtx); + ++sc->ifsppp.pp_if.if_opackets; + + /* + * Check if we have space for another mbuf. + * XXX This is hardcoded. A packet won't be larger + * than 3 buffers (3 x 512). + */ + if((i + 3) >= sc->txmax) + break; + + mtx = sppp_dequeue(ifp); + if(!mtx) + break; + } + + sc->txtail = i; + + /* + * Mark the last descriptor, so that the SCA know where + * to stop. + */ + txdesc--; + txdesc->stat |= SCA_DESC_EOT; + +#if 0 + printf("ARstart: %p desc->cp %x\n", &txdesc->cp, txdesc->cp); + printf("ARstart: %p desc->bp %x\n", &txdesc->bp, txdesc->bp); + printf("ARstart: %p desc->bpb %x\n", &txdesc->bpb, txdesc->bpb); + printf("ARstart: %p desc->len %x\n", &txdesc->len, txdesc->len); + printf("ARstart: %p desc->stat %x\n", &txdesc->stat, txdesc->stat); +#endif + + /* + * Start DMA. + * XXX For now we always start from the start. + */ + { + dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)]; + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + dmac->cda = (u_short)(sc->txdesc & 0xffff); + + txdesc = (sca_descriptor *)sc->txdesc; + dmac->eda = (u_short)((u_int)&txdesc[i]); + dmac->dsr = SCA_DSR_DE; + } + + ifp->if_flags |= IFF_OACTIVE; + ifp->if_timer = 2; /* Value in seconds. */ + ARC_SET_OFF(sc->hc->iobase); +} + +int arioctl(struct ifnet *ifp, int cmd, caddr_t data) +{ + int s, error; + int was_up, should_be_up; + struct sppp *sp = (struct sppp *)ifp; + struct ar_softc *sc = ARUNIT2SC(ifp->if_unit); + + TRC(printf("ar%d: arioctl.\n", ifp->if_unit);) + + if(cmd == SIOCSIFFLAGS) { + if(ifp->if_flags & IFF_LINK2) + sp->pp_flags |= PP_CISCO; + else + sp->pp_flags &= ~PP_CISCO; + } + + was_up = ifp->if_flags & IFF_RUNNING; + + error = sppp_ioctl(ifp, cmd, data); + TRC(printf("ar%d: ioctl: ifsppp.pp_flags = %x, if_flags %x.\n", + ifp->if_unit, ((struct sppp *)ifp)->pp_flags, ifp->if_flags);) + if(error) + return error; + + if((cmd != SIOCSIFFLAGS) && cmd != (SIOCSIFADDR)) + return 0; + + TRC(printf("ar%d: arioctl %s.\n", ifp->if_unit, + (cmd == SIOCSIFFLAGS) ? "SIOCSIFFLAGS" : "SIOCSIFADDR");) + + s = splimp(); + should_be_up = ifp->if_flags & IFF_RUNNING; + + if(!was_up && should_be_up) { + /* Interface should be up -- start it. */ + ar_up(sc); + arstart(ifp); + /* XXX Maybe clear the IFF_UP flag so that the link + * will only go up after sppp lcp and ipcp negotiation. + */ + } else if(was_up && !should_be_up) { + /* Interface should be down -- stop it. */ + ar_down(sc); + sppp_flush(ifp); + } + splx(s); + return 0; +} + +/* + * This is to catch lost tx interrupts. + */ +void arwatchdog(int unit) +{ + struct ar_softc *sc = ARUNIT2SC(unit); + + if(!(sc->ifsppp.pp_if.if_flags & IFF_RUNNING)) + return; + + /* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */ + printf("ar%d: transmit failed.\n", unit); + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + sc->hc->sca->msci[sc->scachan].cmd = SCA_CMD_TXABORT; + + ar_down(sc); + ar_up(sc); + + sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; + + arstart(&sc->ifsppp.pp_if); +} + +static void ar_up(struct ar_softc *sc) +{ + sca_regs *sca = sc->hc->sca; + msci_channel *msci = &sca->msci[sc->scachan]; + + TRC(printf("ar%d: sca %p, msci %p, ch %d\n", + sc->unit, sca, msci, sc->scachan)); + sc->kdc.kdc_state = DC_BUSY; + + /* + * Enable transmitter and receiver. + * Raise DTR and RTS. + * Enable interrupts. + */ + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + /* XXX + * What about using AUTO mode in msci->md0 ??? + * And what about CTS/DCD etc... ? + */ + if(sc->hc->handshake & AR_SHSK_RTS) + msci->ctl |= SCA_CTL_RTS; + if(sc->hc->handshake & AR_SHSK_DTR) { + sc->hc->txc_dtr[sc->scano] |= sc->scachan ? + AR_TXC_DTR_DTR1 : AR_TXC_DTR_DTR0; + outb(sc->hc->iobase + sc->hc->txc_dtr_off[sc->scano], + sc->hc->txc_dtr[sc->scano]); + } + + if(sc->scachan == 0) { + sca->ier0 |= 0x0F; + sca->ier1 |= 0x0F; + } else { + sca->ier0 |= 0xF0; + sca->ier1 |= 0xF0; + } + + msci->cmd = SCA_CMD_RXENABLE; + inb(sc->hc->iobase + AR_ID_5); /* XXX slow it down a bit. */ + msci->cmd = SCA_CMD_TXENABLE; + + ARC_SET_OFF(sc->hc->iobase); +} + +static void ar_down(struct ar_softc *sc) +{ + sca_regs *sca = sc->hc->sca; + msci_channel *msci = &sca->msci[sc->scachan]; + + sc->kdc.kdc_state = DC_IDLE; + + /* + * Disable transmitter and receiver. + * Lower DTR and RTS. + * Disable interrupts. + */ + ARC_SET_SCA(sc->hc->iobase, sc->scano); + msci->cmd = SCA_CMD_RXDISABLE; + inb(sc->hc->iobase + AR_ID_5); /* XXX slow it down a bit. */ + msci->cmd = SCA_CMD_TXDISABLE; + + if(sc->hc->handshake & AR_SHSK_RTS) + msci->ctl &= ~SCA_CTL_RTS; + if(sc->hc->handshake & AR_SHSK_DTR) { + sc->hc->txc_dtr[sc->scano] |= sc->scachan ? + AR_TXC_DTR_DTR1 : AR_TXC_DTR_DTR0; + outb(sc->hc->iobase + sc->hc->txc_dtr_off[sc->scano], + sc->hc->txc_dtr[sc->scano]); + } + + if(sc->scachan == 0) { + sca->ier0 &= ~0x0F; + sca->ier1 &= ~0x0F; + } else { + sca->ier0 &= ~0xF0; + sca->ier1 &= ~0xF0; + } + + ARC_SET_OFF(sc->hc->iobase); +} + +/* + * I don't think anything ever calls this function. + */ +void arinit(int unit) + { + int s; + struct ar_softc *sc = ARUNIT2SC(unit); + + printf("ar%d: OOPS, so somebody do call arinit!\n", unit); + + s = splimp(); + ar_down(sc); + ar_up(sc); + splx(s); + } + +/* + * Initialize the card, allocate memory for the ar_softc structures + * and fill in the pointers. + */ +void arc_init(struct isa_device *id) +{ + struct ar_hardc *hc = &ar_hardc[id->id_unit]; + struct ar_softc *sc; + int x; + u_int chanmem; + u_int bufmem; + u_int next; + u_int descneeded; + u_char isr, mar; + + sc = hc->sc = malloc(hc->numports * sizeof(struct ar_softc), + M_DEVBUF, M_WAITOK); + bzero(sc, hc->numports * sizeof(struct ar_softc)); + + /* + * reset the card and wait at least 1uS. + */ + outb(hc->iobase + AR_TXC_DTR0, AR_TXC_DTR_RESET); + DELAY(2); + outb(hc->iobase + AR_TXC_DTR0, AR_TXC_DTR_NOTRESET); + + hc->txc_dtr[0] = AR_TXC_DTR_NOTRESET; + hc->txc_dtr[1] = 0; + hc->txc_dtr_off[0] = AR_TXC_DTR0; + hc->txc_dtr_off[1] = AR_TXC_DTR2; + + /* + * Configure the card. + * Mem address, irq, + */ + mar = kvtop(id->id_maddr) >> 16; + isr = irqtable[ffs(id->id_irq) - 1] << 1; + if(isr == 0) + printf("ar%d: Warning illegal interrupt %d\n", + id->id_unit, ffs(id->id_irq) - 1); + isr = isr | ((kvtop(id->id_maddr) & 0xc000) >> 10); + + hc->sca = (sca_regs *)hc->mem_start; + + outb(hc->iobase + AR_MEM_SEL, mar); + outb(hc->iobase + AR_INT_SEL, isr | AR_INTS_CEN); + + /* + * Make TX clock output and enable TX. + */ + hc->txc_dtr[0] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1 | + AR_TXC_DTR_TXCS0 | AR_TXC_DTR_TXCS1; + outb(hc->iobase + AR_TXC_DTR0, hc->txc_dtr[0]); + if(hc->numports > NCHAN) { + hc->txc_dtr[1] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1 | + AR_TXC_DTR_TXCS0 | AR_TXC_DTR_TXCS1; + outb(hc->iobase + AR_TXC_DTR2, hc->txc_dtr[1]); + } + + chanmem = hc->memsize / hc->numports; + next = 0; + + for(x=0;x<hc->numports;x++, sc++) { + sc->txdesc = next; + bufmem = 16 * 1024; + descneeded = bufmem / AR_BUF_SIZ; + sc->txstart = sc->txdesc + + ((((descneeded * sizeof(sca_descriptor)) / + AR_BUF_SIZ) + 1) * AR_BUF_SIZ); + sc->txend = next + bufmem; + sc->txmax = (sc->txend - sc->txstart) / AR_BUF_SIZ; + next += bufmem; + + TRC(printf("ar%d: txdesc %x, txstart %x, txend %x, txmax %d\n", + x, + sc->txdesc, sc->txstart, sc->txend, sc->txmax)); + + sc->rxdesc = next; + bufmem = chanmem - bufmem; + descneeded = bufmem / AR_BUF_SIZ; + sc->rxstart = sc->rxdesc + + ((((descneeded * sizeof(sca_descriptor)) / + AR_BUF_SIZ) + 1) * AR_BUF_SIZ); + sc->rxend = next + bufmem; + sc->rxmax = (sc->rxend - sc->rxstart) / AR_BUF_SIZ; + next += bufmem; + + /* + * This is by ARUNIT2SC(). + */ + ar_sc_ind[x] = sc; + } +} + + +/* + * The things done here are channel independent. + * + * Configure the sca waitstates. + * Configure the global interrupt registers. + * Enable master dma enable. + */ +static void ar_init_sca(struct ar_hardc *hc, int scano) +{ + sca_regs *sca = hc->sca; + + ARC_SET_SCA(hc->iobase, scano); + + /* + * Do the wait registers. + * Set everything to 0 wait states. + */ + sca->pabr0 = 0; + sca->pabr1 = 0; + sca->wcrl = 0; + sca->wcrm = 0; + sca->wcrh = 0; + + /* + * Configure the interrupt registers. + * Most are cleared until the interface is configured. + */ + sca->ier0 = 0x00; /* MSCI interrupts... Not used with dma. */ + sca->ier1 = 0x00; /* DMAC interrupts */ + sca->ier2 = 0x00; /* TIMER interrupts... Not used yet. */ + sca->itcr = 0x00; /* Use ivr and no intr ack */ + sca->ivr = 0x40; /* Fill in the interrupt vector. */ + sca->imvr = 0x40; + + /* + * Configure the timers. + * XXX Later + */ + + + sca->dmer = SCA_DMER_EN; /* Enable all dma channels. */ +} + + +/* + * Configure the msci + * + * NOTE: The serial port configuration is hardcoded at the moment. + */ +void ar_init_msci(struct ar_softc *sc) +{ + msci_channel *msci = &sc->hc->sca->msci[sc->scachan]; + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + msci->cmd = SCA_CMD_RESET; + + msci->md0 = SCA_MD0_CRC_1 | + SCA_MD0_CRC_CCITT | + SCA_MD0_CRC_ENABLE | + SCA_MD0_MODE_HDLC; + msci->md1 = SCA_MD1_NOADDRCHK; + msci->md2 = SCA_MD2_DUPLEX | SCA_MD2_NRZ; + + /* + * Acording to the manual I should give a reset after changing the + * mode registers. + */ + msci->cmd = SCA_CMD_RXRESET; + msci->ctl = SCA_CTL_IDLPAT | SCA_CTL_UDRNC; + + /* + * For now all interfaces are programmed to use the RX clock for + * the TX clock. + */ + switch(sc->hc->interface) { + case AR_IFACE_V_35: + case AR_IFACE_X_21: + case AR_IFACE_EIA_530: + case AR_IFACE_COMBO: + msci->rxs = SCA_RXS_CLK_RXC0 | SCA_RXS_DIV1; + msci->txs = SCA_TXS_CLK_RX | SCA_TXS_DIV1; + } + + msci->tmc = 153; /* This give 64k for loopback */ + + /* XXX + * Disable all interrupts for now. I think if you are using + * the dmac you don't use these interrupts. + */ + msci->ie0 = 0; + msci->ie1 = 0x0C; /* XXX CTS and DCD (DSR on 570I) level change. */ + msci->ie2 = 0; + msci->fie = 0; + + msci->sa0 = 0; + msci->sa1 = 0; + + msci->idl = 0x7E; /* XXX This is what cisco does. */ + + /* + * This is what the ARNET diags use. + */ + msci->rrc = 0x0E; + msci->trc0 = 0x12; + msci->trc1 = 0x1F; +} + +/* + * Configure the rx dma controller. + */ +void ar_init_rx_dmac(struct ar_softc *sc) +{ + dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)]; + sca_descriptor *rxd; + u_int rxbuf; + u_int rxda; + u_int rxda_d; + + ARC_SET_MEM(sc->hc->iobase, sc->rxdesc); + + rxd = (sca_descriptor *)(sc->hc->mem_start + (sc->rxdesc&ARC_WIN_MSK)); + rxda_d = (u_int)sc->hc->mem_start - (sc->rxdesc & ~ARC_WIN_MSK); + + for(rxbuf=sc->rxstart;rxbuf<sc->rxend;rxbuf += AR_BUF_SIZ, rxd++) { + rxda = (u_int)&rxd[1] - rxda_d; + rxd->cp = (u_short)(rxda & 0xfffful); + + TRC(printf("Descrp %p, data pt %p, data long %lx, ", + &sc->rxdesc[x], rxinuse->buf, rxbuf)); + + rxd->bp = (u_short)(rxbuf & 0xfffful); + rxd->bpb = (u_char)((rxbuf >> 16) & 0xff); + rxd->len = 0; + rxd->stat = 0xff; /* The sca write here when it is finished. */ + + TRC(printf("bpb %x, bp %x.\n", rxd->bpb, rxd->bp)); + } + rxd--; + rxd->cp = (u_short)(sc->rxdesc & 0xfffful); + + sc->rxhind = 0; + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + dmac->dsr = 0; /* Disable DMA transfer */ + dmac->dcr = SCA_DCR_ABRT; + + /* XXX maybe also SCA_DMR_CNTE */ + dmac->dmr = SCA_DMR_TMOD | SCA_DMR_NF; + dmac->bfl = AR_BUF_SIZ; + + dmac->cda = (u_short)(sc->rxdesc & 0xffff); + dmac->sarb = (u_char)((sc->rxdesc >> 16) & 0xff); + + rxd = (sca_descriptor *)sc->rxstart; + dmac->eda = (u_short)((u_int)&rxd[sc->rxmax - 1] & 0xffff); + + dmac->dir = 0xF0; + + dmac->dsr = SCA_DSR_DE; +} + +/* + * Configure the TX DMA descriptors. + * Initialize the needed values and chain the descriptors. + */ +void ar_init_tx_dmac(struct ar_softc *sc) +{ + dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)]; + sca_descriptor *txd; + u_int txbuf; + u_int txda; + u_int txda_d; + + ARC_SET_MEM(sc->hc->iobase, sc->txdesc); + + txd = (sca_descriptor *)(sc->hc->mem_start + (sc->txdesc&ARC_WIN_MSK)); + txda_d = (u_int)sc->hc->mem_start - (sc->txdesc & ~ARC_WIN_MSK); + + for(txbuf=sc->txstart;txbuf<sc->txend;txbuf += AR_BUF_SIZ, txd++) { + txda = (u_int)&txd[1] - txda_d; + txd->cp = (u_short)(txda & 0xfffful); + + txd->bp = (u_short)(txbuf & 0xfffful); + txd->bpb = (u_char)((txbuf >> 16) & 0xff); + TRC(printf("ar%d: txbuf %x, bpb %x, bp %x\n", + sc->unit, txbuf, txd->bpb, txd->bp)); + txd->len = 0; + txd->stat = 0; + } + txd--; + txd->cp = (u_short)(sc->txdesc & 0xfffful); + + sc->txtail = (u_int)txd - (u_int)sc->hc->mem_start; + TRC(printf("TX Descriptors start %x, end %x.\n", + sc->txhead, + sc->txtail)); + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + dmac->dsr = 0; /* Disable DMA */ + dmac->dcr = SCA_DCR_ABRT; + dmac->dmr = SCA_DMR_TMOD | SCA_DMR_NF; + dmac->dir = SCA_DIR_EOT | SCA_DIR_BOF | SCA_DIR_COF; + + dmac->sarb = (u_char)((sc->txdesc >> 16) & 0xff); +} + + +/* + * Look through the descriptors to see if there is a complete packet + * available. Stop if we get to where the sca is busy. + * + * Return the length and status of the packet. + * Return nonzero if there is a packet available. + */ +int ar_packet_avail(struct ar_softc *sc, + int *len, + u_char *rxstat) +{ + sca_descriptor *rxdesc; + sca_descriptor *endp; + + ARC_SET_MEM(sc->hc->iobase, sc->rxdesc); + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + endp = rxdesc; + rxdesc = &rxdesc[sc->rxhind]; + endp = &endp[sc->rxmax]; + + *len = 0; + + while(rxdesc->stat != 0xff) { + *len += rxdesc->len; + + if(rxdesc->stat & SCA_DESC_EOM) { + *rxstat = rxdesc->stat; + TRC(printf("ar%d: PKT AVAIL len %d, %x, bufs %u.\n", + sc->unit, *len, *rxstat, x)); + return 1; + } + rxdesc++; + if(rxdesc == endp) + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + } + + *len = 0; + *rxstat = 0; + return 0; +} + + +/* + * Copy a packet from the on card memory into a provided mbuf. + * Take into account that buffers wrap and that a packet may + * be larger than a buffer. + */ +void ar_copy_rxbuf(struct mbuf *m, + struct ar_softc *sc, + int len) +{ + sca_descriptor *rxdesc; + u_int rxdata; + u_int rxmax; + u_int off = 0; + u_int tlen; + + rxdata = sc->rxstart + (sc->rxhind * AR_BUF_SIZ); + rxmax = sc->rxstart + (sc->rxmax * AR_BUF_SIZ); + + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + rxdesc = &rxdesc[sc->rxhind]; + + while(len) { + tlen = (len < AR_BUF_SIZ) ? len : AR_BUF_SIZ; + ARC_SET_MEM(sc->hc->iobase, rxdata); + bcopy(sc->hc->mem_start + (rxdata & ARC_WIN_MSK), + mtod(m, caddr_t) + off, + tlen); + + off += tlen; + len -= tlen; + + ARC_SET_MEM(sc->hc->iobase, sc->rxdesc); + rxdesc->len = 0; + rxdesc->stat = 0xff; + + rxdata += AR_BUF_SIZ; + rxdesc++; + if(rxdata == rxmax) { + rxdata = sc->rxstart; + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + } + } +} + +/* + * Just eat a packet. Update pointers to point to the next packet. + */ +void ar_eat_packet(struct ar_softc *sc) +{ + sca_descriptor *rxdesc; + sca_descriptor *endp; + + /* + * Loop until desc->stat == (0xff || EOM) + * Clear the status and length in the descriptor. + * Increment the descriptor. + */ + ARC_SET_MEM(sc->hc->iobase, sc->rxdesc); + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + endp = rxdesc; + rxdesc = &rxdesc[sc->rxhind]; + endp = &endp[sc->rxmax]; + + while(rxdesc->stat != 0xff) { + if((rxdesc->stat & ~SCA_DESC_EOM) == 0) + break; + + rxdesc->len = 0; + rxdesc->stat = 0xff; + + rxdesc++; + sc->rxhind++; + if(rxdesc == endp) { + rxdesc = (sca_descriptor *) + (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK)); + sc->rxhind = 0; + } + } +} + + +/* + * While there is packets available in the rx buffer, read them out + * into mbufs and ship them off. + */ +void ar_get_packets(struct ar_softc *sc) +{ + sca_descriptor *rxdesc; + struct mbuf *m = NULL; + int i; + int len; + u_char rxstat; + + while(ar_packet_avail(sc, &len, &rxstat)) { + if((rxstat & SCA_DESC_ERRORS) == 0) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if(m != NULL) { + MCLGET(m, M_DONTWAIT); + if((m->m_flags & M_EXT) != 0) { + m->m_pkthdr.rcvif = &sc->ifsppp.pp_if; + m->m_pkthdr.len = m->m_len = len; + ar_copy_rxbuf(m, sc, len); +#if NBPFILTER > 0 + if(sc->bpf) + bpf_mtap(sc->bpf, m); +#endif + sppp_input(&sc->ifsppp.pp_if, m); + sc->ifsppp.pp_if.if_ipackets++; + } else { + m_freem(m); + /* eat packet if get mbuf fail!! */ + ar_eat_packet(sc); + } + } else { + /* eat packet if get mbuf fail!! */ + ar_eat_packet(sc); + } + } else { + msci_channel *msci = &sc->hc->sca->msci[sc->scachan]; + + ar_eat_packet(sc); + + sc->ifsppp.pp_if.if_ierrors++; + + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + TRCL(printf("RX%d So this does happen :), stat %x, " + "ST2 %x, cda %x.\n", + sc->scachan, + rxstat, + msci->st2, + sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].cda)); + + /* + * Reset the rx unit. + * + * XXX Maybe it should only be done when certain + * errors occured. ie not for CRC errors? + */ + msci->cmd = SCA_CMD_RXRESET; + msci->cmd = SCA_CMD_RXENABLE; + + TRCL(printf("RX%d After reset: ST2 %x.\n", + sc->scachan, msci->st2)); + } /* else */ + + i = (len + AR_BUF_SIZ - 1) / AR_BUF_SIZ; + sc->rxhind = (sc->rxhind + i) % sc->rxmax; + + /* + * Update the eda to the previous descriptor. + */ + ARC_SET_SCA(sc->hc->iobase, sc->scano); + + rxdesc = (sca_descriptor *)sc->rxdesc; + rxdesc = &rxdesc[(sc->rxhind + sc->rxmax -1 ) % sc->rxmax]; + + sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].eda = + (u_short)((u_int)&rxdesc & 0xffff); + + } /* while */ +} + + +/* + * All DMA interrupts come here. + * + * Each channel has two interrupts. + * Interrupt A for errors and Interrupt B for normal stuff like end + * of transmit or receive dmas. + */ +static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1) +{ + u_char dsr; + int mch; + struct ar_softc *sc; + sca_regs *sca = hc->sca; + dmac_channel *dmac; + + mch = 0; + /* + * Shortcut if there is no interrupts for dma channel 0 or 1 + */ + if((isr1 & 0x0F) == 0) { + mch = 1; + isr1 >>= 4; + } + + do { + sc = &hc->sc[mch + (NCHAN * scano)]; + dmac = &sca->dmac[DMAC_RXCH(mch)]; + + /* + * Receive channel + */ + if(isr1 & 0x03) { + ARC_SET_SCA(hc->iobase, scano); + + dsr = dmac->dsr; + dmac->dsr = dsr; + + TRC(printf("AR: RX DSR %x\n", dsr)); + + /* End of frame */ + if(dsr & SCA_DSR_EOM) { + ar_get_packets(sc); + } + + /* Counter overflow */ + if(dsr & SCA_DSR_COF) { + printf("ar%d: RX DMA Counter overflow, " + "rxpkts %lu.\n", + sc->unit, + sc->ifsppp.pp_if.if_ipackets); + sc->ifsppp.pp_if.if_ierrors++; + } + + /* Buffer overflow */ + if(dsr & SCA_DSR_BOF) { + printf("ar%d: RX DMA Buffer overflow, " + "rxpkts %lu.\n", + sc->unit, + sc->ifsppp.pp_if.if_ipackets); + sc->ifsppp.pp_if.if_ierrors++; + dmac->dsr = SCA_DSR_DE; + } + + /* End of Transfer */ + if(dsr & SCA_DSR_EOT) { + /* + * If this happen, it means that we are + * receiving faster than what the processor + * can handle. + * + * XXX We should enable the dma again. + */ + printf("ar%d: RX End of transfer, rxpkts %lu.\n", + sc->unit, + sc->ifsppp.pp_if.if_ipackets); + sc->ifsppp.pp_if.if_ierrors++; + } + } + + /* + * We are finished with the 2 DMA status bits for RX now do TX. + */ + isr1 >>= 2; + + /* + * Transmit channel + */ + if(isr1 & 0x03) { + dmac = &sca->dmac[DMAC_TXCH(mch)]; + + ARC_SET_SCA(hc->iobase, scano); + + dsr = dmac->dsr; + dmac->dsr = dsr; + + /* Counter overflow */ + if(dsr & SCA_DSR_COF) { + printf("ar%d: TX DMA Counter overflow, " + "txpacket no %lu.\n", + sc->unit, + sc->ifsppp.pp_if.if_opackets); + sc->ifsppp.pp_if.if_oerrors++; + } + + /* Buffer overflow */ + if(dsr & SCA_DSR_BOF) { + printf("ar%d: TX DMA Buffer overflow, " + "txpacket no %lu, dsr %02x, " + "cda %04x, eda %04x.\n", + sc->unit, + sc->ifsppp.pp_if.if_opackets, + dsr, + dmac->cda, + dmac->eda); + sc->ifsppp.pp_if.if_oerrors++; + } + + /* End of Transfer */ + if(dsr & SCA_DSR_EOT) { + /* + * This should be the most common case. + * + * Clear the IFF_OACTIVE flag. + * + * Call arstart to start a new transmit if + * there is data to transmit. + */ + sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; + sc->ifsppp.pp_if.if_timer = 0; + + arstart(&sc->ifsppp.pp_if); + } + } + isr1 >>= 2; + + mch++; + }while((mch<NCHAN) && isr1); +} + +static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr0) +{ + printf("arc%d: ARINTR: MSCI\n", hc->cunit); +} + +static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2) +{ + printf("arc%d: ARINTR: TIMER\n", hc->cunit); +} + +/* + ********************************* END ************************************ + */ + diff --git a/sys/i386/isa/if_arregs.h b/sys/i386/isa/if_arregs.h new file mode 100644 index 0000000..c4f1733 --- /dev/null +++ b/sys/i386/isa/if_arregs.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1995 John Hay. All rights reserved. + * + * 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 + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by [your name] + * and [any other names deserving credit ] + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY [your name] 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 THE REGENTS OR 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. + * + * $Id: if_arregs.h,v 1.6 1995/11/14 19:50:57 jhay Exp $ + */ +#ifndef _IF_ARREGS_H_ +#define _IF_ARREGS_H_ + +#define NCHAN 2 /* A HD64570 chip have 2 channels */ +#define NPORT 4 /* A ArNet board can have 4 ports or */ + /* channels */ + +#define AR_BUF_SIZ 512 +#define ARC_IO_SIZ 0x10 +#define ARC_WIN_SIZ 0x00004000 +#define ARC_WIN_MSK (ARC_WIN_SIZ - 1) +#define ARC_WIN_SHFT 14 + +#define AR_ID_5 0x00 /* RO, Card probe '5' */ +#define AR_ID_7 0x01 /* RO, Card probe '7' */ +#define AR_ID_0 0x02 /* RO, Card probe '0' */ +#define AR_BMI 0x03 /* RO, Bus, mem and interface type */ +#define AR_REV 0x04 /* RO, Adapter revision */ +#define AR_PNUM 0x05 /* RO, Port number */ +#define AR_HNDSH 0x06 /* RO, Supported handshake */ +#define AR_ISTAT 0x07 /* RO, DCD and Interrupt status */ +#define AR_MSCA_EN 0x08 /* WO, Memory and SCA enable */ +#define AR_TXC_DTR0 0x09 /* WO, Tx Clock and DTR control 0 + 1 */ +#define AR_SEC_PAL 0x0A /* RW, Security PAL */ +#define AR_INT_ACK0 0x0B /* RO, Interrupt Acknowledge 0 + 1 */ +#define AR_INT_SEL 0x0C /* RW, Interrupt Select */ +#define AR_MEM_SEL 0x0D /* RW, Memory Select */ +#define AR_INT_ACK2 0x0E /* RO, Interrupt Acknowledge 2 + 3 */ +#define AR_TXC_DTR2 0x0E /* WO, Tx Clock and DTR control 2 + 3 */ + +/* Bus memory and interface type */ +#define AR_BUS_MSK 0x03 +#define AR_BUS_ISA 0x00 +#define AR_BUS_MCA 0x01 +#define AR_BUS_EISA 0x02 + +#define AR_MEM_MSK 0x1C +#define AR_MEM_SHFT 0x02 +#define AR_MEM_64K 0x00 +#define AR_MEM_128K 0x04 +#define AR_MEM_256K 0x08 +#define AR_MEM_512K 0x0C + +/* + * EIA-232 + * V.35/EIA-232 + * EIA-530 + * X.21 + * EIA-530/X.21 Combo + */ +#define AR_IFACE_MSK 0xE0 +#define AR_IFACE_SHFT 0x05 +#define AR_IFACE_EIA_232 0x00 /* Only on the 570 card, not 570i */ +#define AR_IFACE_V_35 0x20 /* Selectable between V.35 and EIA-232 */ +#define AR_IFACE_EIA_530 0x40 +#define AR_IFACE_X_21 0x60 +#define AR_IFACE_COMBO 0xC0 /* X.21 / EIA-530 */ + +/* Supported Handshake signals */ +#define AR_SHSK_DTR 0x01 +#define AR_SHSK_RTS 0x02 +#define AR_SHSK_CTS 0x10 +#define AR_SHSK_DSR 0x20 +#define AR_SHSK_RI 0x40 +#define AR_SHSK_DCD 0x80 + +/* DCD and Interrupt status */ +#define AR_BD_INT 0x01 +#define AR_INT_0 0x20 +#define AR_INT_1 0x40 + +#define AR_DCD_MSK 0x1E +#define AR_DCD_SHFT 0x01 +#define AR_DCD_0 0x02 +#define AR_DCD_1 0x04 +#define AR_DCD_2 0x08 +#define AR_DCD_3 0x10 + +/* Memory and SCA enable */ +#define AR_WIN_MSK 0x1F + +#define AR_SEL_SCA_0 0x00 +#define AR_SEL_SCA_1 0x20 +#define AR_ENA_SCA 0x40 +#define AR_ENA_MEM 0x80 + +/* Transmit Clock and DTR and RESET */ +#define AR_TXC_DTR_TX0 0x01 +#define AR_TXC_DTR_TX1 0x02 +#define AR_TXC_DTR_DTR0 0x04 +#define AR_TXC_DTR_DTR1 0x08 +#define AR_TXC_DTR_TXCS0 0x10 +#define AR_TXC_DTR_TXCS1 0x20 +#define AR_TXC_DTR_NOTRESET 0x40 +#define AR_TXC_DTR_RESET 0x00 + +/* Interrupt select register */ +#define AR_INTS_CEN 0x01 +#define AR_INTS_ISEL0 0x02 +#define AR_INTS_ISEL1 0x04 +#define AR_INTS_ISEL2 0x08 +#define AR_INTS_CMA14 0x10 +#define AR_INTS_CMA15 0x20 + +/* Memory select register */ + + +#endif /* _IF_ARREGS_H_ */ |