summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2005-08-13 22:49:49 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2005-08-13 22:49:49 +0000
commit629ca807ea9692b75199c888af8d722c434eb738 (patch)
tree7780b366add71aac45b3284c938030b461aeb2aa /sys/dev/pci
parent4b6938935c0f118d9f178d89c3fa610b6cff1f1f (diff)
Driver for the Accoom Networks Artery T1/E1 PCI cards.
deraadt@ "yeah, put it in."
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/bt8370.c948
-rw-r--r--sys/dev/pci/bt8370reg.h393
-rw-r--r--sys/dev/pci/if_art.c363
-rw-r--r--sys/dev/pci/if_art.h83
-rw-r--r--sys/dev/pci/musycc.c1941
-rw-r--r--sys/dev/pci/musycc_obsd.c299
-rw-r--r--sys/dev/pci/musyccreg.h256
-rw-r--r--sys/dev/pci/musyccvar.h234
8 files changed, 4517 insertions, 0 deletions
diff --git a/sys/dev/pci/bt8370.c b/sys/dev/pci/bt8370.c
new file mode 100644
index 00000000000..2459f92d5dc
--- /dev/null
+++ b/sys/dev/pci/bt8370.c
@@ -0,0 +1,948 @@
+/* $OpenBSD: bt8370.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: bt8370.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Andre Oppermann <oppermann@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_sppp.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include "musyccvar.h"
+#include "if_art.h"
+#include "bt8370reg.h"
+
+void bt8370_set_sbi_clock_mode(struct art_softc *, enum art_sbi_type,
+ u_int, int);
+void bt8370_set_bus_mode(struct art_softc *, enum art_sbi_mode, int);
+void bt8370_set_line_buildout(struct art_softc *, int);
+void bt8370_set_loopback_mode(struct art_softc *, enum art_loopback);
+void bt8370_set_bop_mode(struct art_softc *ac, int);
+void bt8370_set_dl_1_mode(struct art_softc *, int);
+void bt8370_set_dl_2_mode(struct art_softc *, int);
+void bt8370_intr_enable(struct art_softc *ac, int);
+
+#ifndef ACCOOM_DEBUG
+#define bt8370_print_status(x)
+#define bt8370_dump_registers(x)
+#else
+void bt8370_print_status(struct art_softc *);
+void bt8370_dump_registers(struct art_softc *);
+#endif
+
+int
+bt8370_reset(struct art_softc *ac)
+{
+ u_int8_t cr0;
+
+ ebus_write(&ac->art_ebus, Bt8370_CR0, 0x00);
+ DELAY(10); /* 10 microseconds */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_RESET);
+ DELAY(20); /* 20 microseconds */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, 0x00);
+ cr0 = ebus_read(&ac->art_ebus, Bt8370_CR0);
+ if (cr0 != 0x0) {
+ log(LOG_ERR, "%s: reset not successful\n",
+ ac->art_dev.dv_xname);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+bt8370_set_frame_mode(struct art_softc *ac, u_int mode, u_int clockmode)
+{
+ int channels;
+
+ /* Get into a clean state */
+ bt8370_reset(ac);
+
+ /* Disable all interrupts to be sure */
+ bt8370_intr_enable(ac, 0);
+
+ switch (mode) {
+ case IFM_TDM_E1: /* 32 payload channels, bit transparent */
+ channels = 32;
+
+ /* Global Config */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_E1_FAS);
+
+ /* Primary Config */
+ bt8370_set_loopback_mode(ac, ART_NOLOOP);
+ ebus_write(&ac->art_ebus, Bt8370_DL3_TS, 0x00);
+
+ /* Timing and Clock Config */
+ bt8370_set_sbi_clock_mode(ac, ART_SBI_SINGLE_E1, clockmode,
+ channels);
+
+ /* Receiver RLIU, RCVR */
+ ebus_write(&ac->art_ebus, Bt8370_RCR0, RCR0_HDB3 |
+ RCR0_RABORT | RCR0_LFA_FAS | RCR0_RZCS_NBPV);
+ ebus_write(&ac->art_ebus, Bt8370_RALM, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_LATCH, LATCH_STOPCNT);
+
+ /* Transmitter TLIU, XMTR */
+ ebus_write(&ac->art_ebus, Bt8370_TCR0, TCR0_FAS);
+ ebus_write(&ac->art_ebus, Bt8370_TCR1, TCR1_TABORT |
+ TCR1_HDB3);
+ ebus_write(&ac->art_ebus, Bt8370_TFRM, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TMAN, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TALM, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TPATT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TLB, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSA4, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA5, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA6, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA7, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA8, 0xFF);
+
+ /* Bit Oriented Protocol Transceiver BOP disabled */
+ bt8370_set_bop_mode(ac, 0);
+
+ /* Data Link #1 disabled */
+ bt8370_set_dl_1_mode(ac, 0);
+
+ /* Data Link #2 disabled */
+ bt8370_set_dl_2_mode(ac, 0);
+
+ ACCOOM_PRINTF(1, ("%s: set to E1 G.703 unframed, HDB3\n",
+ ac->art_dev.dv_xname));
+ break;
+ case IFM_TDM_E1_G704: /* 31 payload channels, byte aligned */
+ channels = 32;
+
+ /* Global Config */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_E1_FAS);
+
+ /* Primary Config */
+ bt8370_set_loopback_mode(ac, ART_NOLOOP);
+ ebus_write(&ac->art_ebus, Bt8370_DL3_TS, 0x00);
+
+ /* Timing and Clock Config */
+ bt8370_set_sbi_clock_mode(ac, ART_SBI_SINGLE_E1, clockmode,
+ channels);
+
+ /* Receiver RLIU, RCVR */
+ bt8370_set_line_buildout(ac, 0);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_RCR0, RCR0_RFORCE |
+ RCR0_HDB3 | RCR0_LFA_FAS | RCR0_RZCS_NBPV);
+ ebus_write(&ac->art_ebus, Bt8370_RALM, RALM_FSNFAS);
+ ebus_write(&ac->art_ebus, Bt8370_LATCH, LATCH_STOPCNT);
+
+ /* Transmitter TLIU, XMTR */
+ ebus_write(&ac->art_ebus, Bt8370_TCR0, TCR0_FAS);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_TCR1, TCR1_TABORT |
+ TCR1_3FAS | TCR1_HDB3);
+ ebus_write(&ac->art_ebus, Bt8370_TFRM, TFRM_YEL |
+ TFRM_FBIT);
+ ebus_write(&ac->art_ebus, Bt8370_TMAN, TMAN_MALL);
+ ebus_write(&ac->art_ebus, Bt8370_TALM, TALM_AYEL);
+ ebus_write(&ac->art_ebus, Bt8370_TPATT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TLB, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSA4, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA5, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA6, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA7, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA8, 0xFF);
+
+ /* Bit Oriented Protocol Transceiver BOP disabled */
+ bt8370_set_bop_mode(ac, 0);
+
+ /* Data Link #1 disabled */
+ bt8370_set_dl_1_mode(ac, 0);
+
+ /* Data Link #2 disabled */
+ bt8370_set_dl_2_mode(ac, 0);
+
+ ACCOOM_PRINTF(1, ("%s: set to E1 G.704, HDB3\n",
+ ac->art_dev.dv_xname));
+ break;
+ case IFM_TDM_E1_G704_CRC4: /* 31 payload channels, byte aligned */
+ channels = 32;
+
+ /*
+ * Over normal G.704 the following registers need changes:
+ * CR0 = +CRC
+ * TFRM = +INS_CRC
+ */
+
+ /* Global Config */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_E1_FAS_CRC);
+
+ /* Primary Config */
+ bt8370_set_loopback_mode(ac, ART_NOLOOP);
+ ebus_write(&ac->art_ebus, Bt8370_DL3_TS, 0x00);
+
+ /* Timing and Clock Config */
+ bt8370_set_sbi_clock_mode(ac, ART_SBI_SINGLE_E1, clockmode,
+ channels);
+
+ /* Receiver RLIU, RCVR */
+ bt8370_set_line_buildout(ac, 0);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_RCR0, RCR0_RFORCE |
+ RCR0_HDB3 | RCR0_LFA_FASCRC | RCR0_RZCS_NBPV);
+ ebus_write(&ac->art_ebus, Bt8370_RALM, RALM_FSNFAS);
+ ebus_write(&ac->art_ebus, Bt8370_LATCH, LATCH_STOPCNT);
+
+ /* Transmitter TLIU, XMTR */
+ ebus_write(&ac->art_ebus, Bt8370_TCR0, TCR0_MFAS);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_TCR1, TCR1_TABORT |
+ TCR1_3FAS | TCR1_HDB3);
+ ebus_write(&ac->art_ebus, Bt8370_TFRM, TFRM_YEL |
+ TFRM_MF | TFRM_FE | TFRM_CRC | TFRM_FBIT);
+ ebus_write(&ac->art_ebus, Bt8370_TMAN, TMAN_MALL);
+ ebus_write(&ac->art_ebus, Bt8370_TALM, TALM_AYEL | TALM_AAIS);
+ ebus_write(&ac->art_ebus, Bt8370_TPATT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TLB, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSA4, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA5, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA6, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA7, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA8, 0xFF);
+
+ /* Bit Oriented Protocol Transceiver BOP disabled */
+ bt8370_set_bop_mode(ac, 0);
+
+ /* Data Link #1 disabled */
+ bt8370_set_dl_1_mode(ac, 0);
+
+ /* Data Link #2 disabled */
+ bt8370_set_dl_2_mode(ac, 0);
+
+ ACCOOM_PRINTF(1, ("%s: set to E1 G.704 CRC4, HDB3\n",
+ ac->art_dev.dv_xname));
+ break;
+ case IFM_TDM_T1_AMI: /* 24 payload channels, byte aligned */
+ channels = 25; /* zero is ignored for T1 */
+
+ /* Global Config */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_T1_SF);
+
+ /* Primary Config */
+ bt8370_set_loopback_mode(ac, ART_NOLOOP);
+ ebus_write(&ac->art_ebus, Bt8370_DL3_TS, 0x00);
+
+ /* Timing and Clock Config */
+ bt8370_set_sbi_clock_mode(ac, ART_SBI_SINGLE_T1, clockmode,
+ channels);
+
+ /* Receiver RLIU, RCVR */
+ bt8370_set_line_buildout(ac, 0);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_RCR0, RCR0_RFORCE |
+ RCR0_AMI | RCR0_LFA_26F | RCR0_RZCS_NBPV);
+ ebus_write(&ac->art_ebus, Bt8370_RALM, RALM_FSNFAS);
+ ebus_write(&ac->art_ebus, Bt8370_LATCH, LATCH_STOPCNT);
+
+ /* Transmitter TLIU, XMTR */
+ ebus_write(&ac->art_ebus, Bt8370_TCR0, TCR0_SF);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_TCR1, TCR1_TABORT |
+ TCR1_26F | TCR1_AMI);
+ ebus_write(&ac->art_ebus, Bt8370_TFRM, TFRM_YEL |
+ TFRM_MF | TFRM_FBIT);
+ ebus_write(&ac->art_ebus, Bt8370_TMAN, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TALM, TALM_AYEL);
+ ebus_write(&ac->art_ebus, Bt8370_TPATT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TLB, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSA4, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA5, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA6, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA7, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA8, 0xFF);
+
+ /* Bit Oriented Protocol Transceiver BOP disabled */
+ bt8370_set_bop_mode(ac, 0);
+
+ /* Data Link #1 disabled */
+ bt8370_set_dl_1_mode(ac, 0);
+
+ /* Data Link #2 disabled */
+ bt8370_set_dl_2_mode(ac, 0);
+
+ ACCOOM_PRINTF(1, ("%s: set to T1 SF, AMI\n",
+ ac->art_dev.dv_xname));
+ break;
+ case IFM_TDM_T1: /* 24 payload channels, byte aligned */
+ channels = 25; /* zero is ignored for T1 */
+
+ /* Global Config */
+ ebus_write(&ac->art_ebus, Bt8370_CR0, CR0_T1_ESF);
+
+ /* Primary Config */
+ bt8370_set_loopback_mode(ac, ART_NOLOOP);
+ ebus_write(&ac->art_ebus, Bt8370_DL3_TS, 0x00);
+
+ /* Timing and Clock Config */
+ bt8370_set_sbi_clock_mode(ac, ART_SBI_SINGLE_T1, clockmode,
+ channels);
+
+ /* Receiver RLIU, RCVR */
+ bt8370_set_line_buildout(ac, 0);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_RCR0, RCR0_RFORCE |
+ RCR0_B8ZS | RCR0_LFA_26F | RCR0_RZCS_NBPV);
+ ebus_write(&ac->art_ebus, Bt8370_RLB, 0x09);
+ ebus_write(&ac->art_ebus, Bt8370_LBA, 0x08);
+ ebus_write(&ac->art_ebus, Bt8370_LBD, 0x24);
+ ebus_write(&ac->art_ebus, Bt8370_RALM, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_LATCH, LATCH_STOPCNT);
+
+ /* Transmitter TLIU, XMTR */
+ ebus_write(&ac->art_ebus, Bt8370_TCR0, TCR0_ESFCRC);
+ /* This one is critical */
+ ebus_write(&ac->art_ebus, Bt8370_TCR1, TCR1_TABORT |
+ TCR1_26F | TCR1_B8ZS);
+ ebus_write(&ac->art_ebus, Bt8370_TFRM, TFRM_CRC |
+ TFRM_FBIT);
+ ebus_write(&ac->art_ebus, Bt8370_TMAN, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TALM, TALM_AYEL);
+ ebus_write(&ac->art_ebus, Bt8370_TPATT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TLB, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSA4, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA5, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA6, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA7, 0xFF);
+ ebus_write(&ac->art_ebus, Bt8370_TSA8, 0xFF);
+
+ /* Bit Oriented Protocol Transceiver BOP setup */
+ bt8370_set_bop_mode(ac, ART_BOP_ESF);
+
+ /* Data Link #1 set to BOP mode for FDL */
+ bt8370_set_dl_1_mode(ac, ART_DL1_BOP);
+
+ /* Data Link #2 disabled */
+ bt8370_set_dl_2_mode(ac, 0);
+
+ ACCOOM_PRINTF(1, ("%s: set to T1 ESF CRC6, B8ZS\n",
+ ac->art_dev.dv_xname));
+ break;
+ /*
+ * case FAS_BSLIP:
+ * case FAS_CRC_BSLIP:
+ * case FAS_CAS:
+ * case FAS_CAS_BSLIP:
+ * case FAS_CRC_CAS:
+ * case FAS_CRC_CAS_BSLIP:
+ * case FT:
+ * case ESF_NOCRC:
+ * case SF_JYEL:
+ * case SF_T1DM:
+ * case SLC_FSLOF:
+ * case SLC:
+ * case ESF_xx (MimicCRC, ForceCRC?)
+ *
+ * are not yet implemented.
+ * If you need one of them please contact us.
+ */
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+void
+bt8370_set_sbi_clock_mode(struct art_softc *ac, enum art_sbi_type mode,
+ u_int linemode, int channels)
+{
+ u_int8_t cmux, jatcr;
+
+ /*
+ * mode is either master or slave.
+ * linemode is either T1 (1544) or E1 (2048) external or internal.
+ */
+ switch (mode) {
+ case ART_SBI_MASTER:
+ /*
+ * ONESEC pulse output,
+ * RDL/TDL/INDY ignored,
+ * RFSYNC Receive Frame Sync output,
+ * RMSYNC Reveice MultiFrame Sync output,
+ * TFYNC Transmit Frame Sync output,
+ * TMSYNC Transmit MultiFrame Sync output.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_PIO, PIO_ONESEC_IO |
+ PIO_RFSYNC_IO | PIO_RMSYNC_IO | PIO_TFSYNC_IO |
+ PIO_TMSYNC_IO);
+ /*
+ * TDL/RDL/INDY/TCKO three-stated.
+ * CLADO enabled, drives SBI bus RCLK, TCLK and
+ * is connected to own TSBCKI and TSBCKI on slave.
+ * RCKO enabled, is connected to TCKI on slave.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_POE, POE_TDL_OE |
+ POE_RDL_OE | POE_INDY_OE | POE_TCKO_OE);
+ /*
+ * We are the SBI bus master and take clock from our own
+ * CLADO. The TCKI source depends on line or internal
+ * clocking.
+ */
+ cmux = CMUX_RSBCKI_CLADO | CMUX_TSBCKI_CLADO |
+ CMUX_CLADI_CLADI;
+ break;
+ case ART_SBI_SLAVE:
+ /*
+ * ONESEC pulse input,
+ * RDL/TDL/INDY ignored,
+ * RFSYNC Receive Frame Sync input,
+ * RMSYNC Reveice MultiFrame Sync input,
+ * TFYNC Transmit Frame Sync input,
+ * TMSYNC Transmit MultiFrame Sync input.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_PIO, 0x00);
+ /*
+ * TDL/RDL/INDY/TCKO three-stated.
+ * CLADO enabled, is connected to own ACKI and
+ * RSBCKI, ACKI on master.
+ * RCKO enabled, is connected to TCKI on master.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_POE, POE_TDL_OE |
+ POE_RDL_OE | POE_INDY_OE | POE_TCKO_OE);
+ /*
+ * We are the SBI bus slave and take clock from TSBCKI.
+ * The TCKI source depends on line or internal clocking.
+ */
+ cmux = CMUX_RSBCKI_TSBCKI | CMUX_TSBCKI_TSBCKI |
+ CMUX_CLADI_CLADI;
+ break;
+ case ART_SBI_SINGLE_T1:
+ case ART_SBI_SINGLE_E1:
+ /*
+ * ONESEC pulse output,
+ * RDL/TDL/INDY ignored,
+ * RFSYNC Receive Frame Sync output,
+ * RMSYNC Reveice MultiFrame Sync output,
+ * TFYNC Transmit Frame Sync output,
+ * TMSYNC Transmit MultiFrame Sync output.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_PIO, PIO_ONESEC_IO |
+ PIO_TDL_IO | PIO_RFSYNC_IO | PIO_RMSYNC_IO |
+ PIO_TFSYNC_IO | PIO_TMSYNC_IO);
+ /*
+ * TDL/RDL/INDY/TCKO three-stated, CLADO/RCKO enabled.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_POE, POE_TDL_OE |
+ POE_RDL_OE | POE_INDY_OE | POE_RCKO_OE);
+ /*
+ * We are the SBI bus master and take clock from our own
+ * CLADO. The TCKI source is always CLADO (jitter attenuated
+ * if receive clock).
+ */
+ cmux = CMUX_RSBCKI_CLADO | CMUX_TSBCKI_CLADO |
+ CMUX_CLADI_RCKO;
+ break;
+ }
+
+ /* Transmit clock from where? */
+ switch (linemode) {
+ case IFM_TDM_MASTER:
+ if (mode == ART_SBI_MASTER)
+ cmux |= CMUX_TCKI_RSBCKI;
+ else
+ cmux |= CMUX_TCKI_CLADO;
+ jatcr = JAT_CR_JFREE;
+ break;
+ /* case ART_CLOCK_EXTREF: */
+ default:
+ cmux |= CMUX_TCKI_RCKO;
+ jatcr = JAT_CR_JEN | JAT_CR_JDIR_RX | JAT_CR_JSIZE32;
+ break;
+ }
+
+ ebus_write(&ac->art_ebus, Bt8370_CMUX, cmux);
+ ebus_write(&ac->art_ebus, Bt8370_JAT_CR, jatcr);
+
+ /* Set up the SBI (System Bus Interface) and clock source. */
+ switch (mode) {
+ case ART_SBI_MASTER:
+ ebus_write(&ac->art_ebus, Bt8370_CSEL, CSEL_VSEL_4096 |
+ CSEL_OSEL_4096);
+ bt8370_set_bus_mode(ac, SBI_MODE_4096_A, channels);
+ break;
+ case ART_SBI_SLAVE:
+ /*
+ * On the slave the CLADO depends on the line type
+ * of the master.
+ */
+ bt8370_set_bus_mode(ac, SBI_MODE_4096_B, channels);
+ break;
+ case ART_SBI_SINGLE_T1:
+ ebus_write(&ac->art_ebus, Bt8370_CSEL, CSEL_VSEL_1544 |
+ CSEL_OSEL_1544);
+ bt8370_set_bus_mode(ac, SBI_MODE_1544, channels);
+ break;
+ case ART_SBI_SINGLE_E1:
+ ebus_write(&ac->art_ebus, Bt8370_CSEL, CSEL_VSEL_2048 |
+ CSEL_OSEL_2048);
+ bt8370_set_bus_mode(ac, SBI_MODE_2048, channels);
+ break;
+ }
+ ebus_write(&ac->art_ebus, Bt8370_CLAD_CR, CLAD_CR_LFGAIN);
+}
+
+void
+bt8370_set_bus_mode(struct art_softc *ac, enum art_sbi_mode mode, int nchannels)
+{
+ bus_size_t channel;
+
+ /*
+ * Be aware that on the CN847x 'TSYNC_EDGE' has to be set to
+ * 'raising edge' in the port config for this to work correctly.
+ * All others (including RSYNC) are on 'falling edge'.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_RSB_CR, RSB_CR_SIG_OFF |
+ RSB_CR_RPCM_NEG | RSB_CR_RSYN_NEG | RSB_CR_RSB_CTR |
+ TSB_CR_TSB_NORMAL);
+ ebus_write(&ac->art_ebus, Bt8370_RSYNC_BIT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_RSYNC_TS, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSB_CR, TSB_CR_TPCM_NEG |
+ TSB_CR_TSYN_NEG | TSB_CR_TSB_CTR | TSB_CR_TSB_NORMAL);
+ ebus_write(&ac->art_ebus, Bt8370_TSYNC_BIT, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSYNC_TS, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_RSIG_CR, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_RSYNC_FRM, 0x00);
+
+ /* Mode dependent */
+ switch (mode) {
+ case SBI_MODE_1536:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_1536);
+ break;
+ case SBI_MODE_1544:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_1544);
+ break;
+ case SBI_MODE_2048:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_2048);
+ break;
+ case SBI_MODE_4096_A:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_4096_A);
+ break;
+ case SBI_MODE_4096_B:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_4096_B);
+ break;
+ case SBI_MODE_8192_A:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_8192_A);
+ break;
+ case SBI_MODE_8192_B:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_8192_B);
+ break;
+ case SBI_MODE_8192_C:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_8192_C);
+ break;
+ case SBI_MODE_8192_D:
+ ebus_write(&ac->art_ebus, Bt8370_SBI_CR, SBI_CR_SBI_OE |
+ SBI_CR_8192_D);
+ break;
+ }
+
+ /* Initialize and reset all channels */
+ for (channel = 0; channel < 32; channel++) {
+ ebus_write(&ac->art_ebus, Bt8370_SBCn + channel, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TPCn + channel, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSIGn + channel, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_TSLIP_LOn + channel, 0x7e);
+ ebus_write(&ac->art_ebus, Bt8370_RSLIP_LOn + channel, 0x7e);
+ ebus_write(&ac->art_ebus, Bt8370_RPCn + channel, 0x00);
+ }
+
+ /* Configure used channels */
+ for (channel = Bt8370_SBCn; channel < Bt8370_SBCn +
+ nchannels; channel++) {
+ ebus_write(&ac->art_ebus, channel, SBCn_RINDO |
+ SBCn_TINDO | SBCn_ASSIGN);
+ /* In T1 mode timeslot 0 must not be used. */
+ if (nchannels == 24 && channel == 0)
+ ebus_write(&ac->art_ebus, channel, 0x00);
+ }
+ for (channel = Bt8370_TPCn; channel < Bt8370_TPCn +
+ nchannels; channel++) {
+ ebus_write(&ac->art_ebus, channel, TPCn_CLEAR);
+ }
+ for (channel = Bt8370_RPCn; channel < Bt8370_RPCn +
+ nchannels; channel++) {
+ ebus_write(&ac->art_ebus, channel, RPCn_CLEAR);
+ }
+}
+
+void
+bt8370_set_line_buildout(struct art_softc *ac, int mode)
+{
+ /*
+ * LIU Stuff: Send and Reveive side
+ * T1: 0-133, 133-266, 266-399, 399-533, 533-655,
+ * Long-Haul FCC Part 68.
+ * E1: ITU-T G.703 120 Ohm Twisted Pair.
+ */
+
+ ebus_write(&ac->art_ebus, Bt8370_RLIU_CR, RLIU_CR_FRZ_SHORT |
+ RLIU_CR_AGC2048 | RLIU_CR_LONG_EYE);
+
+ switch (mode) {
+#if 0
+ case FRAMER_LIU_T1_133:
+ /* fallthrough */
+ case FRAMER_LIU_T1_266:
+ /* fallthrough */
+ case FRAMER_LIU_T1_399:
+ /* fallthrough */
+ case FRAMER_LIU_T1_533:
+ /* fallthrough */
+ case FRAMER_LIU_T1_655:
+ /* fallthrough */
+ case FRAMER_LIU_T1_LH68:
+ /* fallthrough */
+ case FRAMER_LIU_E1_120:
+ /* fallthrough */
+#endif
+ default:
+ /* Short haul */
+ ebus_write(&ac->art_ebus, Bt8370_VGA_MAX, 0x1F);
+ /* Force EQ off */
+ ebus_write(&ac->art_ebus, Bt8370_PRE_EQ, 0xA6);
+
+ ebus_write(&ac->art_ebus, Bt8370_TLIU_CR, TLIU_CR_120);
+ break;
+ }
+
+ /*
+ * Run this last. The RLIU reset causes the values written above
+ * to be activated.
+ */
+ ebus_write(&ac->art_ebus, Bt8370_LIU_CR, LIU_CR_MAGIC |
+ LIU_CR_SQUELCH | LIU_CR_RST_LIU);
+}
+
+void
+bt8370_set_loopback_mode(struct art_softc *ac, enum art_loopback mode)
+{
+ switch (mode) {
+ case ART_RLOOP_PAYLOAD: /* Remote digital payload loopback */
+ ebus_write(&ac->art_ebus, Bt8370_LOOP, LOOP_PLOOP);
+ break;
+ case ART_RLOOP_LINE: /* Remote analog line signal loopback */
+ ebus_write(&ac->art_ebus, Bt8370_LOOP, LOOP_LLOOP);
+ break;
+ case ART_LLOOP_PAYLOAD: /* Local digital payload loopback */
+ ebus_write(&ac->art_ebus, Bt8370_LOOP, LOOP_FLOOP);
+ break;
+ case ART_LLOOP_LINE: /* Local analog line signal loopback */
+ ebus_write(&ac->art_ebus, Bt8370_LOOP, LOOP_ALOOP);
+ break;
+ case ART_NOLOOP: /* Disable all loopbacks */
+ ebus_write(&ac->art_ebus, Bt8370_LOOP, 0x00);
+ break;
+ }
+}
+
+void
+bt8370_set_bop_mode(struct art_softc *ac, int mode)
+{
+ /* disabled or ESF mode */
+ switch (mode) {
+ case ART_BOP_ESF:
+ ebus_write(&ac->art_ebus, Bt8370_BOP, 0x9A);
+ break;
+ default:
+ ebus_write(&ac->art_ebus, Bt8370_BOP, 0x00);
+ break;
+ }
+}
+
+void
+bt8370_set_dl_1_mode(struct art_softc *ac, int mode)
+{
+ /*
+ * We don't support the builtin HDLC controllers,
+ * however some DL1 registers are used for the BOP
+ * in ESF mode.
+ */
+ switch (mode) {
+ case ART_DL1_BOP:
+ ebus_write(&ac->art_ebus, Bt8370_DL1_TS, 0x40);
+ ebus_write(&ac->art_ebus, Bt8370_DL1_CTL, 0x03);
+ ebus_write(&ac->art_ebus, Bt8370_RDL1_FFC, 0x0A);
+ ebus_write(&ac->art_ebus, Bt8370_PRM1, 0x80);
+ ebus_write(&ac->art_ebus, Bt8370_TDL1_FEC, 0x0A);
+ break;
+ default:
+ ebus_write(&ac->art_ebus, Bt8370_RDL1_FFC, 0x0A);
+ ebus_write(&ac->art_ebus, Bt8370_TDL1, 0x00);
+ break;
+ }
+}
+
+void
+bt8370_set_dl_2_mode(struct art_softc *ac, int mode)
+{
+ /* We don't support the builtin HDLC controllers. */
+ ebus_write(&ac->art_ebus, Bt8370_RDL2_FFC, 0x0A);
+ ebus_write(&ac->art_ebus, Bt8370_TDL2, 0x00);
+}
+
+void
+bt8370_intr_enable(struct art_softc *ac, int intr)
+{
+ switch (intr) {
+ default:
+ /* Disable all interrupts */
+ ebus_write(&ac->art_ebus, Bt8370_IER7, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER6, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER5, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER4, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER3, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER2, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER1, 0x00);
+ ebus_write(&ac->art_ebus, Bt8370_IER0, 0x00);
+ break;
+ }
+ return;
+}
+
+void
+bt8370_intr(struct art_softc *ac)
+{
+ u_int8_t irr, alrm;
+
+ /* IRR tells us which interrupt class fired. */
+ irr = ebus_read(&ac->art_ebus, Bt8370_IRR);
+ /* If it wasn't us don't waste time. */
+ if (irr == 0x00)
+ return;
+
+ /* Reding the interrupt service registers clears them. */
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR7);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR6);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR5);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR4);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR3);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR2);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR1);
+ alrm = ebus_read(&ac->art_ebus, Bt8370_ISR0);
+
+ /* IRR should be zero now or something went wrong. */
+ irr = ebus_read(&ac->art_ebus, Bt8370_IRR);
+ if (irr != 0x00)
+ ACCOOM_PRINTF(0, ("%s: Interrupts did not clear properly\n",
+ ac->art_dev.dv_xname));
+ return;
+}
+
+int
+bt8370_link_status(struct art_softc *ac)
+{
+ u_int8_t rstat, alm1, alm2, alm3;
+ int status = 1;
+
+ /*
+ * 1 everything fine
+ * 0 framing problems but link detected
+ * -1 no link detected
+ */
+
+ rstat = ebus_read(&ac->art_ebus, Bt8370_RSTAT);
+ alm1 = ebus_read(&ac->art_ebus, Bt8370_ALM1);
+ alm2 = ebus_read(&ac->art_ebus, Bt8370_ALM2);
+ alm3 = ebus_read(&ac->art_ebus, Bt8370_ALM3);
+
+ if ((rstat & (RSTAT_EXZ | RSTAT_BPV)) ||
+ (alm1 & (ALM1_RYEL | ALM1_RAIS | ALM1_RALOS | ALM1_RLOF)) ||
+ (alm3 & (ALM3_SEF)))
+ status = 0;
+
+ if ((alm1 & (ALM1_RLOS)) ||
+ (alm2 & (ALM2_TSHORT)))
+ status = -1;
+
+ return (status);
+}
+
+#ifdef ACCOOM_DEBUG
+void
+bt8370_print_status(struct art_softc *ac)
+{
+ u_int8_t fstat, rstat, vga, alm1, alm2, alm3, sstat, loop;
+
+ /* FSTAT Register. */
+ fstat = ebus_read(&ac->art_ebus, Bt8370_FSTAT);
+ printf("%s: Current FSTAT:\n", ac->art_dev.dv_xname);
+ if (fstat & FSTAT_ACTIVE) {
+ printf("\tOffline Framer active ");
+ if (fstat & FSTAT_RXTXN)
+ printf("in Receive direction\n");
+ else
+ printf("in Transmit direction\n");
+ if (fstat & FSTAT_INVALID)
+ printf("\tNo Candidate found\n");
+ if (fstat & FSTAT_FOUND)
+ printf("\tFrame Alignment found\n");
+ if (fstat & FSTAT_TIMEOUT)
+ printf("\tFramer Search timeout\n");
+ } else
+ printf("\tOffline inactive\n");
+
+ /* RSTAT and VGA Register. */
+ rstat = ebus_read(&ac->art_ebus, Bt8370_RSTAT);
+ printf("%s: Current RSTAT:\n", ac->art_dev.dv_xname);
+ if (rstat & RSTAT_CPDERR)
+ printf("\tCLAD phase detector lost lock to CLADI reference\n");
+ if (rstat & RSTAT_ZCSUB)
+ printf("\tHDB3/B8ZS pattern detected\n");
+ if (rstat & RSTAT_EXZ)
+ printf("\tExcessive zeros detected\n");
+ if (rstat & RSTAT_BPV)
+ printf("\tBipolar violations\n");
+ if (rstat & RSTAT_EYEOPEN)
+ printf("\tReceived signal valid and RPLL locked\n");
+ else
+ printf("\tReceived signal invalid\n");
+ if (rstat & RSTAT_PRE_EQ)
+ printf("\tPre-Equalizer is ON\n");
+ else
+ printf("\tPre-Equalizer is OFF\n");
+ /* Need to write something to cause internal update. */
+ ebus_write(&ac->art_ebus, Bt8370_VGA, 0x00);
+ vga = ebus_read(&ac->art_ebus, Bt8370_VGA);
+ printf("\t%i dB Gain\n", vga);
+
+ /* Alarm 1 Status. */
+ alm1 = ebus_read(&ac->art_ebus, Bt8370_ALM1);
+ printf("%s: Current ALM1:\n", ac->art_dev.dv_xname);
+ if (alm1 & ALM1_RMYEL)
+ printf("\tMultiframe Yellow Alarm [MYEL]\n");
+ if (alm1 & ALM1_RYEL)
+ printf("\tYellow Alarm [YEL]\n");
+ if (alm1 & ALM1_RAIS)
+ printf("\tRemote Alarm Indication [RAIS]\n");
+ if (alm1 & ALM1_RALOS)
+ printf("\tAnalog Loss of Signal or RCKI Loss of Clock [RALOS]\n");
+ if (alm1 & ALM1_RLOS)
+ printf("\tLoss of Signal [RLOS]\n");
+ if (alm1 & ALM1_RLOF)
+ printf("\tLoss of Frame Alignment [RLOF]\n");
+ if (alm1 & ALM1_SIGFRZ)
+ printf("\tSignalling Freeze\n");
+
+ /* Alarm 2 Status. */
+ alm2 = ebus_read(&ac->art_ebus, Bt8370_ALM2);
+ printf("%s: Current ALM2:\n", ac->art_dev.dv_xname);
+ if (alm2 & ALM2_LOOPDN)
+ printf("\tLOOPDN code detected\n");
+ if (alm2 & ALM2_LOOPUP)
+ printf("\tLOOPUP code detected\n");
+ if (alm2 & ALM2_TSHORT)
+ printf("\tTransmitter short circuit\n");
+ if (alm2 & ALM2_TLOC)
+ printf("\tTransmit loss of clock (relative to ACKI)\n");
+ if (alm2 & ALM2_TLOF)
+ printf("\tTransmit loss of frame alignment (ignored)\n");
+
+ /* Alarm 3 Status. */
+ alm3 = ebus_read(&ac->art_ebus, Bt8370_ALM3);
+ printf("%s: Current ALM3:\n", ac->art_dev.dv_xname);
+ if (alm3 & ALM3_RMAIS)
+ printf("\tRMAIS TS16 Alarm Indication Signal\n");
+ if (alm3 & ALM3_SEF)
+ printf("\tSeverely Errored Frame encountered\n");
+ if (alm3 & ALM3_SRED)
+ printf("\tLoss of CAS Alignment\n");
+ if (alm3 & ALM3_MRED)
+ printf("\tLoss of MFAS Alignment\n");
+ if (alm3 & ALM3_FRED)
+ printf("\tLoss of T1/FAS Alignment\n");
+ /* LOF omitted */
+
+ /* Slip Buffer Status. */
+ sstat = ebus_read(&ac->art_ebus, Bt8370_SSTAT);
+ printf("%s: Current SSTAT:\n", ac->art_dev.dv_xname);
+ if (sstat & SSTAT_TFSLIP) {
+ if (sstat & SSTAT_TUSLIP)
+ printf("\tControlled Transmit Slip, ");
+ else
+ printf("\tUncontrolled Transmit Slip, ");
+ if (sstat & SSTAT_TSDIR)
+ printf("repeated one frame\n");
+ else
+ printf("deleted one frame\n");
+ } else if (sstat & SSTAT_RFSLIP) {
+ if (sstat & SSTAT_RUSLIP)
+ printf("\tControlled Receive Slip, ");
+ else
+ printf("\tUncontrolled Receive Slip, ");
+ if (sstat & SSTAT_RSDIR)
+ printf("repeated one frame\n");
+ else
+ printf("deleted one frame\n");
+ }
+
+ /* Loopback Status. */
+ loop = ebus_read(&ac->art_ebus, Bt8370_LOOP);
+ printf("%s: Current LOOP:\n", ac->art_dev.dv_xname);
+ if (loop & LOOP_PLOOP)
+ printf("\tRemote Payload Loopback\n");
+ if (loop & LOOP_LLOOP)
+ printf("\tRemote Line Loopback\n");
+ if (loop & LOOP_FLOOP)
+ printf("\tLocal Payload Loopback\n");
+ if (loop & LOOP_ALOOP)
+ printf("\tLocal Line Loopback\n");
+ if (loop & 0x00)
+ printf("\tNo active Loopbacks\n");
+}
+
+void
+bt8370_dump_registers(struct art_softc *ac)
+{
+ int i;
+
+ printf("%s: dummping registers", ac->art_dev.dv_xname);
+ for (i = 0; i < 0x200; i++) {
+ if (i % 16 == 0)
+ printf("\n%03x:", i);
+ printf("%s%02x%s", i % 2 ? "" : " ",
+ ebus_read(&ac->art_ebus, i),
+ i % 8 == 7 ? " " : "");
+ }
+ printf("\n");
+}
+
+#endif
diff --git a/sys/dev/pci/bt8370reg.h b/sys/dev/pci/bt8370reg.h
new file mode 100644
index 00000000000..70b29e5ecde
--- /dev/null
+++ b/sys/dev/pci/bt8370reg.h
@@ -0,0 +1,393 @@
+/* $OpenBSD: bt8370reg.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: bt8370reg.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Andre Oppermann <oppermann@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Bt8370 Register definitions */
+/* Globals */
+#define Bt8370_DID 0x000 /* Device Identification */
+#define Bt8370_CR0 0x001 /* Primary control register */
+#define CR0_RESET 0x80 /* Reset Framer */
+#define CR0_E1_FAS 0x00 /* E1 FAS only */
+#define CR0_E1_FAS_CRC 0x08 /* E1 FAS+CRC4 */
+#define CR0_T1_SF 0x09 /* T1 SF */
+#define CR0_T1_ESF 0x1A /* T1 ESF+ForceCRC */
+#define Bt8370_JAT_CR 0x002 /* Jitter attenuator conf */
+#define JAT_CR_JEN 0x80 /* Jitter anntenuator enable */
+#define JAT_CR_JFREE 0x40 /* Free running JCLK and CLADO */
+#define JAT_CR_JDIR_TX 0x00 /* JAT in TX direction */
+#define JAT_CR_JDIR_RX 0x20 /* JAT in RC direction */
+#define JAT_CR_JAUTO 0x10 /* JCLK Acceleration */
+#define JAT_CR_CENTER 0x80 /* Force JAT to center */
+#define JAT_CR_JSIZE8 0x00 /* Elastic store size 8 bits */
+#define JAT_CR_JSIZE16 0x01 /* Elastic store size 16 bits */
+#define JAT_CR_JSIZE32 0x02 /* Elastic store size 32 bits */
+#define JAT_CR_JSIZE64 0x03 /* Elastic store size 64 bits */
+#define JAT_CR_JSIZE128 0x04 /* Elastic store size 128 bits */
+#define Bt8370_IRR 0x003 /* Interrupt request register */
+/* Interrupt Status */
+#define Bt8370_ISR7 0x004 /* Alarm 1 Interrupt Status */
+#define Bt8370_ISR6 0x005 /* Alarm 2 Interrupt Status */
+#define Bt8370_ISR5 0x006 /* Error Interrupt Status */
+#define Bt8370_ISR4 0x007 /* Counter Overflow Interrupt Status */
+#define Bt8370_ISR3 0x008 /* Timer Interrupt Status */
+#define Bt8370_ISR2 0x009 /* Data Link 1 Interrupt Status */
+#define Bt8370_ISR1 0x00A /* Data Link 2 Interrupt Status */
+#define Bt8370_ISR0 0x00B /* Pattern Interrupt Status */
+/* Interrupt Enable */
+#define Bt8370_IER7 0x00C /* Alarm 1 Interrupt Enable register */
+#define Bt8370_IER6 0x00D /* Alarm 2 Interrupt Enable register */
+#define Bt8370_IER5 0x00E /* Error Interrupt Enable register */
+#define Bt8370_IER4 0x00F /* Count Overflow Interrupt Enable register */
+#define Bt8370_IER3 0x010 /* Timer Interrupt Enable register */
+#define Bt8370_IER2 0x011 /* Data Link 1 Interrupt Enable register */
+#define Bt8370_IER1 0x012 /* Date Link 2 Interrupt Enable register */
+#define Bt8370_IER0 0x013 /* Pattern Interrupt Enable register */
+/* Primary */
+#define Bt8370_LOOP 0x014 /* Loopback Configuration register */
+#define LOOP_PLOOP 0x08 /* Remote Payload Loopback */
+#define LOOP_LLOOP 0x04 /* Remote Line Loopback */
+#define LOOP_FLOOP 0x02 /* Local Framer Loopback */
+#define LOOP_ALOOP 0x01 /* Local Analog Loopback */
+#define Bt8370_DL3_TS 0x015 /* External Data Link Channel */
+#define Bt8370_DL3_BIT 0x016 /* External Data Link Bit */
+#define Bt8370_FSTAT 0x017 /* Offline Framer Status */
+#define FSTAT_INVALID 0x10 /* No candidate */
+#define FSTAT_FOUND 0x08 /* Frame Search Successful */
+#define FSTAT_TIMEOUT 0x04 /* Framer Search Timeout */
+#define FSTAT_ACTIVE 0x02 /* Framer Active */
+#define FSTAT_RXTXN 0x01 /* RX/TX Reframe Operation */
+#define Bt8370_PIO 0x018 /* Programmable Input/Output */
+#define PIO_ONESEC_IO 0x80 /* */
+#define PIO_RDL_IO 0x40 /* */
+#define PIO_TDL_IO 0x20 /* */
+#define PIO_INDY_IO 0x10 /* */
+#define PIO_RFSYNC_IO 0x08 /* */
+#define PIO_RMSYNC_IO 0x04 /* */
+#define PIO_TFSYNC_IO 0x02 /* */
+#define PIO_TMSYNC_IO 0x01 /* */
+#define Bt8370_POE 0x019 /* Programmable Output Enable */
+#define POE_TDL_OE 0x20 /* */
+#define POE_RDL_OE 0x10 /* */
+#define POE_INDY_OE 0x08 /* */
+#define POE_TCKO_OE 0x04 /* */
+#define POE_CLADO_OE 0x02 /* */
+#define POE_RCKO_OE 0x01 /* */
+#define Bt8370_CMUX 0x01A /* Clock Input Mux */
+#define CMUX_RSBCKI_RSBCKI 0x00 /* */
+#define CMUX_RSBCKI_TSBCKI 0x40 /* */
+#define CMUX_RSBCKI_CLADI 0x80 /* */
+#define CMUX_RSBCKI_CLADO 0xC0 /* */
+#define CMUX_TSBCKI_TSBCKI 0x00 /* */
+#define CMUX_TSBCKI_RSBCKI 0x10 /* */
+#define CMUX_TSBCKI_CLADI 0x20 /* */
+#define CMUX_TSBCKI_CLADO 0x30 /* */
+#define CMUX_CLADI_CLADI 0x00 /* */
+#define CMUX_CLADI_RCKO 0x04 /* */
+#define CMUX_CLADI_TSBCKI 0x08 /* */
+#define CMUX_CLADI_TCKI 0x0C /* */
+#define CMUX_TCKI_TCKI 0x00 /* */
+#define CMUX_TCKI_RCKO 0x01 /* */
+#define CMUX_TCKI_RSBCKI 0x02 /* */
+#define CMUX_TCKI_CLADO 0x03 /* */
+#define Bt8370_TMUX 0x01B /* Test Mux Configuration */
+#define Bt8370_TEST 0x01C /* Test Configuration */
+/* Receive LIU (RLIU) */
+#define Bt8370_LIU_CR 0x020 /* LIU Configuration */
+#define LIU_CR_RST_LIU 0x80 /* Reset RLIU */
+#define LIU_CR_SQUELCH 0x40 /* Enable Squelch */
+#define LIU_CR_FORCE_VGA 0x20 /* Internal Variable Gain Amp */
+#define LIU_CR_RDIGI 0x10 /* Enable Receive Digital Inputs */
+#define LIU_CR_ATTN0 0x00 /* Bridge Attenuation 0db */
+#define LIU_CR_ATTN10 0x04 /* Bridge Attenuation -10db */
+#define LIU_CR_ATTN20 0x08 /* Bridge Attenuation -20db */
+#define LIU_CR_ATTN30 0x0C /* Bridge Attenuation -30db */
+#define LIU_CR_MAGIC 0x01 /* This one must be enabled */
+#define Bt8370_RSTAT 0x021 /* Receive LIU Status */
+#define RSTAT_CPDERR 0x80 /* CLAD Phase detector lost lock */
+#define RSTAT_JMPTY 0x40 /* JAT Empty/Full */
+#define RSTAT_ZCSUB 0x20 /* ZCS detected */
+#define RSTAT_EXZ 0x10 /* Excessive Zeros */
+#define RSTAT_BPV 0x08 /* Bipolar Violations */
+#define RSTAT_EYEOPEN 0x02 /* Equalization State */
+#define RSTAT_PRE_EQ 0x01 /* Pre-Equalizer Status */
+#define Bt8370_RLIU_CR 0x022 /* Receive LIU Configuration */
+#define RLIU_CR_FRZ_SHORT 0x80 /* Freeze Equalizer for short lines */
+#define RLIU_CR_HI_CLICE 0x40 /* High Clock Slicer Threshold */
+#define RLIU_CR_AGC32 0x00 /* AGC Observation Window 32bit */
+#define RLIU_CR_AGC128 0x10 /* AGC Observation Window 128bit */
+#define RLIU_CR_AGC512 0x20 /* AGC Observation Window 512bit */
+#define RLIU_CR_AGC2048 0x30 /* AGC Observation Window 2048bit */
+#define RLIU_CR_EQ_FRZ 0x08 /* Freeze EQ Coefficients */
+#define RLIU_CR_OOR_BLOCK 0x04 /* Disable automatic RLBO */
+#define RLIU_CR_RLBO 0x02 /* Receiver Line Build Out */
+#define RLIU_CR_LONG_EYE 0x01 /* Eye Open Timeout 8192bit */
+#define Bt8370_LPF 0x023 /* RPLL Low Pass Filter */
+#define Bt8370_VGA_MAX 0x024 /* Variable Gain Amplifier Maximum */
+#define Bt8370_EQ_DAT 0x025 /* Equalizer Coefficient Data register */
+#define Bt8370_EQ_PTR 0x026 /* Equalizer Coefficient Table Pointer */
+#define Bt8370_DSLICE 0x027 /* Data Slicer Threshold */
+#define Bt8370_EQ_OUT 0x028 /* Equalizer Output Levels */
+#define Bt8370_VGA 0x029 /* Variable Gain Amplifier Status */
+#define Bt8370_PRE_EQ 0x02A /* Pre-Equalizer */
+#define Bt8370_COEFF 0x030 /* -037 *//* LMS Adjusted Equalizer Coefficient Status */
+#define Bt8370_GAIN 0x038 /* -03C *//* Equalizer Gain Thresholds */
+/* Digital Reveiver (RCVR) */
+#define Bt8370_RCR0 0x040 /* Receiver Configuration */
+#define RCR0_HDB3 0x00 /* */
+#define RCR0_B8ZS 0x00 /* */
+#define RCR0_AMI 0x80 /* */
+#define RCR0_RABORT 0x40 /* */
+#define RCR0_RFORCE 0x20 /* */
+#define RCR0_LFA_FAS 0x18 /* 3 consecutive FAS Errors */
+#define RCR0_LFA_FASCRC 0x08 /* 3 consecutive FAS or 915 CRC Errors */
+#define RCR0_LFA_26F 0x08 /* 2 out of 6 F bit Errors */
+#define RCR0_RZCS_BPV 0x00 /* */
+#define RCR0_RZCS_NBPV 0x01 /* */
+#define Bt8370_RPATT 0x041 /* Receive Test Pattern Configuration */
+#define Bt8370_RLB 0x042 /* Receive Loopback Code Detector Configuration */
+#define Bt8370_LBA 0x043 /* Loopback Activate Code Pattern */
+#define Bt8370_LBD 0x044 /* Loopback Deactivate Code Pattern */
+#define Bt8370_RALM 0x045 /* Receive Alarm Signal Configuration */
+#define RALM_FSNFAS 0x20 /* Include FS/NFAS in FERR and FRED */
+#define Bt8370_LATCH 0x046 /* Alarm/Error/Counter Latch Configuration */
+#define LATCH_STOPCNT 0x08 /* Stop Error Counter during RLOF,RLOS,RAIS */
+#define Bt8370_ALM1 0x047 /* Alarm 1 Status */
+#define ALM1_RMYEL 0x80 /* Receive Multifram Yellow Alarm */
+#define ALM1_RYEL 0x40 /* Receive Yellow Alarm */
+#define ALM1_RAIS 0x10 /* Reveive Alarm Indication Signal */
+#define ALM1_RALOS 0x09 /* Receive Analog Loss of Signal */
+#define ALM1_RLOS 0x04 /* Receive Loss of Signal */
+#define ALM1_RLOF 0x02 /* Receive Loss of Frame Alignment */
+#define ALM1_SIGFRZ 0x01 /* Signalling Freeze */
+#define Bt8370_ALM2 0x048 /* Alarm 2 Status */
+#define ALM2_LOOPDN 0x80 /* */
+#define ALM2_LOOPUP 0x40 /* */
+#define ALM2_TSHORT 0x10 /* Transmit Short Circuit */
+#define ALM2_TLOC 0x08 /* Transmit Loss of clock */
+#define ALM2_TLOF 0x02 /* Transmit Loss of Frame alignment */
+#define Bt8370_ALM3 0x049 /* Alarm 3 Status */
+#define ALM3_RMAIS 0x40 /* Receive TS16 Alarm Indication */
+#define ALM3_SEF 0x20 /* Severely Errored Frame */
+#define ALM3_SRED 0x10 /* Loss of CAS Alignment */
+#define ALM3_MRED 0x08 /* Loss of MFAS Alignment */
+#define ALM3_FRED 0x04 /* Loss of T1/FAS Alignment */
+#define ALM3_LOF1 0x02 /* Reason for Loss of Frame Alignment */
+#define ALM3_LOF0 0x01 /* Reason for Loss of Frame Alignment */
+/* Error/Alarm Counters */
+#define Bt8370_FERR_LSB 0x050 /* Framing Bit Error Counter LSB */
+#define Bt8370_FERR_MSB 0x051 /* ditto MSB */
+#define Bt8370_CERR_LSB 0x052 /* CRC Error Counter LSB */
+#define Bt8370_CERR_MSB 0x053 /* ditto MSB */
+#define Bt8370_LCV_LSB 0x054 /* Line Code Violation Counter LSB*/
+#define Bt8370_LCV_MSB 0x055 /* ditto MSB */
+#define Bt8370_FEBE_LSB 0x056 /* Far End Block Error Counter LSB*/
+#define Bt8370_FEBE_MSB 0x057 /* ditto MSB */
+#define Bt8370_BERR_LSB 0x058 /* PRBS Bit Error Counter LSB */
+#define Bt8370_BERR_MSB 0x059 /* ditto MSB */
+/* Receive Sa-Byte */
+#define Bt8370_RSA4 0x05B /* Receive Sa4 Byte Buffer */
+#define Bt8370_RSA5 0x05C /* ditto Sa5 */
+#define Bt8370_RSA6 0x05D /* ditto Sa6 */
+#define Bt8370_RSA7 0x05E /* ditto Sa7 */
+#define Bt8370_RSA8 0x05F /* ditto Sa8 */
+/* Transmit LIU (TLIU) */
+#define Bt8370_SHAPE 0x060 /* -067 *//* Transmit Pulse Shape Configuration */
+#define Bt8370_TLIU_CR 0x068 /* Transmit LIU Configuration */
+#define TLIU_CR_120 0x4C /* 120 Ohms, external term */
+#define TLIU_CR_100 0x40 /* 100 Ohms, external term */
+/* Digital Transmitter (XMTR) */
+#define Bt8370_TCR0 0x070 /* Transmit Framer Configuration */
+#define TCR0_FAS 0x00 /* FAS Only */
+#define TCR0_MFAS 0x04 /* FAS + MFAS*/
+#define TCR0_SF 0x04 /* SF Only */
+#define TCR0_ESF 0x01 /* ESF Only */
+#define TCR0_ESFCRC 0x0D /* ESF + Force CRC */
+#define Bt8370_TCR1 0x071 /* Transmitter Configuration */
+#define TCR1_TABORT 0x40 /* Disable TX Offline Framer */
+#define TCR1_TFORCE 0x20 /* Force TX Reframe */
+#define TCR1_HDB3 0x01 /* Line code HDB3 */
+#define TCR1_B8ZS 0x01 /* Line code B8ZS */
+#define TCR1_AMI 0x00 /* Line code AMI */
+#define TCR1_3FAS 0x10 /* 3 consecutive FAS Errors */
+#define TCR1_26F 0x10 /* 2 out of 6 Frame Bit Errors */
+#define Bt8370_TFRM 0x072 /* Transmit Frame Format */
+#define TFRM_MYEL 0x20 /* Insert MultiFrame Yellow Alarm */
+#define TFRM_YEL 0x10 /* Insert Yellow Alarm */
+#define TFRM_MF 0x08 /* Insert MultiFrame Alignment */
+#define TFRM_FE 0x04 /* Insert FEBE */
+#define TFRM_CRC 0x02 /* Insert CRC4 */
+#define TFRM_FBIT 0x01 /* Insert F bit or FAS/NAS alignment */
+#define Bt8370_TERROR 0x073 /* Transmit Error Insert */
+#define Bt8370_TMAN 0x074 /* Transmit Manual Sa-Byte/FEBE Configuration */
+#define TMAN_MALL 0xF8 /* All Sa Bytes Manual */
+#define Bt8370_TALM 0x075 /* Transmit Alarm Signal Configuration */
+#define TALM_AMYEL 0x20 /* Automatic MultiFrame Yellow Alarm transmit */
+#define TALM_AYEL 0x10 /* Automatic Yellow Alarm transmit */
+#define TALM_AAIS 0x08 /* Automatic AIS Alarm transmit */
+#define Bt8370_TPATT 0x076 /* Transmit Test Pattern Configuration */
+#define Bt8370_TLB 0x077 /* Transmit Inband Loopback Code Configuration */
+#define Bt8370_LBP 0x078 /* Transmit Inband Loopback Code Pattern */
+/* Transmit Sa-Byte */
+#define Bt8370_TSA4 0x07B /* Transmit Sa4 Byte Buffer */
+#define Bt8370_TSA5 0x07C /* ditto Sa5 */
+#define Bt8370_TSA6 0x07D /* ditto Sa6 */
+#define Bt8370_TSA7 0x07E /* ditto Sa7 */
+#define Bt8370_TSA8 0x07F /* ditto Sa8 */
+/* Clock Rate Adapter (CLAD) */
+#define Bt8370_CLAD_CR 0x090 /* Clock Rate Adapter Configuration */
+#define CLAD_CR_CEN 0x80 /* Enable CLAD phase detector */
+#define CLAD_CR_XSEL_1X 0x00 /* Line rate multiplier 1X */
+#define CLAD_CR_XSEL_2X 0x10 /* Line rate multiplier 2X */
+#define CLAD_CR_XSEL_4X 0x20 /* Line rate multiplier 4X */
+#define CLAD_CR_XSEL_8X 0x30 /* Line rate multiplier 8X */
+#define CLAD_CR_LFGAIN 0x05 /* Loop filter gain */
+#define Bt8370_CSEL 0x091 /* CLAD Frequency Select */
+#define CSEL_VSEL_1536 0x60 /* 1536kHz */
+#define CSEL_VSEL_1544 0x50 /* 1544kHz */
+#define CSEL_VSEL_2048 0x10 /* 2048kHz */
+#define CSEL_VSEL_4096 0x20 /* 4096kHz */
+#define CSEL_VSEL_8192 0x30 /* 8192kHz */
+#define CSEL_OSEL_1536 0x06 /* 1536kHz */
+#define CSEL_OSEL_1544 0x05 /* 1544kHz */
+#define CSEL_OSEL_2048 0x01 /* 2048kHz */
+#define CSEL_OSEL_4096 0x02 /* 4096kHz */
+#define CSEL_OSEL_8192 0x03 /* 8192kHz */
+#define Bt8370_CPHASE 0x092 /* CLAD Phase Detector Scale Factor */
+#define Bt8370_CTEST 0x093 /* CLAD Test */
+/* Bit Oriented Protocol Transceiver (BOP) */
+#define Bt8370_BOP 0x0A0 /* Bit Oriented Protocol Transceiver */
+#define Bt8370_TBOP 0x0A1 /* Transmit BOP Code Word */
+#define Bt8370_RBOP 0x0A2 /* Receive BOP Code Word */
+#define Bt8370_BOP_STAT 0x0A3 /* BOP Status */
+/* Data Link #1 */
+#define Bt8370_DL1_TS 0x0A4 /* DL1 Time Slot Enable */
+#define Bt8370_DL1_BIT 0x0A5 /* DL1 Bit Enable */
+#define Bt8370_DL1_CTL 0x0A6 /* DL1 Control */
+#define Bt8370_RDL1_FFC 0x0A7 /* RDL #1 FIFO Fill Control */
+#define Bt8370_RDL1 0x0A8 /* Receive Data Link FIFO #1 */
+#define Bt8370_RDL1_STAT 0x0A9 /* RDL #1 Status */
+#define Bt8370_PRM1 0x0AA /* Performance Report Message */
+#define Bt8370_TDL1_FEC 0x0AB /* TDL #1 FIFO Empty Control */
+#define Bt8370_TDL1_EOM 0x0AC /* TDL #1 End of Message Control */
+#define Bt8370_TDL1 0x0AD /* Transmit Data Link FIFO #1*/
+#define Bt8370_TDL1_STAT 0x0AE /* TDL #1 Status */
+/* Data Link #2 */
+#define Bt8370_DL2_TS 0x0AF /* DL2 Time Slot Enable */
+#define Bt8370_DL2_BIT 0x0B0 /* DL2 Bit Enable */
+#define Bt8370_DL2_CTL 0x0B1 /* DL2 Control */
+#define Bt8370_RDL2_FFC 0x0B2 /* RDL #2 FIFO Fill Control */
+#define Bt8370_RDL2 0x0B3 /* Receive Data Link FIFO #2 */
+#define Bt8370_RDL2_STAT 0x0B4 /* RDL #2 Status */
+#define Bt8370_TDL2_FEC 0x0B6 /* TDL #2 FIFO Empty Control */
+#define Bt8370_TDL2_EOM 0x0B7 /* TDL #2 End of Message Control */
+#define Bt8370_TDL2 0x0B8 /* Transmit Data Link FIFO #2*/
+#define Bt8370_TDL2_STAT 0x0B9 /* TDL #2 Status */
+/* Test */
+#define Bt8370_TEST1 0x0BA /* DLINK Test Configuration */
+#define Bt8370_TEST2 0x0BB /* DLINK Test Status */
+#define Bt8370_TEST3 0x0BC /* DLINK Test Status */
+#define Bt8370_TEST4 0x0BD /* DLINK Test Control #1 or Configuration #2 */
+#define Bt8370_TEST5 0x0BE /* DLINK Test Control #2 or Configuration #2 */
+/* System Bus Interface (SBI) */
+#define Bt8370_SBI_CR 0x0D0 /* System Bus Interface Configuration */
+#define SBI_CR_X2CLK 0x80 /* Times 2 clock */
+#define SBI_CR_SBI_OE 0x40 /* Enable SBI */
+#define SBI_CR_1536 0x08 /* 1536, 24TS*/
+#define SBI_CR_1544 0x07 /* 1544, 24TS + F bit */
+#define SBI_CR_2048 0x06 /* 2048, 32TS */
+#define SBI_CR_4096_A 0x04 /* 4096 Group A */
+#define SBI_CR_4096_B 0x05 /* 4096 Group B */
+#define SBI_CR_8192_A 0x00 /* 8192 Group A */
+#define SBI_CR_8192_B 0x01 /* 8192 Group B */
+#define SBI_CR_8192_C 0x02 /* 8192 Group C */
+#define SBI_CR_8192_D 0x03 /* 8192 Group D */
+#define Bt8370_RSB_CR 0x0D1 /* Receive System Bus Configuration */
+#define RSB_CR_BUS_RSB 0x80 /* Multiple devices on bus */
+#define RSB_CR_SIG_OFF 0x40 /* Inhibit RPCMO Signal reinsertion */
+#define RSB_CR_RPCM_NEG 0x20 /* RSB falling edge */
+#define RSB_CR_RSYN_NEG 0x10 /* RFSYNC falling edge */
+#define RSB_CR_BUS_FRZ 0x08 /* Multiple devices on bus */
+#define RSB_CR_RSB_CTR 0x04 /* Force RSLIP Center */
+#define RSB_CR_RSBI_NORMAL 0x00 /* Normal Slip Buffer Mode */
+#define RSB_CR_RSBI_ELASTIC 0x02 /* Receive Slip Buffer Elastic Mode */
+#define RSB_CR_RSBI_BYPASS 0x03 /* Bypass Slip Buffer */
+#define Bt8370_RSYNC_BIT 0x0D2 /* Receive System Bus Sync Bit Offset */
+#define Bt8370_RSYNC_TS 0x0D3 /* Receive System Bus Sync Time Slot Offset */
+#define Bt8370_TSB_CR 0x0D4 /* Transmit System Bus Configuration */
+#define TSB_CR_BUS_TSB 0x80 /* Bused TSB output */
+#define TSB_CR_TPCM_NEG 0x20 /* TINDO falling edge */
+#define TSB_CR_TSYN_NEG 0x10 /* TFSYNC falling edge */
+#define TSB_CR_TSB_CTR 0x04 /* Force TSLIP Center */
+#define TSB_CR_TSB_NORMAL 0x00 /* Normal Slip Buffer Mode */
+#define TSB_CR_TSB_ELASTIC 0x02 /* Send Slip Buffer Elastic Mode */
+#define TSB_CR_TSB_BYPASS 0x03 /* Bypass Slip Buffer */
+#define Bt8370_TSYNC_BIT 0x0D5 /* Transmit System Bus Sync Bit Offset */
+#define Bt8370_TSYNC_TS 0x0D6 /* Transmit System Bus Sync Time Slot Offset */
+#define Bt8370_RSIG_CR 0x0D7 /* Receive Signaling Configuration */
+#define RSIG_CR_FRZ_OFF 0x04 /* Manual Signaling Update FRZ */
+#define RSIG_CR_THRU 0x01 /* Transparent Robbed Bit Signaling */
+#define Bt8370_RSYNC_FRM 0x0D8 /* Signaling Reinsertion Frame Offset */
+#define Bt8370_SSTAT 0x0D9 /* Slip Buffer Status */
+#define SSTAT_TSDIR 0x80 /* Transmit Slip Direction */
+#define SSTAT_TFSLIP 0x40 /* Controlled Slip Event */
+#define SSTAT_TUSLIP 0x20 /* Uncontrolled Slip Event */
+#define SSTAT_RSDIR 0x08 /* Receive Slip Direction */
+#define SSTAT_RFSLIP 0x04 /* Controlled Slip Event */
+#define SSTAT_RUSLIP 0x02 /* Uncontrolled Slip Event */
+#define Bt8370_STACK 0x0DA /* Receive Signaling Stack */
+#define Bt8370_RPHASE 0x0DB /* RSLIP Phase Status */
+#define Bt8370_TPHASE 0x0DC /* TSLIP Phase Status */
+#define Bt8370_PERR 0x0DD /* RAM Parity Status */
+#define Bt8370_SBCn 0x0E0 /* -0FF *//* System Bus Per-Channel Control */
+#define SBCn_INSERT 0x40 /* Insert RX Signaling on RPCMO */
+#define SBCn_SIG_LP 0x20 /* Local Signaling Loopback */
+#define SBCn_RLOOP 0x10 /* Local Loopback */
+#define SBCn_RINDO 0x08 /* Activate RINDO time slot indicator */
+#define SBCn_TINDO 0x04 /* Activate TINDO time slot indicator */
+#define SBCn_TSIG_AB 0x02 /* AB Signaling */
+#define SBCn_ASSIGN 0x01 /* Enable System Bus Time Slot */
+/* Buffer Memory */
+#define Bt8370_TPCn 0x100 /* Transmit Per-Channel Control */
+#define TPCn_CLEAR 0x00 /* Clear Channel Mode */
+#define TPCn_EMFBIT 0x80 /* TB7ZS/EMFBIT */
+#define TPCn_TLOOP 0x40 /* Remote DS0 Channel Loopback */
+#define TPCn_TIDLE 0x20 /* Transmit Idle */
+#define TPCn_TLOCAL 0x10 /* Transmit Local Signaling */
+#define TPCn_TSIGA 0x08 /* ABCD signaling value */
+#define TPCn_TSIGB 0x04 /* ABCD signaling value */
+#define TPCn_TSIGC 0x02 /* ABCD signaling value */
+#define TPCn_TSIGD 0x01 /* ABCD signaling value */
+#define TPCn_TSIGO TPCn_TSIGA /* Transmit Signaling Output */
+#define TPCn_RSIGO TPCn_TSIGB /* Receive Signaling Output */
+#define Bt8370_TSIGn 0x120 /* Transmit Signaling Buffer */
+#define Bt8370_TSLIP_LOn 0x140 /* Transmit PCM Slip Buffer */
+#define Bt8370_TSLIP_HIn 0x160 /* Transmit PCM Slip Buffer */
+#define Bt8370_RPCn 0x180 /* Receive Per-Channel Control */
+#define RPCn_CLEAR 0x00 /* Clear Channel Mode */
+#define RPCn_RSIG_AB 0x80 /* AB Signaling */
+#define RPCn_RIDLE 0x40 /* Time Slot Idle */
+#define RPCn_SIG_STK 0x20 /* Receive Signal Stack */
+#define RPCn_RLOCAL 0x10 /* Enable Local Signaling Output */
+#define RPCn_RSIGA 0x08 /* Local Receive Signaling */
+#define RPCn_RSIGB 0x04 /* Local Receive Signaling */
+#define RPCn_RSIGC 0x02 /* Local Receive Signaling */
+#define RPCn_RSIGD 0x01 /* Local Receive Signaling */
+#define Bt8370_RSIGn 0x1A0 /* Receive Signaling Buffer */
+#define Bt8370_RSLIP_LOn 0x1C0 /* Receive PCM Slip Buffer */
+#define Bt8370_RSLIP_HIn 0x1E0 /* Receive PCM Slip Buffer */
diff --git a/sys/dev/pci/if_art.c b/sys/dev/pci/if_art.c
new file mode 100644
index 00000000000..a39d31a0148
--- /dev/null
+++ b/sys/dev/pci/if_art.c
@@ -0,0 +1,363 @@
+/* $OpenBSD: if_art.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: if_art.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_sppp.h>
+
+#include <dev/pci/musyccvar.h>
+#include <dev/pci/if_art.h>
+
+int art_match(struct device *, void *, void *);
+void art_softc_attach(struct device *, struct device *, void *);
+
+int art_ioctl(struct ifnet *, u_long, caddr_t);
+int art_ifm_change(struct ifnet *);
+void art_ifm_status(struct ifnet *, struct ifmediareq *);
+int art_ifm_options(struct ifnet *, struct channel_softc *, u_int);
+void art_onesec(void *);
+
+struct cfattach art_ca = {
+ sizeof(struct art_softc), art_match, art_softc_attach
+};
+
+struct cfdriver art_cd = {
+ NULL, "art", DV_DULL
+};
+
+int
+art_match(struct device *parent, void *match, void *aux)
+{
+ struct musycc_attach_args *ma = aux;
+
+ if (ma->ma_type == MUSYCC_FRAMER_BT8370)
+ return (1);
+ return (0);
+}
+
+/*
+ * used for the one second timer
+ */
+extern int hz;
+
+void
+art_softc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct art_softc *sc = (struct art_softc *)self;
+ struct musycc_softc *psc = (struct musycc_softc *)parent;
+ struct musycc_attach_args *ma = aux;
+
+ printf(" \"%s\"", ma->ma_product);
+
+ if (ebus_attach_device(&sc->art_ebus, psc, ma->ma_base,
+ ma->ma_size) != 0) {
+ printf(": could not map framer\n");
+ return;
+ }
+
+ /* set basic values */
+ sc->art_port = ma->ma_port;
+ sc->art_slot = ma->ma_slot;
+ sc->art_gnum = ma->ma_gnum;
+
+ sc->art_channel = musycc_channel_create(self->dv_xname, 1);
+ if (sc->art_channel == NULL) {
+ printf(": could not alloc channel descriptor\n");
+ return;
+ }
+
+ if (musycc_channel_attach(psc, sc->art_channel, self, sc->art_gnum) ==
+ -1) {
+ printf(": unable to attach to hdlc controller\n");
+ return;
+ }
+
+ ifmedia_init(&sc->art_ifm, 0, art_ifm_change, art_ifm_status);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, 0, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, 0, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, 0, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, 0, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, 0, 0), 0, NULL);
+
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_MASTER, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_MASTER, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_MASTER, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_MASTER, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_MASTER, 0),
+ 0, NULL);
+
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP, 0), 0,
+ NULL);
+
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
+ 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
+ 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP | IFM_TDM_MASTER,
+ 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP |
+ IFM_TDM_MASTER, 0), 0, NULL);
+ ifmedia_add(&sc->art_ifm,
+ IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP |
+ IFM_TDM_MASTER, 0), 0, NULL);
+
+ printf(": E1/T1 framer\n");
+
+ if (bt8370_reset(sc) != 0)
+ return;
+
+ /*
+ * Initialize timeout for statistics update.
+ */
+ timeout_set(&sc->art_onesec, art_onesec, sc);
+
+ ifmedia_set(&sc->art_ifm, IFM_TDM|IFM_TDM_E1_G704_CRC4);
+ sc->art_media = sc->art_ifm.ifm_media;
+
+ bt8370_set_frame_mode(sc, IFM_TDM_E1_G704_CRC4, 0);
+ musycc_attach_sppp(sc->art_channel, art_ioctl);
+
+ /*
+ * Schedule the timeout one second from now.
+ */
+ timeout_add(&sc->art_onesec, hz);
+}
+
+/* interface ioctl */
+int
+art_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct ifreq *ifr = (struct ifreq*) data;
+ struct channel_softc *cc = ifp->if_softc;
+ struct art_softc *ac = (struct art_softc *)cc->cc_parent;
+ u_int32_t tsmap;
+ int s, rv = 0;
+
+ s = splnet();
+ switch (command) {
+ case SIOCSIFADDR:
+ if ((rv = musycc_init_channel(cc, ac->art_slot)))
+ break;
+ rv = sppp_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFTIMESLOT:
+ if ((rv = suser(curproc, 0)) != 0)
+ break;
+ rv = copyin(ifr->ifr_data, &tsmap, sizeof(tsmap));
+ if (rv)
+ break;
+ cc->cc_tslots = tsmap;
+ rv = musycc_init_channel(cc, ac->art_slot);
+ break;
+ case SIOCGIFTIMESLOT:
+ rv = copyout(&cc->cc_tslots, ifr->ifr_data, sizeof(tsmap));
+ break;
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked up and not running, then start it.
+ * If it is marked down and running, stop it.
+ */
+ if (ifr->ifr_flags & IFF_UP && cc->cc_state != CHAN_RUNNING) {
+ if ((rv = musycc_init_channel(cc, ac->art_slot)))
+ break;
+ } else if ((ifr->ifr_flags & IFF_UP) == 0 &&
+ cc->cc_state == CHAN_RUNNING)
+ musycc_stop_channel(cc);
+ rv = sppp_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ ac = (struct art_softc *)
+ ((struct channel_softc *)ifp->if_softc)->cc_parent;
+ if (ac != NULL)
+ rv = ifmedia_ioctl(ifp, ifr, &ac->art_ifm, command);
+ else
+ rv = EINVAL;
+ break;
+ default:
+ rv = sppp_ioctl(ifp, command, data);
+ break;
+ }
+ splx(s);
+ return (rv);
+}
+
+int
+art_ifm_change(struct ifnet *ifp)
+{
+ struct channel_softc *cc = ifp->if_softc;
+ struct art_softc *ac = (struct art_softc *)cc->cc_parent;
+ struct ifmedia *ifm = &ac->art_ifm;
+ int rv;
+
+ ACCOOM_PRINTF(2, ("%s: art_ifm_change %08x\n", ifp->if_xname,
+ ifm->ifm_media));
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_TDM)
+ return (EINVAL);
+
+ /* OPTIONS (controller mode hdlc, ppp, eoe) */
+ if ((rv = art_ifm_options(ifp, cc, IFM_OPTIONS(ifm->ifm_media))) != 0)
+ return (rv);
+
+ /* SUBTYPE (framing mode T1/E1) + MODE (clocking master/slave) */
+ if (IFM_SUBTYPE(ifm->ifm_media) !=
+ IFM_SUBTYPE(ac->art_media) ||
+ IFM_MODE(ifm->ifm_media) != IFM_MODE(ac->art_media)) {
+ ACCOOM_PRINTF(0, ("%s: art_ifm_change type %d mode %x\n",
+ ifp->if_xname, IFM_SUBTYPE(ifm->ifm_media),
+ IFM_MODE(ifm->ifm_media)));
+ bt8370_set_frame_mode(ac, IFM_SUBTYPE(ifm->ifm_media),
+ IFM_MODE(ifm->ifm_media));
+ }
+ ac->art_media = ifm->ifm_media;
+
+ return (0);
+}
+
+void
+art_ifm_status(struct ifnet *ifp, struct ifmediareq *ifmreq)
+{
+ struct art_softc *ac;
+
+ ac = (struct art_softc *)
+ ((struct channel_softc *)ifp->if_softc)->cc_parent;
+ ifmreq->ifm_status = ac->art_status;
+ ifmreq->ifm_active = ac->art_media;
+ return;
+}
+
+int
+art_ifm_options(struct ifnet *ifp, struct channel_softc *cc, u_int options)
+{
+ struct art_softc *ac = (struct art_softc *)cc->cc_parent;
+ u_int flags = cc->cc_ppp.pp_flags;
+ int rv;
+
+ if (options == IFM_TDM_PPP) {
+ flags &= ~PP_CISCO;
+ flags |= PP_KEEPALIVE;
+ } else if (options == 0) {
+ flags |= PP_CISCO;
+ flags |= PP_KEEPALIVE;
+ } else {
+ ACCOOM_PRINTF(0, ("%s: Unsupported ifmedia options\n",
+ ifp->if_xname));
+ return (EINVAL);
+ }
+ if (flags != cc->cc_ppp.pp_flags) {
+ musycc_stop_channel(cc);
+ cc->cc_ppp.pp_flags = flags;
+ if ((rv = musycc_init_channel(cc, ac->art_slot)))
+ return (rv);
+ return (sppp_ioctl(ifp, SIOCSIFFLAGS, NULL));
+ }
+ return (0);
+}
+
+void
+art_onesec(void *arg)
+{
+ struct art_softc *ac = arg;
+ struct ifnet *ifp = ac->art_channel->cc_ifp;
+ int s, rv, link_state, baudrate, announce = 0;
+
+ ac->art_status = IFM_AVALID;
+ rv = bt8370_link_status(ac);
+ switch (rv) {
+ case 1:
+ link_state = LINK_STATE_UP;
+ /* set led green but ask sppp if red is needed */
+ ebus_set_led(ac->art_channel->cc_group->mg_hdlc->mc_ebus, 1);
+ ac->art_status |= IFM_ACTIVE;
+ break;
+ case 0:
+ link_state = LINK_STATE_DOWN;
+ /* set led green & red */
+ ebus_set_led(ac->art_channel->cc_group->mg_hdlc->mc_ebus, 3);
+ break;
+ default:
+ link_state = LINK_STATE_DOWN;
+ /* set led red */
+ ebus_set_led(ac->art_channel->cc_group->mg_hdlc->mc_ebus, 2);
+ break;
+ }
+
+ if (link_state != ifp->if_link_state) {
+ ifp->if_link_state = link_state;
+ announce = 1;
+ }
+
+ baudrate = ifmedia_baudrate(ac->art_media);
+
+ if (baudrate != ifp->if_baudrate) {
+ ifp->if_baudrate = baudrate;
+ announce = 1;
+ }
+
+ if (announce) {
+ s = splnet();
+ if_link_state_change(ifp);
+ splx(s);
+ }
+
+ /*
+ * Schedule another timeout one second from now.
+ */
+ timeout_add(&ac->art_onesec, hz);
+}
+
diff --git a/sys/dev/pci/if_art.h b/sys/dev/pci/if_art.h
new file mode 100644
index 00000000000..47069086fc7
--- /dev/null
+++ b/sys/dev/pci/if_art.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: if_art.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: if_art.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __IF_ART_H__
+#define __IF_ART_H__
+
+#define MUSYCC_FRAMER_BT8370 0x8370
+
+struct art_softc {
+ struct device art_dev; /* generic device structures */
+ struct ebus_dev art_ebus; /* ebus attachement */
+ struct ifmedia art_ifm; /* interface media descriptor */
+ struct timeout art_onesec; /* onesec timeout */
+ struct musycc_softc *art_parent; /* parent hdlc controller */
+ struct channel_softc *art_channel; /* channel config */
+
+ int art_status; /* if_media status */
+ u_int art_media; /* if_media media */
+ u_int8_t art_gnum; /* group number */
+ u_int8_t art_port; /* port number */
+ char art_slot; /* TDM slot */
+};
+
+int bt8370_reset(struct art_softc *);
+int bt8370_set_frame_mode(struct art_softc *, u_int, u_int);
+void bt8370_intr_enable(struct art_softc *, int);
+void bt8370_intr(struct art_softc *);
+int bt8370_link_status(struct art_softc *);
+
+enum art_sbi_type {
+ ART_SBI_MASTER,
+ ART_SBI_SLAVE,
+ ART_SBI_SINGLE_T1,
+ ART_SBI_SINGLE_E1
+};
+
+enum art_sbi_mode {
+ SBI_MODE_1536 = 1, /* 24TS */
+ SBI_MODE_1544, /* 24TS + F bit */
+ SBI_MODE_2048, /* 32TS */
+ SBI_MODE_4096_A, /* lower 32TS */
+ SBI_MODE_4096_B, /* upper 32TS */
+ SBI_MODE_8192_A, /* first 32TS */
+ SBI_MODE_8192_B, /* second 32TS */
+ SBI_MODE_8192_C, /* third 32TS */
+ SBI_MODE_8192_D /* last 32TS */
+};
+
+enum art_linecode {
+ ART_LIU_AMI, /* Alternate Mark Inversion */
+ ART_LIU_B8ZS, /* Bipolar 8-zero Substitution */
+ ART_LIU_HDB3 /* High Density Bipolar 3 */
+};
+
+enum art_loopback {
+ ART_NOLOOP, /* All Loopback disabled */
+ ART_RLOOP_PAYLOAD, /* Remote Payload Loopback */
+ ART_RLOOP_LINE, /* Remote Line Loopback */
+ ART_LLOOP_PAYLOAD, /* Local Payload Loopback */
+ ART_LLOOP_LINE /* Local Line Loopback */
+};
+
+#define ART_DL1_BOP 1
+#define ART_BOP_ESF 1
+
+#endif
diff --git a/sys/dev/pci/musycc.c b/sys/dev/pci/musycc.c
new file mode 100644
index 00000000000..3c31afb8f5b
--- /dev/null
+++ b/sys/dev/pci/musycc.c
@@ -0,0 +1,1941 @@
+/* $OpenBSD: musycc.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: musycc.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_sppp.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <dev/pci/musyccvar.h>
+#include <dev/pci/musyccreg.h>
+
+int musycc_alloc_groupdesc(struct musycc_softc *);
+int musycc_alloc_intqueue(struct musycc_softc *);
+int musycc_alloc_group(struct musycc_group *);
+void musycc_free_groupdesc(struct musycc_softc *);
+void musycc_free_intqueue(struct musycc_softc *);
+void musycc_free_dmadesc(struct musycc_group *);
+void musycc_free_group(struct musycc_group *);
+void musycc_set_group(struct musycc_group *, int, int, int);
+void musycc_set_port(struct musycc_group *, int);
+int musycc_set_tsmap(struct musycc_group *, int, u_int32_t [4]);
+int musycc_set_chandesc(struct musycc_group *, int, int, int);
+void musycc_activate_channel(struct musycc_group *, int);
+void musycc_state_engine(struct musycc_group *, int, enum musycc_event);
+
+struct dma_desc *musycc_dma_get(struct musycc_group *);
+void musycc_dma_free(struct musycc_group *, struct dma_desc *);
+int musycc_list_tx_init(struct musycc_group *, int, int);
+int musycc_list_rx_init(struct musycc_group *, int, int);
+void musycc_list_tx_free(struct musycc_group *, int);
+void musycc_list_rx_free(struct musycc_group *, int);
+void musycc_reinit_dma(struct musycc_group *, int);
+int musycc_newbuf(struct musycc_group *, struct dma_desc *, struct mbuf *);
+int musycc_encap(struct musycc_group *, struct mbuf *, int);
+
+void musycc_rxeom(struct musycc_group *, int, int);
+void musycc_txeom(struct musycc_group *, int, int);
+void musycc_kick(struct musycc_group *);
+void musycc_sreq(struct musycc_group *, int, u_int32_t, int,
+ enum musycc_event);
+
+#ifndef ACCOOM_DEBUG
+#define musycc_dump_group(n, x)
+#define musycc_dump_desc(n, x)
+#define musycc_dump_dma(n, x, y)
+#else
+int accoom_debug = 0;
+
+char *musycc_intr_print(u_int32_t);
+void musycc_dump_group(int, struct musycc_group *);
+void musycc_dump_desc(int, struct musycc_group *);
+void musycc_dump_dma(int, struct musycc_group *, int);
+#endif
+
+int
+musycc_attach_common(struct musycc_softc *sc, u_int32_t portmap, u_int32_t mode)
+{
+ struct musycc_group *mg;
+ int i, j;
+
+ /* soft reset device */
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_SERREQ(0),
+ MUSYCC_SREQ_SET(1));
+ bus_space_barrier(sc->mc_st, sc->mc_sh, MUSYCC_SERREQ(0),
+ sizeof(u_int32_t), BUS_SPACE_BARRIER_WRITE);
+ (void) bus_space_read_4(sc->mc_st, sc->mc_sh, MUSYCC_SERREQ(0));
+
+ if (musycc_alloc_groupdesc(sc) == -1) {
+ printf(": couldn't alloc group descriptors\n");
+ return (-1);
+ }
+
+ if (musycc_alloc_intqueue(sc) == -1) {
+ printf(": couldn't alloc interrupt queue\n");
+ musycc_free_groupdesc(sc);
+ return (-1);
+ }
+
+ /*
+ * global configuration: set EBUS to sane defaults:
+ * intel mode, elapse = 3, blapse = 3, alapse = 3
+ * XXX XXX disable INTB for now
+ */
+ sc->mc_global_conf = (portmap & MUSYCC_CONF_PORTMAP) |
+ MUSYCC_CONF_MPUSEL | MUSYCC_CONF_ECKEN |
+ MUSYCC_CONF_ELAPSE_SET(3) | MUSYCC_CONF_ALAPSE_SET(3) |
+ MUSYCC_CONF_BLAPSE_SET(3) | MUSYCC_CONF_INTB;
+
+ /* initialize group descriptors */
+ sc->mc_groups = (struct musycc_group *)malloc(sc->mc_ngroups *
+ sizeof(struct musycc_group), M_DEVBUF, M_NOWAIT);
+ if (sc->mc_groups == NULL) {
+ printf(": couldn't alloc group descriptors\n");
+ musycc_free_groupdesc(sc);
+ musycc_free_intqueue(sc);
+ return (-1);
+ }
+ bzero(sc->mc_groups, sc->mc_ngroups * sizeof(struct musycc_group));
+
+ for (i = 0; i < sc->mc_ngroups; i++) {
+ mg = &sc->mc_groups[i];
+ mg->mg_hdlc = sc;
+ mg->mg_gnum = i;
+ mg->mg_port = i >> (sc->mc_global_conf & 0x3);
+ mg->mg_dmat = sc->mc_dmat;
+
+ if (musycc_alloc_group(mg) == -1) {
+ printf(": couldn't alloc group structures\n");
+ for (j = 0; j < i; j++)
+ musycc_free_group(&sc->mc_groups[j]);
+ musycc_free_groupdesc(sc);
+ musycc_free_intqueue(sc);
+ return (-1);
+ }
+
+ mg->mg_group = (struct musycc_grpdesc *)
+ (sc->mc_groupkva + MUSYCC_GROUPBASE(i));
+ bzero(mg->mg_group, sizeof(struct musycc_grpdesc));
+ musycc_set_group(mg, MUSYCC_GRCFG_POLL16, MUSYCC_MAXFRM_MAX,
+ MUSYCC_MAXFRM_MAX);
+ musycc_set_port(mg, mode);
+
+ bus_dmamap_sync(sc->mc_dmat, sc->mc_cfgmap,
+ MUSYCC_GROUPBASE(i), sizeof(struct musycc_grpdesc),
+ BUS_DMASYNC_PREWRITE);
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_GROUPBASE(i),
+ sc->mc_cfgmap->dm_segs[0].ds_addr + MUSYCC_GROUPBASE(i));
+ }
+
+ /* Dual Address Cycle Base Pointer */
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_DACB_PTR, 0);
+ /* Global Configuration Descriptor */
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_GLOBALCONF,
+ sc->mc_global_conf);
+ /* Interrupt Queue Descriptor */
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_INTQPTR,
+ sc->mc_intrqptr);
+ /*
+ * Interrupt Queue Length.
+ * NOTE: a value of 1 indicates a queue length of 2 descriptors!
+ */
+ bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_INTQLEN,
+ MUSYCC_INTLEN - 1);
+
+ return (0);
+}
+
+int
+musycc_alloc_groupdesc(struct musycc_softc *sc)
+{
+ /*
+ * Allocate per group/port shared memory.
+ * One big cunck of nports * 2048 bytes is allocated. This is
+ * done to ensure that all group structures are 2048 bytes aligned.
+ */
+ if (bus_dmamem_alloc(sc->mc_dmat, sc->mc_ngroups * 2048,
+ 2048, 0, sc->mc_cfgseg, 1, &sc->mc_cfgnseg, BUS_DMA_NOWAIT)) {
+ return (-1);
+ }
+ if (bus_dmamem_map(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg,
+ sc->mc_ngroups * 2048, &sc->mc_groupkva, BUS_DMA_NOWAIT)) {
+ bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
+ return (-1);
+ }
+ /* create and load bus dma segment, one for all ports */
+ if (bus_dmamap_create(sc->mc_dmat, sc->mc_ngroups * 2048,
+ 1, sc->mc_ngroups * 2048, 0, BUS_DMA_NOWAIT, &sc->mc_cfgmap)) {
+ bus_dmamem_unmap(sc->mc_dmat, sc->mc_groupkva,
+ sc->mc_ngroups * 2048);
+ bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
+ return (-1);
+ }
+ if (bus_dmamap_load(sc->mc_dmat, sc->mc_cfgmap, sc->mc_groupkva,
+ sc->mc_ngroups * 2048, NULL, BUS_DMA_NOWAIT)) {
+ musycc_free_groupdesc(sc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+musycc_alloc_intqueue(struct musycc_softc *sc)
+{
+ /*
+ * allocate interrupt queue, use one page for the queue
+ */
+ if (bus_dmamem_alloc(sc->mc_dmat, sizeof(struct musycc_intdesc), 4, 0,
+ sc->mc_intrseg, 1, &sc->mc_intrnseg, BUS_DMA_NOWAIT)) {
+ return (-1);
+ }
+ if (bus_dmamem_map(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg,
+ sizeof(struct musycc_intdesc), (caddr_t *)&sc->mc_intrd,
+ BUS_DMA_NOWAIT)) {
+ bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
+ return (-1);
+ }
+
+ /* create and load bus dma segment */
+ if (bus_dmamap_create(sc->mc_dmat, sizeof(struct musycc_intdesc),
+ 1, sizeof(struct musycc_intdesc), 0, BUS_DMA_NOWAIT,
+ &sc->mc_intrmap)) {
+ bus_dmamem_unmap(sc->mc_dmat, (caddr_t)sc->mc_intrd,
+ sizeof(struct musycc_intdesc));
+ bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
+ return (-1);
+ }
+ if (bus_dmamap_load(sc->mc_dmat, sc->mc_intrmap, sc->mc_intrd,
+ sizeof(struct musycc_intdesc), NULL, BUS_DMA_NOWAIT)) {
+ musycc_free_intqueue(sc);
+ return (-1);
+ }
+
+ /* initialize the interrupt queue pointer */
+ sc->mc_intrqptr = sc->mc_intrmap->dm_segs[0].ds_addr +
+ offsetof(struct musycc_intdesc, md_intrq[0]);
+
+ return (0);
+}
+
+int
+musycc_alloc_group(struct musycc_group *mg)
+{
+ struct dma_desc *dd;
+ int j;
+
+ /* Allocate per group dma memory */
+ if (bus_dmamem_alloc(mg->mg_dmat, MUSYCC_DMA_MAPSIZE,
+ PAGE_SIZE, 0, mg->mg_listseg, 1, &mg->mg_listnseg,
+ BUS_DMA_NOWAIT))
+ return (-1);
+ if (bus_dmamem_map(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg,
+ MUSYCC_DMA_MAPSIZE, &mg->mg_listkva, BUS_DMA_NOWAIT)) {
+ bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
+ return (-1);
+ }
+
+ /* create and load bus dma segment */
+ if (bus_dmamap_create(mg->mg_dmat, MUSYCC_DMA_MAPSIZE, 1,
+ MUSYCC_DMA_MAPSIZE, 0, BUS_DMA_NOWAIT, &mg->mg_listmap)) {
+ bus_dmamem_unmap(mg->mg_dmat, mg->mg_listkva,
+ MUSYCC_DMA_MAPSIZE);
+ bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
+ return (-1);
+ }
+ if (bus_dmamap_load(mg->mg_dmat, mg->mg_listmap, mg->mg_listkva,
+ MUSYCC_DMA_MAPSIZE, NULL, BUS_DMA_NOWAIT)) {
+ musycc_free_dmadesc(mg);
+ return (-1);
+ }
+
+ /*
+ * Create spare maps for musycc_start and musycc_newbuf.
+ * Limit the dma queue to MUSYCC_DMA_MAX entries even though there
+ * is no actual hard limit from the chip.
+ */
+ if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_MAX, MCLBYTES,
+ 0, BUS_DMA_NOWAIT, &mg->mg_tx_sparemap) != 0) {
+ musycc_free_dmadesc(mg);
+ return (-1);
+ }
+ if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_MAX, MCLBYTES,
+ 0, BUS_DMA_NOWAIT, &mg->mg_rx_sparemap) != 0) {
+ bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
+ musycc_free_dmadesc(mg);
+ return (-1);
+ }
+
+ mg->mg_dma_pool = (struct dma_desc *)mg->mg_listkva;
+ bzero(mg->mg_dma_pool,
+ MUSYCC_DMA_CNT * sizeof(struct dma_desc));
+
+ /* add all descriptors to the freelist */
+ for (j = 0; j < MUSYCC_DMA_CNT; j++) {
+ dd = &mg->mg_dma_pool[j];
+ /* initalize, same as for spare maps */
+ if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_MAX,
+ MCLBYTES, 0, BUS_DMA_NOWAIT, &dd->map)) {
+ musycc_free_group(mg);
+ return (-1);
+ }
+ /* link */
+ dd->nextdesc = mg->mg_freelist;
+ mg->mg_freelist = dd;
+ mg->mg_freecnt++;
+ }
+
+ return (0);
+}
+
+void
+musycc_free_groupdesc(struct musycc_softc *sc)
+{
+ bus_dmamap_destroy(sc->mc_dmat, sc->mc_cfgmap);
+ bus_dmamem_unmap(sc->mc_dmat, sc->mc_groupkva,
+ sc->mc_ngroups * 2048);
+ bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
+}
+
+void
+musycc_free_intqueue(struct musycc_softc *sc)
+{
+ bus_dmamap_destroy(sc->mc_dmat, sc->mc_intrmap);
+ bus_dmamem_unmap(sc->mc_dmat, (caddr_t)sc->mc_intrd,
+ sizeof(struct musycc_intdesc));
+ bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
+}
+
+void
+musycc_free_dmadesc(struct musycc_group *mg)
+{
+ bus_dmamap_destroy(mg->mg_dmat, mg->mg_listmap);
+ bus_dmamem_unmap(mg->mg_dmat, mg->mg_listkva,
+ MUSYCC_DMA_MAPSIZE);
+ bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
+}
+
+void
+musycc_free_group(struct musycc_group *mg)
+{
+ bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
+ bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
+ /* XXX dma descriptors ? */
+ musycc_free_dmadesc(mg);
+ mg->mg_dma_pool = NULL;
+ mg->mg_freelist = NULL;
+ mg->mg_freecnt = 0;
+}
+
+void
+musycc_set_group(struct musycc_group *mg, int poll, int maxa, int maxb)
+{
+ /* set global conf and interrupt descriptor */
+ mg->mg_group->global_conf = htole32(mg->mg_hdlc->mc_global_conf);
+ /*
+ * Interrupt Queue and Length.
+ * NOTE: a value of 1 indicates the queue length of 2 descriptors!
+ */
+ mg->mg_group->int_queuep = htole32(mg->mg_hdlc->mc_intrqptr);
+ mg->mg_group->int_queuelen = htole32(MUSYCC_INTLEN - 1);
+
+ /* group config */
+ mg->mg_group->group_conf = htole32(MUSYCC_GRCFG_RXENBL |
+ MUSYCC_GRCFG_TXENBL | MUSYCC_GRCFG_SUBDSBL | MUSYCC_GRCFG_MSKCOFA |
+ MUSYCC_GRCFG_MSKOOF | MUSYCC_GRCFG_MCENBL |
+ (poll & MUSYCC_GRCFG_POLL64));
+
+ /* memory protection, not supported by device */
+
+ /* message length config, preinit with useful data */
+ /* this is currently not used and the max is limited to 4094 bytes */
+ mg->mg_group->msglen_conf = htole32(maxa);
+ mg->mg_group->msglen_conf |= htole32(maxb << MUSYCC_MAXFRM2_SHIFT);
+
+}
+
+void
+musycc_set_port(struct musycc_group *mg, int mode)
+{
+ /*
+ * All signals trigger on falling edge only exception is TSYNC
+ * which triggers on rising edge. For the framer TSYNC is set to
+ * falling edge too but Musycc needs rising edge or everything gets
+ * off by one. Don't three-state TX (not needed).
+ */
+ mg->mg_group->port_conf = htole32(MUSYCC_PORT_TSYNC_EDGE |
+ MUSYCC_PORT_TRITX | (mode & MUSYCC_PORT_MODEMASK));
+}
+
+/*
+ * Channel specifc calls
+ */
+int
+musycc_set_tsmap(struct musycc_group *mg, int chan, u_int32_t tslots[4])
+{
+ int i, nslots = 0;
+
+ /* setup timeslot map but first make sure no timeslot is already used */
+ /* note: 56kbps mode for T1-SF needs to be set in here */
+ for (i = 0; i < sizeof(tslots) * 8; i++)
+ if ((1 << (i & 31)) & tslots[i >> 5])
+ if (mg->mg_group->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED ||
+ mg->mg_group->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ return (-1);
+
+ for (i = 0; i < sizeof(tslots) * 8; i++)
+ if ((1 << (i & 31)) & tslots[i >> 5]) {
+ nslots++;
+ mg->mg_group->tx_tsmap[i] =
+ MUSYCC_TSLOT_CHAN(chan) | MUSYCC_TSLOT_ENABLED;
+ mg->mg_group->rx_tsmap[i] =
+ MUSYCC_TSLOT_CHAN(chan) | MUSYCC_TSLOT_ENABLED;
+ }
+
+ return (nslots);
+}
+
+int
+musycc_set_chandesc(struct musycc_group *mg, int chan, int nslots, int proto)
+{
+ u_int64_t mask = ULLONG_MAX;
+ int idx, n;
+
+ ACCOOM_PRINTF(1, ("%s: musycc_set_chandesc nslots %d\n",
+ mg->mg_channels[chan]->cc_ifp->if_xname, nslots));
+
+ if (nslots == 0 || nslots > 32)
+ return (EINVAL);
+
+ n = 64 - 2 * nslots;
+ mask >>= n;
+
+ for (idx = 0; idx <= n; idx += 2)
+ if (!(mg->mg_fifomask & mask << idx))
+ break;
+
+ if (idx > n)
+ return (EBUSY);
+
+ mg->mg_fifomask |= mask << idx;
+
+ /* setup channel descriptor */
+ mg->mg_group->tx_cconf[chan] = htole32(MUSYCC_CHAN_BUFIDX_SET(idx) |
+ MUSYCC_CHAN_BUFLEN_SET(nslots * 2 - 1) |
+ MUSYCC_CHAN_PROTO_SET(proto));
+ mg->mg_group->rx_cconf[chan] = htole32(MUSYCC_CHAN_BUFIDX_SET(idx) |
+ MUSYCC_CHAN_BUFLEN_SET(nslots * 2 - 1) |
+ MUSYCC_CHAN_MSKIDLE | MUSYCC_CHAN_MSKSUERR | MUSYCC_CHAN_MSKSINC |
+ MUSYCC_CHAN_MSKSDEC | MUSYCC_CHAN_MSKSFILT |
+ MUSYCC_CHAN_PROTO_SET(proto));
+
+ return (0);
+}
+
+int
+musycc_init_channel(struct channel_softc *cc, char slot)
+{
+ struct musycc_group *mg;
+ struct ifnet *ifp = cc->cc_ifp;
+ u_int32_t tslots[4];
+ int chan, nslots, rv, s;
+
+ if (cc->cc_state == CHAN_FLOAT)
+ return (ENOTTY);
+ mg = cc->cc_group;
+
+ ACCOOM_PRINTF(2, ("%s: musycc_init_channel [state %d] slot %c\n",
+ cc->cc_ifp->if_xname, cc->cc_state, slot));
+ if (cc->cc_state != CHAN_IDLE) {
+ musycc_sreq(mg, cc->cc_channel, MUSYCC_SREQ_SET(9),
+ MUSYCC_SREQ_BOTH, EV_STOP);
+ tsleep(cc, PZERO | PCATCH, "musycc", hz);
+ if (cc->cc_state != CHAN_IDLE) {
+ ACCOOM_PRINTF(0, ("%s: failed to reset channel\n",
+ cc->cc_ifp->if_xname));
+ return (EIO);
+ }
+ }
+
+ if (mg->mg_loaded == 0) {
+ /* needs only be done once per group */
+ musycc_sreq(mg, 0, MUSYCC_SREQ_SET(5), MUSYCC_SREQ_BOTH,
+ EV_NULL);
+ mg->mg_loaded = 1;
+ }
+
+ bzero(tslots, sizeof(tslots));
+ switch (slot) {
+ case 'A':
+ tslots[0] = cc->cc_tslots;
+ break;
+ case 'B':
+ tslots[1] = cc->cc_tslots;
+ break;
+ case 'C':
+ tslots[2] = cc->cc_tslots;
+ break;
+ case 'D':
+ tslots[3] = cc->cc_tslots;
+ break;
+ default:
+ /* impossible */
+ log(LOG_ERR, "%s: accessing unsupported slot %c",
+ cc->cc_ifp->if_xname, slot);
+ cc->cc_state = CHAN_IDLE; /* force idle state */
+ musycc_free_channel(mg, chan);
+ return (EINVAL);
+ }
+
+ s = splnet();
+ /* setup timeslot map */
+ chan = cc->cc_channel;
+ nslots = musycc_set_tsmap(mg, chan, tslots);
+ if (nslots == -1) {
+ rv = EBUSY;
+ goto fail;
+ }
+
+ if ((rv = musycc_set_chandesc(mg, chan, nslots, MUSYCC_PROTO_HDLC16)))
+ goto fail;
+
+ /* setup tx DMA chain */
+ musycc_list_tx_init(mg, chan, nslots);
+ /* setup rx DMA chain */
+ if ((rv = musycc_list_rx_init(mg, chan, MUSYCC_DMA_MIN + nslots))) {
+ ACCOOM_PRINTF(0, ("%s: initialization failed: "
+ "no memory for rx buffers\n", cc->cc_ifp->if_xname));
+ goto fail;
+ }
+
+ /* IFF_RUNNING set by sppp_ioctl() */
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ cc->cc_state = CHAN_TRANSIENT;
+ splx(s);
+
+ musycc_activate_channel(mg, chan);
+ tsleep(cc, PZERO | PCATCH, "musycc", hz);
+
+ /*
+ * XXX we could actually check if the activation of the channels was
+ * successful but what type of error should we return?
+ */
+ return (0);
+
+fail:
+ splx(s);
+ cc->cc_state = CHAN_IDLE; /* force idle state */
+ musycc_free_channel(mg, chan);
+ return (rv);
+}
+
+void
+musycc_activate_channel(struct musycc_group *mg, int chan)
+{
+ ACCOOM_PRINTF(2, ("%s: musycc_activate_channel\n",
+ mg->mg_channels[chan]->cc_ifp->if_xname));
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(26), MUSYCC_SREQ_BOTH,
+ EV_NULL);
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(24), MUSYCC_SREQ_BOTH,
+ EV_NULL);
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_BOTH,
+ EV_ACTIVATE);
+}
+
+void
+musycc_stop_channel(struct channel_softc *cc)
+{
+ struct musycc_group *mg;
+
+ if (cc->cc_state == CHAN_FLOAT) {
+ /* impossible */
+ log(LOG_ERR, "%s: unexpected state in musycc_stop_channel",
+ cc->cc_ifp->if_xname);
+ cc->cc_state = CHAN_IDLE; /* reset */
+ musycc_free_channel(mg, cc->cc_channel);
+ return;
+ }
+
+ mg = cc->cc_group;
+ ACCOOM_PRINTF(2, ("%s: musycc_stop_channel\n", cc->cc_ifp->if_xname));
+ musycc_sreq(mg, cc->cc_channel, MUSYCC_SREQ_SET(9), MUSYCC_SREQ_BOTH,
+ EV_STOP);
+ tsleep(cc, PZERO | PCATCH, "musycc", hz);
+}
+
+void
+musycc_free_channel(struct musycc_group *mg, int chan)
+{
+ u_int64_t mask = ULLONG_MAX;
+ int i, idx, s, slots;
+
+ ACCOOM_PRINTF(2, ("%s: musycc_free_channel\n",
+ mg->mg_channels[chan]->cc_ifp->if_xname));
+
+ s = splnet();
+ /* Clear the timeout timer. */
+ mg->mg_channels[chan]->cc_ifp->if_timer = 0;
+
+ /* clear timeslot map */
+ for (i = 0; i < 128; i++) {
+ if (mg->mg_group->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ if ((mg->mg_group->tx_tsmap[i] & MUSYCC_TSLOT_MASK) ==
+ chan)
+ mg->mg_group->tx_tsmap[i] = 0;
+ if (mg->mg_group->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ if ((mg->mg_group->rx_tsmap[i] & MUSYCC_TSLOT_MASK) ==
+ chan)
+ mg->mg_group->rx_tsmap[i] = 0;
+ }
+
+ /* clear channel descriptor, especially free FIFO space */
+ idx = MUSYCC_CHAN_BUFIDX_GET(letoh32(mg->mg_group->tx_cconf[chan]));
+ slots = MUSYCC_CHAN_BUFLEN_GET(letoh32(mg->mg_group->tx_cconf[chan]));
+ slots = (slots + 1) / 2;
+ mask >>= 64 - 2 * slots;
+ mask <<= idx;
+ mg->mg_fifomask &= ~mask;
+ mg->mg_group->tx_cconf[chan] = 0;
+ mg->mg_group->rx_cconf[chan] = 0;
+
+ /* free dma rings */
+ musycc_list_rx_free(mg, chan);
+ musycc_list_tx_free(mg, chan);
+
+ splx(s);
+
+ /* update chip info with sreq */
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(24), MUSYCC_SREQ_BOTH,
+ EV_NULL);
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(26), MUSYCC_SREQ_BOTH,
+ EV_IDLE);
+}
+
+void
+musycc_state_engine(struct musycc_group *mg, int chan, enum musycc_event ev)
+{
+ enum musycc_state state;
+
+ if (mg->mg_channels[chan] == NULL)
+ return;
+
+ state = mg->mg_channels[chan]->cc_state;
+
+ ACCOOM_PRINTF(1, ("%s: musycc_state_engine state %d event %d\n",
+ mg->mg_channels[chan]->cc_ifp->if_xname, state, ev));
+
+ switch (ev) {
+ case EV_NULL:
+ /* no state change */
+ return;
+ case EV_ACTIVATE:
+ state = CHAN_RUNNING;
+ break;
+ case EV_STOP:
+ /* channel disabled now free dma rings et al. */
+ musycc_free_channel(mg, chan);
+ return;
+ case EV_IDLE:
+ state = CHAN_IDLE;
+ break;
+ case EV_WATCHDOG:
+ musycc_reinit_dma(mg, chan);
+ return;
+ }
+
+ mg->mg_channels[chan]->cc_state = state;
+ wakeup(mg->mg_channels[chan]);
+}
+
+/*
+ * DMA handling functions
+ */
+
+struct dma_desc *
+musycc_dma_get(struct musycc_group *mg)
+{
+ struct dma_desc *dd;
+
+ splassert(IPL_NET);
+
+ if (mg->mg_freecnt == 0)
+ return (NULL);
+ mg->mg_freecnt--;
+ dd = mg->mg_freelist;
+ mg->mg_freelist = dd->nextdesc;
+ /* clear some important data */
+ dd->nextdesc = NULL;
+ dd->mbuf = NULL;
+
+ return (dd);
+}
+
+void
+musycc_dma_free(struct musycc_group *mg, struct dma_desc *dd)
+{
+ splassert(IPL_NET);
+
+ dd->nextdesc = mg->mg_freelist;
+ mg->mg_freelist = dd;
+ mg->mg_freecnt++;
+}
+
+/*
+ * Initialize the transmit descriptors. Acctually they are left empty until
+ * a packet comes in.
+ */
+int
+musycc_list_tx_init(struct musycc_group *mg, int c, int nslots)
+{
+ struct musycc_dma_data *md;
+ struct dma_desc *dd;
+ bus_addr_t base;
+ int i;
+
+ ACCOOM_PRINTF(2, ("musycc_list_tx_init\n"));
+ md = &mg->mg_dma_d[c];
+ md->tx_pend = NULL;
+ md->tx_cur = NULL;
+ md->tx_cnt = 4 * nslots;
+ md->tx_pkts = 0;
+
+ base = mg->mg_listmap->dm_segs[0].ds_addr;
+ for (i = 0; i < md->tx_cnt; i++) {
+ dd = musycc_dma_get(mg);
+ if (dd == NULL) {
+ ACCOOM_PRINTF(0, ("musycc_list_tx_init: "
+ "out of dma_desc\n"));
+ musycc_list_tx_free(mg, c);
+ return (ENOBUFS);
+ }
+ dd->status = 0 /* MUSYCC_STATUS_NOPOLL */;
+ dd->data = 0;
+ if (md->tx_cur) {
+ md->tx_cur->nextdesc = dd;
+ md->tx_cur->next = htole32(base + (caddr_t)dd -
+ mg->mg_listkva);
+ md->tx_cur = dd;
+ } else
+ md->tx_pend = md->tx_cur = dd;
+ }
+
+ dd->nextdesc = md->tx_pend;
+ dd->next = htole32(base + (caddr_t)md->tx_pend - mg->mg_listkva);
+ md->tx_pend = dd;
+
+ mg->mg_group->tx_headp[c] = htole32(base + (caddr_t)dd -
+ mg->mg_listkva);
+
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap, 0, MUSYCC_DMA_MAPSIZE,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+int
+musycc_list_rx_init(struct musycc_group *mg, int c, int size)
+{
+ struct musycc_dma_data *md;
+ struct dma_desc *dd = NULL, *last;
+ bus_addr_t base;
+ int i;
+
+ ACCOOM_PRINTF(2, ("musycc_list_rx_init\n"));
+ md = &mg->mg_dma_d[c];
+ md->rx_cnt = size;
+
+ base = mg->mg_listmap->dm_segs[0].ds_addr;
+ for (i = 0; i < size; i++) {
+ dd = musycc_dma_get(mg);
+ if (dd == NULL) {
+ ACCOOM_PRINTF(0, ("musycc_list_rx_init: "
+ "out of dma_desc\n"));
+ musycc_list_rx_free(mg, c);
+ return (ENOBUFS);
+ }
+ if (musycc_newbuf(mg, dd, NULL) == ENOBUFS) {
+ ACCOOM_PRINTF(0, ("musycc_list_rx_init: "
+ "out of mbufs\n"));
+ musycc_list_rx_free(mg, c);
+ return (ENOBUFS);
+ }
+ if (md->rx_prod) {
+ md->rx_prod->nextdesc = dd;
+ md->rx_prod->next = htole32(base + (caddr_t)dd -
+ mg->mg_listkva);
+ md->rx_prod = dd;
+ } else
+ last = md->rx_prod = dd;
+ }
+
+ dd->nextdesc = last;
+ dd->next = htole32(base + (caddr_t)last - mg->mg_listkva);
+
+ mg->mg_group->rx_headp[c] = htole32(base + (caddr_t)dd -
+ mg->mg_listkva);
+
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap, 0, MUSYCC_DMA_MAPSIZE,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+void
+musycc_list_tx_free(struct musycc_group *mg, int c)
+{
+ struct musycc_dma_data *md;
+ struct dma_desc *dd, *tmp;
+
+ md = &mg->mg_dma_d[c];
+
+ ACCOOM_PRINTF(2, ("musycc_list_tx_free\n"));
+ dd = md->tx_pend;
+ do {
+ if (dd == NULL)
+ break;
+ if (dd->map->dm_nsegs != 0) {
+ bus_dmamap_t map = dd->map;
+
+ bus_dmamap_unload(mg->mg_dmat, map);
+ }
+ if (dd->mbuf != NULL) {
+ m_freem(dd->mbuf);
+ dd->mbuf = NULL;
+ }
+ tmp = dd;
+ dd = dd->nextdesc;
+ musycc_dma_free(mg, tmp);
+ } while (dd != md->tx_pend);
+ md->tx_pend = md->tx_cur = NULL;
+ md->tx_cnt = md->tx_use = md->tx_pkts = 0;
+}
+
+void
+musycc_list_rx_free(struct musycc_group *mg, int c)
+{
+ struct musycc_dma_data *md;
+ struct dma_desc *dd, *tmp;
+
+ md = &mg->mg_dma_d[c];
+
+ ACCOOM_PRINTF(2, ("musycc_list_rx_free\n"));
+ dd = md->rx_prod;
+ do {
+ if (dd == NULL)
+ break;
+ if (dd->map->dm_nsegs != 0) {
+ bus_dmamap_t map = dd->map;
+
+ bus_dmamap_unload(mg->mg_dmat, map);
+ }
+ if (dd->mbuf != NULL) {
+ m_freem(dd->mbuf);
+ dd->mbuf = NULL;
+ }
+ tmp = dd;
+ dd = dd->nextdesc;
+ musycc_dma_free(mg, tmp);
+ } while (dd != md->rx_prod);
+ md->rx_prod = NULL;
+ md->rx_cnt = 0;
+}
+
+/* only used by the watchdog timeout */
+void
+musycc_reinit_dma(struct musycc_group *mg, int c)
+{
+ int s, ntx, nrx;
+
+ s = splnet();
+ ntx = mg->mg_dma_d[c].tx_cnt / 4;
+ nrx = mg->mg_dma_d[c].rx_cnt;
+
+ musycc_list_tx_free(mg, c);
+ musycc_list_rx_free(mg, c);
+
+ /* setup tx & rx DMA chain */
+ if (musycc_list_tx_init(mg, c, ntx) ||
+ musycc_list_rx_init(mg, c, nrx)) {
+ log(LOG_ERR, "%s: Failed to malloc memory\n",
+ mg->mg_channels[c]->cc_ifp->if_xname);
+ musycc_free_channel(mg, c);
+ }
+ splx(s);
+
+ musycc_activate_channel(mg, c);
+}
+
+/*
+ * Initialize an RX descriptor and attach an mbuf cluster.
+ */
+int
+musycc_newbuf(struct musycc_group *mg, struct dma_desc *c, struct mbuf *m)
+{
+ struct mbuf *m_new = NULL;
+ bus_dmamap_t map;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return (ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return (ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ if (bus_dmamap_load(mg->mg_dmat, mg->mg_rx_sparemap,
+ mtod(m_new, caddr_t), m_new->m_pkthdr.len, NULL,
+ BUS_DMA_NOWAIT) != 0) {
+ ACCOOM_PRINTF(0, ("%s: rx load failed\n",
+ mg->mg_hdlc->mc_dev.dv_xname));
+ m_freem(m_new);
+ return (ENOBUFS);
+ }
+ map = c->map;
+ c->map = mg->mg_rx_sparemap;
+ mg->mg_rx_sparemap = map;
+
+ bus_dmamap_sync(mg->mg_dmat, c->map, 0, c->map->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+
+ c->mbuf = m_new;
+ c->data = htole32(c->map->dm_segs[0].ds_addr);
+ c->status = htole32(MUSYCC_STATUS_NOPOLL |
+ MUSYCC_STATUS_LEN(m_new->m_pkthdr.len));
+
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
+ ((caddr_t)c - mg->mg_listkva), sizeof(struct dma_desc),
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+int
+musycc_encap(struct musycc_group *mg, struct mbuf *m_head, int c)
+{
+ struct dma_desc *cur, *tmp;
+ bus_dmamap_t map;
+ bus_addr_t base;
+ u_int32_t status;
+ int i, needed;
+
+ map = mg->mg_tx_sparemap;
+ if (bus_dmamap_load_mbuf(mg->mg_dmat, map, m_head,
+ BUS_DMA_NOWAIT) != 0) {
+ ACCOOM_PRINTF(0, ("%s: musycc_encap: dmamap_load failed\n",
+ mg->mg_channels[c]->cc_ifp->if_xname));
+ return (ENOBUFS);
+ }
+
+ cur = mg->mg_dma_d[c].tx_cur;
+ base = mg->mg_listmap->dm_segs[0].ds_addr;
+
+ /*
+ * Start packing the mbufs in this chain into the
+ * fragment pointers. The ring size is limited to
+ * tx_cnt or if less than MUSYCC_DMA_MIN packets
+ * are queued additional temporary space is used.
+ */
+ if (map->dm_nsegs + mg->mg_dma_d[c].tx_use >= mg->mg_dma_d[c].tx_cnt) {
+ if (mg->mg_dma_d[c].tx_pkts >= MUSYCC_DMA_MIN) {
+ ACCOOM_PRINTF(2, ("%s: musycc_encap: "
+ "too many packets\n",
+ mg->mg_channels[c]->cc_ifp->if_xname));
+ return (ENOBUFS);
+ }
+ if (map->dm_nsegs > mg->mg_freecnt) {
+ ACCOOM_PRINTF(1, ("%s: musycc_encap: "
+ "not enough descriptors left\n",
+ mg->mg_channels[c]->cc_ifp->if_xname));
+ return (ENOBUFS);
+ }
+ /* resize ring */
+ needed = map->dm_nsegs + mg->mg_dma_d[c].tx_use -
+ mg->mg_dma_d[c].tx_cnt;
+ for (i = 0; i < needed; i++) {
+ tmp = musycc_dma_get(mg);
+ if (tmp == NULL)
+ /* should be impossible */
+ return (ENOBUFS);
+ tmp->status = 0 /* MUSYCC_STATUS_NOPOLL */;
+ tmp->data = 0;
+ tmp->next = cur->next;
+ tmp->nextdesc = cur->nextdesc;
+ cur->next = htole32(base + ((caddr_t)tmp -
+ mg->mg_listkva));
+ cur->nextdesc = tmp;
+ mg->mg_dma_d[c].tx_cnt++;
+ }
+ }
+
+ i = 0;
+ while (i < map->dm_nsegs) {
+ status = /* MUSYCC_STATUS_NOPOLL | */
+ MUSYCC_STATUS_LEN(map->dm_segs[i].ds_len);
+ if (cur != mg->mg_dma_d[c].tx_cur)
+ status |= MUSYCC_STATUS_OWNER;
+
+ cur->status = htole32(status);
+ cur->data = htole32(map->dm_segs[i].ds_addr);
+
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
+ ((caddr_t)cur - mg->mg_listkva), sizeof(struct dma_desc),
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ if (++i >= map->dm_nsegs)
+ break;
+ cur = cur->nextdesc;
+ }
+
+ bus_dmamap_sync(mg->mg_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ cur->mbuf = m_head;
+ mg->mg_tx_sparemap = cur->map;
+ cur->map = map;
+ cur->status |= htole32(MUSYCC_STATUS_EOM);
+ tmp = mg->mg_dma_d[c].tx_cur;
+ mg->mg_dma_d[c].tx_cur = cur->nextdesc;
+ mg->mg_dma_d[c].tx_use += i;
+ mg->mg_dma_d[c].tx_pkts++;
+
+ /*
+ * Last but not least, flag the buffer if the buffer is flagged to
+ * early, it may happen, that the buffer is already transmitted
+ * before we changed all relevant variables.
+ */
+ tmp->status |= htole32(MUSYCC_STATUS_OWNER);
+#if 0
+ /* check for transmited packets NO POLLING mode only */
+ /*
+ * Note: a bug in the HDLC chip seems to make it impossible to use
+ * no polling mode.
+ */
+ musycc_txeom(mg, c);
+ if (mg->mg_dma_d[c].tx_pend == tmp) {
+ /* and restart as needed */
+ printf("%s: tx needs kick\n",
+ mg->mg_channels[c]->cc_ifp->if_xname);
+ mg->mg_group->tx_headp[c] = htole32(base +
+ (caddr_t)mg->mg_dma_d[c].tx_pend - mg->mg_listkva);
+
+ musycc_sreq(mg, c, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_TX);
+ }
+#endif
+
+ return (0);
+}
+
+
+/*
+ * API towards the kernel
+ */
+
+/* start transmit of new network buffer */
+void
+musycc_start(struct ifnet *ifp)
+{
+ struct musycc_group *mg;
+ struct channel_softc *cc;
+ struct mbuf *m = NULL;
+
+ cc = ifp->if_softc;
+ mg = cc->cc_group;
+
+ if (cc->cc_state != CHAN_RUNNING)
+ return;
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ while (!sppp_isempty(ifp)) {
+ if ((m = sppp_pick(ifp)) == NULL)
+ /* Should never happened that packet pointer is NULL */
+ break;
+
+ if (musycc_encap(mg, m, cc->cc_channel)) {
+ ifp->if_flags |= IFF_OACTIVE;
+ ACCOOM_PRINTF(1, ("%s: tx out of dma bufs\n",
+ cc->cc_ifp->if_xname));
+ break;
+ }
+
+ /* now we are committed to transmit the packet */
+ sppp_dequeue(ifp);
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+ }
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ return;
+}
+
+
+/*
+ * Watchdog/transmission transmit timeout handler. Called when a
+ * transmission is started on the interface, but no interrupt is
+ * received before the timeout. This usually indicates that the
+ * card has wedged for some reason.
+ */
+void
+musycc_watchdog(struct ifnet *ifp)
+{
+ struct channel_softc *cc = ifp->if_softc;
+
+ log(LOG_ERR, "%s: device timeout\n", cc->cc_ifp->if_xname);
+ ifp->if_oerrors++;
+
+ musycc_sreq(cc->cc_group, cc->cc_channel, MUSYCC_SREQ_SET(9),
+ MUSYCC_SREQ_BOTH, EV_WATCHDOG);
+}
+
+
+/*
+ * Interrupt specific functions
+ */
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+void
+musycc_rxeom(struct musycc_group *mg, int channel, int forcekick)
+{
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct dma_desc *cur_rx, *start_rx;
+ int total_len = 0, consumed = 0;
+ u_int32_t rxstat;
+
+ ifp = mg->mg_channels[channel]->cc_ifp;
+
+ start_rx = cur_rx = mg->mg_dma_d[channel].rx_prod;
+ do {
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
+ ((caddr_t)cur_rx - mg->mg_listkva),
+ sizeof(struct dma_desc),
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ rxstat = letoh32(cur_rx->status);
+ if (!(rxstat & MUSYCC_STATUS_OWNER))
+ break;
+
+ m = cur_rx->mbuf;
+ cur_rx->mbuf = NULL;
+ total_len = MUSYCC_STATUS_LEN(rxstat);
+
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & MUSYCC_STATUS_ERROR) {
+ ifp->if_ierrors++;
+ ACCOOM_PRINTF(0, ("%s: rx error %08x\n",
+ mg->mg_channels[channel]->cc_ifp->if_xname,
+ rxstat));
+ musycc_newbuf(mg, cur_rx, m);
+ cur_rx = cur_rx->nextdesc;
+ consumed++;
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+ bus_dmamap_sync(mg->mg_dmat, cur_rx->map, 0,
+ cur_rx->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ if (musycc_newbuf(mg, cur_rx, NULL) != 0) {
+ cur_rx = cur_rx->nextdesc;
+ consumed++;
+ continue;
+ }
+
+ cur_rx = cur_rx->nextdesc;
+ consumed++;
+
+ /* TODO support mbuf chains */
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+ ifp->if_ipackets++;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /* pass it on. */
+ sppp_input(ifp, m);
+ } while (cur_rx != start_rx);
+
+ mg->mg_dma_d[channel].rx_prod = cur_rx;
+
+ if ((cur_rx == start_rx && consumed) || forcekick) {
+ /* send SREQ to signal the new buffers */
+ ACCOOM_PRINTF(1, ("%s: rx kick, consumed %d pkts\n",
+ mg->mg_channels[channel]->cc_ifp->if_xname, consumed));
+ mg->mg_group->rx_headp[channel] = htole32(
+ mg->mg_listmap->dm_segs[0].ds_addr +
+ (caddr_t)cur_rx - mg->mg_listkva);
+ musycc_sreq(mg, channel, MUSYCC_SREQ_SET(8),
+ MUSYCC_SREQ_RX, EV_NULL);
+ }
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+void
+musycc_txeom(struct musycc_group *mg, int channel, int forcekick)
+{
+ struct dma_desc *dd;
+ struct ifnet *ifp;
+
+ ifp = mg->mg_channels[channel]->cc_ifp;
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ /* TODO if tx_cnt > limit we should drop some descriptors */
+ for (dd = mg->mg_dma_d[channel].tx_pend;
+ dd != mg->mg_dma_d[channel].tx_cur;
+ dd = dd->nextdesc) {
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
+ ((caddr_t)dd - mg->mg_listkva), sizeof(struct dma_desc),
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ if (letoh32(dd->status) & MUSYCC_STATUS_OWNER)
+ /* musycc still owns this descriptor */
+ break;
+
+ mg->mg_dma_d[channel].tx_use--;
+
+ dd->status = 0; /* reinit dma status flags */
+ /* dd->status |= MUSYCC_STATUS_NOPOLL; *//* disable polling */
+
+ if (dd->map->dm_nsegs != 0) {
+ bus_dmamap_sync(mg->mg_dmat, dd->map, 0,
+ dd->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(mg->mg_dmat, dd->map);
+ }
+ if (dd->mbuf != NULL) {
+ m_freem(dd->mbuf);
+ dd->mbuf = NULL;
+ mg->mg_dma_d[channel].tx_pkts--;
+ ifp->if_opackets++;
+ }
+ }
+
+ if (mg->mg_dma_d[channel].tx_pend != dd)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ mg->mg_dma_d[channel].tx_pend = dd;
+
+ if (forcekick) {
+ /* restart */
+ ACCOOM_PRINTF(1, ("%s: tx kick forced\n",
+ mg->mg_channels[channel]->cc_ifp->if_xname));
+ mg->mg_group->tx_headp[channel] =
+ htole32(mg->mg_listmap->dm_segs[0].ds_addr +
+ (caddr_t)mg->mg_dma_d[channel].tx_pend - mg->mg_listkva);
+
+ musycc_sreq(mg, channel, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_TX,
+ EV_NULL);
+ }
+}
+
+int
+musycc_intr(void *arg)
+{
+ struct musycc_softc *mc = arg;
+ struct musycc_group *mg;
+ struct ifnet *ifp;
+ u_int32_t intstatus, id;
+ int i, n, chan;
+
+ intstatus = bus_space_read_4(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS);
+ if (intstatus & MUSYCC_INTCNT_MASK) {
+ bus_dmamap_sync(mc->mc_dmat, mc->mc_intrmap,
+ offsetof(struct musycc_intdesc, md_intrq[0]),
+ MUSYCC_INTLEN * sizeof(u_int32_t), BUS_DMASYNC_POSTREAD);
+
+ ACCOOM_PRINTF(4, ("%s: interrupt status %08x\n",
+ mc->mc_dev.dv_xname, intstatus));
+
+ n = MUSYCC_NEXTINT_GET(intstatus);
+ for (i = 0; i < (intstatus & MUSYCC_INTCNT_MASK); i++) {
+ id = mc->mc_intrd->md_intrq[(n + i) % MUSYCC_INTLEN];
+ chan = MUSYCC_INTD_CHAN(id);
+ mg = &mc->mc_groups[MUSYCC_INTD_GRP(id)];
+
+ ACCOOM_PRINTF(4, ("%s: interrupt %s\n",
+ mc->mc_dev.dv_xname, musycc_intr_print(id)));
+
+ switch (MUSYCC_INTD_EVENT(id)) {
+ case MUSYCC_INTEV_NONE:
+ break;
+ case MUSYCC_INTEV_SACK:
+ musycc_state_engine(mg, chan,
+ mg->mg_sreq[mg->mg_sreqpend].event);
+ mg->mg_sreqpend =
+ (mg->mg_sreqpend + 1) & MUSYCC_SREQMASK;
+ if (mg->mg_sreqpend != mg->mg_sreqprod)
+ musycc_kick(mg);
+ break;
+ case MUSYCC_INTEV_EOM:
+ case MUSYCC_INTEV_EOB:
+ if (id & MUSYCC_INTD_DIR)
+ musycc_txeom(mg, chan, 0);
+ else
+ musycc_rxeom(mg, chan, 0);
+ break;
+ default:
+ ACCOOM_PRINTF(0, ("%s: unhandled event: %s\n",
+ mc->mc_dev.dv_xname,
+ musycc_intr_print(id)));
+ break;
+ }
+ switch (MUSYCC_INTD_ERROR(id)) {
+ case MUSYCC_INTERR_NONE:
+ break;
+ case MUSYCC_INTERR_COFA:
+ if ((id & MUSYCC_INTD_DIR) == 0)
+ /* ignore COFA for RX side */
+ break;
+ if (mg->mg_channels[chan]->cc_state !=
+ CHAN_RUNNING) {
+#if 0
+ if (mg->mg_sreqpend != mg->mg_sreqprod) {
+#endif
+ ACCOOM_PRINTF(1, ("%s: COFA ignored\n",
+ mg->mg_channels[chan]->
+ cc_ifp->if_xname));
+ break;
+ }
+ ACCOOM_PRINTF(0, ("%s: error: %s\n",
+ mc->mc_dev.dv_xname,
+ musycc_intr_print(id)));
+#if 0
+ /* digest already transmitted packets */
+ musycc_txeom(mg, chan);
+
+ musycc_dump_dma(mg);
+ /* adjust head pointer */
+ musycc_dump_dma(mg);
+ mg->mg_group->tx_headp[chan] =
+ htole32(mg->mg_listmap->dm_segs[0].ds_addr +
+ (caddr_t)mg->mg_dma_d[chan].tx_pend -
+ mg->mg_listkva);
+ musycc_dump_dma(mg);
+
+ musycc_sreq(mg, chan, MUSYCC_SREQ_SET(8),
+ MUSYCC_SREQ_TX, CHAN_RUNNING);
+#endif
+ break;
+ case MUSYCC_INTERR_BUFF:
+ /*
+ * log event as this should not happen,
+ * indicates PCI bus congestion
+ */
+ log(LOG_ERR, "%s: internal FIFO %s\n",
+ mg->mg_channels[chan]->cc_ifp->if_xname,
+ id & MUSYCC_INTD_DIR ? "underflow" :
+ "overflow");
+
+ /* digest queue and restarting dma engine */
+ ifp = mg->mg_channels[chan]->cc_ifp;
+ if (id & MUSYCC_INTD_DIR) {
+ ifp->if_oerrors++;
+ musycc_txeom(mg, chan, 1);
+ } else {
+ ifp->if_ierrors++;
+ musycc_rxeom(mg, chan, 1);
+ }
+ break;
+ case MUSYCC_INTERR_ONR:
+ ACCOOM_PRINTF(0, ("%s: error: %s\n",
+ mc->mc_dev.dv_xname,
+ musycc_intr_print(id)));
+
+ /* digest queue and restarting dma engine */
+ ifp = mg->mg_channels[chan]->cc_ifp;
+ if (id & MUSYCC_INTD_DIR) {
+ ifp->if_oerrors++;
+ musycc_txeom(mg, chan, 1);
+ } else {
+ ifp->if_ierrors++;
+ musycc_rxeom(mg, chan, 1);
+ }
+ break;
+ default:
+ ACCOOM_PRINTF(0, ("%s: unhandled error: %s\n",
+ mc->mc_dev.dv_xname,
+ musycc_intr_print(id)));
+ break;
+ }
+ }
+ bus_space_write_4(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS,
+ MUSYCC_NEXTINT_SET((n + i) % MUSYCC_INTLEN));
+ bus_space_barrier(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS,
+ sizeof(u_int32_t), BUS_SPACE_BARRIER_WRITE);
+ return (1);
+ } else
+ return (0);
+}
+
+void
+musycc_kick(struct musycc_group *mg)
+{
+
+ bus_dmamap_sync(mg->mg_dmat, mg->mg_hdlc->mc_cfgmap,
+ MUSYCC_GROUPBASE(mg->mg_gnum), sizeof(struct musycc_grpdesc),
+ BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
+
+ ACCOOM_PRINTF(4, ("musycc_kick: group %d sreq[%d] req %08x\n",
+ mg->mg_gnum, mg->mg_sreqpend, mg->mg_sreq[mg->mg_sreqpend]));
+
+ bus_space_write_4(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
+ MUSYCC_SERREQ(mg->mg_gnum), mg->mg_sreq[mg->mg_sreqpend].sreq);
+ bus_space_barrier(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
+ MUSYCC_SERREQ(mg->mg_gnum), sizeof(u_int32_t),
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+void
+musycc_sreq(struct musycc_group *mg, int channel, u_int32_t req, int dir,
+ enum musycc_event event)
+{
+#define MUSYCC_SREQINC(x, y) \
+ do { \
+ (x) = ((x) + 1) & MUSYCC_SREQMASK; \
+ if (x == y) \
+ panic("%s: sreq queue overflow", \
+ mg->mg_hdlc->mc_dev.dv_xname); \
+ } while (0)
+
+ int needskick;
+
+ needskick = (mg->mg_sreqpend == mg->mg_sreqprod);
+
+ ACCOOM_PRINTF(4, ("musycc_sreq: g# %d c# %d req %x dir %x\n",
+ mg->mg_gnum, channel, req, dir));
+
+ if (dir & MUSYCC_SREQ_RX) {
+ req &= ~MUSYCC_SREQ_TXDIR & ~MUSYCC_SREQ_MASK;
+ req |= MUSYCC_SREQ_CHSET(channel);
+ mg->mg_sreq[mg->mg_sreqprod].sreq = req;
+ if (dir == MUSYCC_SREQ_RX)
+ mg->mg_sreq[mg->mg_sreqprod].event = event;
+ else
+ mg->mg_sreq[mg->mg_sreqprod].event = EV_NULL;
+ MUSYCC_SREQINC(mg->mg_sreqprod, mg->mg_sreqpend);
+ }
+ if (dir & MUSYCC_SREQ_TX) {
+ req &= ~MUSYCC_SREQ_MASK;
+ req |= MUSYCC_SREQ_TXDIR;
+ req |= MUSYCC_SREQ_CHSET(channel);
+ mg->mg_sreq[mg->mg_sreqprod].sreq = req;
+ mg->mg_sreq[mg->mg_sreqprod].event = event;
+ MUSYCC_SREQINC(mg->mg_sreqprod, mg->mg_sreqpend);
+ }
+
+ if (needskick)
+ musycc_kick(mg);
+
+#undef MUSYCC_SREQINC
+}
+
+
+
+
+/*
+ * Extension Bus API
+ */
+int
+ebus_intr(void *arg)
+{
+ struct ebus_softc *ec = arg;
+#if 0
+ struct framer_softc *fc;
+
+ SLIST_FOREACH(fc, &sc->sc_hdlc->sc_framers, list) {
+ f->sc_intr(f);
+ }
+#endif
+ printf("%s: interrupt\n", ec->ec_dev.dv_xname);
+ return (1);
+}
+
+int
+ebus_attach_device(struct ebus_dev *e, struct musycc_softc *mc,
+ bus_size_t offset, bus_size_t size)
+{
+ struct ebus_softc *ec = mc->mc_ebus;
+
+ e->base = offset << 2;
+ e->size = size;
+ e->st = ec->ec_st;
+ return (bus_space_subregion(ec->ec_st, ec->ec_sh, offset << 2,
+ size, &e->sh));
+}
+
+u_int8_t
+ebus_read(struct ebus_dev *e, bus_size_t offset)
+{
+ u_int8_t value;
+
+ value = bus_space_read_1(e->st, e->sh, offset << 2);
+ bus_space_barrier(e->st, e->sh, 0, e->size,
+ BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+ return (value);
+}
+
+void
+ebus_write(struct ebus_dev *e, bus_size_t offset, u_int8_t value)
+{
+ bus_space_write_1(e->st, e->sh, offset << 2, value);
+ bus_space_barrier(e->st, e->sh, 0, e->size,
+ BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+}
+
+void
+ebus_read_buf(struct ebus_dev *rom, bus_size_t offset, void *buf, size_t size)
+{
+ u_int8_t *b = buf;
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ b[i] = ebus_read(rom, offset + i);
+}
+
+void
+ebus_set_led(struct ebus_softc *esc, u_int8_t value)
+{
+ bus_space_write_1(esc->ec_st, esc->ec_sh, esc->ec_ledbase << 2, value);
+ bus_space_barrier(esc->ec_st, esc->ec_sh, esc->ec_ledbase << 2, 1,
+ BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+}
+
+/*
+ * Channel API
+ */
+
+void
+musycc_attach_sppp(struct channel_softc *cc,
+ int (*if_ioctl)(struct ifnet *, u_long, caddr_t))
+{
+ struct ifnet *ifp;
+
+ ifp = &cc->cc_ppp.pp_if;
+ cc->cc_ifp = ifp;
+
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ IFQ_SET_READY(&ifp->if_snd);
+ ifp->if_mtu = PP_MTU;
+ ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST /* | IFF_SIMPLEX */;
+ cc->cc_ppp.pp_flags |= PP_CISCO;
+ cc->cc_ppp.pp_flags |= PP_KEEPALIVE;
+ cc->cc_ppp.pp_framebytes = 3;
+
+ ifp->if_ioctl = if_ioctl;
+ ifp->if_start = musycc_start;
+ ifp->if_watchdog = musycc_watchdog;
+
+ if_attach(ifp);
+ if_alloc_sadl(ifp);
+ sppp_attach(ifp);
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_PPP, PPP_HEADER_LEN);
+#endif /* NBPFILTER > 0 */
+
+}
+
+struct channel_softc *
+musycc_channel_create(const char *name, u_int8_t locked)
+{
+ struct channel_softc *cc;
+
+ cc = malloc(sizeof(*cc), M_DEVBUF, M_NOWAIT);
+ if (!cc)
+ return (NULL);
+ bzero(cc, sizeof(*cc));
+
+ cc->cc_state = CHAN_FLOAT;
+ cc->cc_locked = locked;
+
+ /* set default timeslot map for E1 */
+ cc->cc_tslots = 0xfffffffe; /* all but timeslot 0 */
+ strlcpy(cc->cc_ppp.pp_if.if_xname, name,
+ sizeof(cc->cc_ppp.pp_if.if_xname));
+
+ cc->cc_ppp.pp_if.if_softc = cc;
+
+ return (cc);
+}
+
+int
+musycc_channel_attach(struct musycc_softc *mc, struct channel_softc *cc,
+ struct device *dev, u_int8_t gnum)
+{
+ struct musycc_group *mg;
+ int i;
+
+ if (cc->cc_state != CHAN_FLOAT)
+ return (-1); /* already attached */
+
+ if (gnum >= mc->mc_ngroups) {
+ ACCOOM_PRINTF(0, ("%s: %s tries to attach to nonexistent group",
+ mc->mc_dev.dv_xname, cc->cc_ifp->if_xname));
+ return (-1);
+ }
+
+ mg = &mc->mc_groups[gnum];
+ for (i = 0; i < MUSYCC_NUMCHAN; i++)
+ if (mg->mg_channels[i] == NULL) {
+ mg->mg_channels[i] = cc;
+ cc->cc_state = CHAN_IDLE;
+ cc->cc_group = mg;
+ cc->cc_channel = i;
+ cc->cc_parent = dev;
+ return (i);
+ }
+ return (-1);
+}
+
+void
+musycc_channel_detach(struct ifnet *ifp)
+{
+ struct channel_softc *cc = ifp->if_softc;
+
+ if (cc->cc_state != CHAN_FLOAT) {
+ musycc_free_channel(cc->cc_group, cc->cc_channel);
+ cc->cc_group->mg_channels[cc->cc_channel] = NULL;
+ }
+
+ if_detach(ifp);
+}
+
+#ifdef ACCOOM_DEBUG
+const char *musycc_events[] = {
+ "NONE", "SACK", "EOB", "EOM", "EOP", "CHABT", "CHIC", "FREC",
+ "SINC", "SDEC", "SFILT", "RFU", "RFU", "RFU", "RFU", "RFU"
+};
+const char *musycc_errors[] = {
+ "NONE", "BUFF", "COFA", "ONR", "PROT", "RFU", "RFU", "RFU",
+ "OOF", "FCS", "ALIGN", "ABT", "LNG", "SHT", "SUERR", "PERR"
+};
+const char *mu_proto[] = {
+ "trans", "ss7", "hdlc16", "hdlc32"
+};
+const char *mu_mode[] = {
+ "t1", "e1", "2*e1", "4*e1", "n64"
+};
+
+char musycc_intrbuf[48];
+
+char *
+musycc_intr_print(u_int32_t id)
+{
+ snprintf(musycc_intrbuf, sizeof(musycc_intrbuf),
+ "ev %s er %s grp %d chan %d dir %s",
+ musycc_events[MUSYCC_INTD_EVENT(id)],
+ musycc_errors[MUSYCC_INTD_ERROR(id)],
+ MUSYCC_INTD_GRP(id), MUSYCC_INTD_CHAN(id),
+ id & MUSYCC_INTD_DIR ? "T" : "R");
+ return (musycc_intrbuf);
+}
+
+void
+musycc_dump_group(int level, struct musycc_group *mg)
+{
+ struct musycc_grpdesc *md = mg->mg_group;
+ int i;
+
+ if (level > accoom_debug)
+ return;
+
+ printf("%s: dumping group %d\n",
+ mg->mg_hdlc->mc_dev.dv_xname, mg->mg_gnum);
+ printf("===========================================================\n");
+ printf("global conf: %08x\n", md->global_conf);
+ printf("group conf: [%08x] %s %s %s int %s%s inhib BSD %s%s poll %d\n",
+ md->group_conf,
+ md->group_conf & MUSYCC_GRCFG_TXENBL ? "TX" : "",
+ md->group_conf & MUSYCC_GRCFG_RXENBL ? "RX" : "",
+ md->group_conf & MUSYCC_GRCFG_SUBDSBL ? "" : "SUB",
+ md->group_conf & MUSYCC_GRCFG_MSKOOF ? "" : "O",
+ md->group_conf & MUSYCC_GRCFG_MSKCOFA ? "" : "C",
+ md->group_conf & MUSYCC_GRCFG_INHTBSD ? "TX" : "",
+ md->group_conf & MUSYCC_GRCFG_INHRBSD ? "RX" : "",
+ (md->group_conf & MUSYCC_GRCFG_POLL64) == MUSYCC_GRCFG_POLL64 ? 64 :
+ md->group_conf & MUSYCC_GRCFG_POLL32 ? 32 :
+ md->group_conf & MUSYCC_GRCFG_POLL16 ? 16 : 1);
+ printf("port conf: [%08x] %s %s %s %s %s %s %s\n", md->port_conf,
+ mu_mode[md->port_conf & MUSYCC_PORT_MODEMASK],
+ md->port_conf & MUSYCC_PORT_TDAT_EDGE ? "TXE" : "!TXE",
+ md->port_conf & MUSYCC_PORT_TSYNC_EDGE ? "TXS" : "!TXS",
+ md->port_conf & MUSYCC_PORT_RDAT_EDGE ? "RXE" : "!RXE",
+ md->port_conf & MUSYCC_PORT_RSYNC_EDGE ? "RXS" : "!RXS",
+ md->port_conf & MUSYCC_PORT_ROOF_EDGE ? "ROOF" : "!ROOF",
+ md->port_conf & MUSYCC_PORT_TRITX ? "!tri-state" : "tri-state");
+ printf("message len 1: %d 2: %d\n",
+ md->msglen_conf & MUSYCC_MAXFRM_MASK,
+ (md->msglen_conf >> MUSYCC_MAXFRM2_SHIFT) & MUSYCC_MAXFRM_MASK);
+ printf("interrupt queue %x len %d\n", md->int_queuep, md->int_queuelen);
+ printf("memory protection %x\n", md->memprot);
+ printf("===========================================================\n");
+ printf("Timeslot Map:TX\t\tRX\n");
+ for (i = 0; i < 128; i++) {
+ if (md->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ printf("%d: %s%s%s[%02d]\t\t", i,
+ md->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED ? "C" : " ",
+ md->tx_tsmap[i] & MUSYCC_TSLOT_SUB ? "S" : " ",
+ md->tx_tsmap[i] & MUSYCC_TSLOT_56K ? "*" : " ",
+ MUSYCC_TSLOT_CHAN(md->tx_tsmap[i]));
+ else if (md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ printf("%d: \t\t", i);
+ if (md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
+ printf("%s%s%s[%02d]\n",
+ md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED ? "C" : " ",
+ md->rx_tsmap[i] & MUSYCC_TSLOT_SUB ? "S" : " ",
+ md->rx_tsmap[i] & MUSYCC_TSLOT_56K ? "*" : " ",
+ MUSYCC_TSLOT_CHAN(md->rx_tsmap[i]));
+ }
+ printf("===========================================================\n");
+ printf("Channel config:\nTX\t\t\tRX\n");
+ for (i = 0; i < 32; i++)
+ if (md->tx_cconf[i] != 0) {
+ printf("%s%s%s%s%s%s%s %s [%x]\t",
+ md->tx_cconf[i] & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
+ md->tx_cconf[i] & MUSYCC_CHAN_MSKEOM ? "E" : " ",
+ md->tx_cconf[i] & MUSYCC_CHAN_MSKMSG ? "M" : " ",
+ md->tx_cconf[i] & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
+ md->tx_cconf[i] & MUSYCC_CHAN_FCS ? "F" : "",
+ md->tx_cconf[i] & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
+ md->tx_cconf[i] & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
+ mu_proto[MUSYCC_CHAN_PROTO_GET(md->tx_cconf[i])],
+ md->tx_cconf[i]);
+ printf("%s%s%s%s%s%s%s %s [%x]\n",
+ md->rx_cconf[i] & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
+ md->rx_cconf[i] & MUSYCC_CHAN_MSKEOM ? "E" : " ",
+ md->rx_cconf[i] & MUSYCC_CHAN_MSKMSG ? "M" : " ",
+ md->rx_cconf[i] & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
+ md->rx_cconf[i] & MUSYCC_CHAN_FCS ? "F" : "",
+ md->rx_cconf[i] & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
+ md->rx_cconf[i] & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
+ mu_proto[MUSYCC_CHAN_PROTO_GET(md->rx_cconf[i])],
+ md->rx_cconf[i]);
+ }
+ printf("===========================================================\n");
+ musycc_dump_dma(level, mg, 0);
+}
+
+void
+musycc_dump_desc(int level, struct musycc_group *mg)
+{
+#define READ4(x) \
+ bus_space_read_4(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh, \
+ MUSYCC_GROUPBASE(mg->mg_gnum) + (x))
+ u_int32_t w;
+ int i;
+
+ if (level > accoom_debug)
+ return;
+
+ printf("%s: dumping descriptor %d\n",
+ mg->mg_hdlc->mc_dev.dv_xname, mg->mg_gnum);
+ printf("===========================================================\n");
+ printf("global conf: %08x\n", READ4(MUSYCC_GLOBALCONF));
+ w = READ4(0x060c);
+ printf("group conf: [%08x] %s %s %s int %s%s inhib BSD %s%s poll %d\n",
+ w, w & MUSYCC_GRCFG_TXENBL ? "TX" : "",
+ w & MUSYCC_GRCFG_RXENBL ? "RX" : "",
+ w & MUSYCC_GRCFG_SUBDSBL ? "" : "SUB",
+ w & MUSYCC_GRCFG_MSKOOF ? "" : "O",
+ w & MUSYCC_GRCFG_MSKCOFA ? "" : "C",
+ w & MUSYCC_GRCFG_INHTBSD ? "TX" : "",
+ w & MUSYCC_GRCFG_INHRBSD ? "RX" : "",
+ (w & MUSYCC_GRCFG_POLL64) == MUSYCC_GRCFG_POLL64 ? 64 :
+ w & MUSYCC_GRCFG_POLL32 ? 32 :
+ w & MUSYCC_GRCFG_POLL16 ? 16 : 1);
+ w = READ4(0x0618);
+ printf("port conf: [%08x] %s %s %s %s %s %s %s\n", w,
+ mu_mode[w & MUSYCC_PORT_MODEMASK],
+ w & MUSYCC_PORT_TDAT_EDGE ? "TXE" : "!TXE",
+ w & MUSYCC_PORT_TSYNC_EDGE ? "TXS" : "!TXS",
+ w & MUSYCC_PORT_RDAT_EDGE ? "RXE" : "!RXE",
+ w & MUSYCC_PORT_RSYNC_EDGE ? "RXS" : "!RXS",
+ w & MUSYCC_PORT_ROOF_EDGE ? "ROOF" : "!ROOF",
+ w & MUSYCC_PORT_TRITX ? "!tri-state" : "tri-state");
+ w = READ4(0x0614);
+ printf("message len 1: %d 2: %d\n",
+ w & MUSYCC_MAXFRM_MASK,
+ (w >> MUSYCC_MAXFRM2_SHIFT) & MUSYCC_MAXFRM_MASK);
+ printf("interrupt queue %x len %d\n", READ4(0x0604), READ4(0x0608));
+ printf("memory protection %x\n", READ4(0x0610));
+ printf("===========================================================\n");
+
+ printf("Channel config:\nTX\t\t\t\tRX\n");
+ for (i = 0; i < 32; i++) {
+ w = READ4(0x0380 + i * 4);
+ if (w != 0) {
+ printf("%s%s%s%s%s%s%s %s [%08x]\t",
+ w & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
+ w & MUSYCC_CHAN_MSKEOM ? "E" : " ",
+ w & MUSYCC_CHAN_MSKMSG ? "M" : " ",
+ w & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
+ w & MUSYCC_CHAN_FCS ? "F" : "",
+ w & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
+ w & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
+ mu_proto[MUSYCC_CHAN_PROTO_GET(w)],
+ w);
+ w = READ4(0x0580 + i * 4);
+ printf("%s%s%s%s%s%s%s %s [%08x]\n",
+ w & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
+ w & MUSYCC_CHAN_MSKEOM ? "E" : " ",
+ w & MUSYCC_CHAN_MSKMSG ? "M" : " ",
+ w & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
+ w & MUSYCC_CHAN_FCS ? "F" : "",
+ w & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
+ w & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
+ mu_proto[MUSYCC_CHAN_PROTO_GET(w)],
+ w);
+ }
+ }
+ printf("===========================================================\n");
+ musycc_dump_dma(level, mg, 0);
+
+}
+
+void
+musycc_dump_dma(int level, struct musycc_group *mg, int dir)
+{
+ struct musycc_grpdesc *md = mg->mg_group;
+ struct dma_desc *dd;
+ bus_addr_t base, addr;
+ int i;
+
+ if (level > accoom_debug)
+ return;
+
+ printf("DMA Pointers:\n%8s %8s %8s %8s\n",
+ "tx head", "tx msg", "rx head", "rx msg");
+ for (i = 0; i < 32; i++) {
+ if (md->tx_headp[i] == 0 && md->rx_headp[i] == 0)
+ continue;
+ printf("%08x %08x %08x %08x\n",
+ md->tx_headp[i], md->tx_msgp[i],
+ md->rx_headp[i], md->rx_msgp[i]);
+ }
+
+ base = mg->mg_listmap->dm_segs[0].ds_addr;
+ for (i = 0; dir & MUSYCC_SREQ_TX && i < 32; i++) {
+ if (md->tx_headp[i] == 0)
+ continue;
+
+ printf("==================================================\n");
+ printf("TX DMA Ring for channel %d\n", i);
+ printf("pend: %p cur: %p cnt: %d use: %d pkgs: %d\n",
+ mg->mg_dma_d[i].tx_pend, mg->mg_dma_d[i].tx_cur,
+ mg->mg_dma_d[i].tx_cnt, mg->mg_dma_d[i].tx_use,
+ mg->mg_dma_d[i].tx_pkts);
+ printf(" %10s %8s %8s %8s %8s %10s\n",
+ "addr", "paddr", "next", "status", "data", "mbuf");
+ dd = mg->mg_dma_d[i].tx_pend;
+ do {
+ addr = htole32(base + ((caddr_t)dd - mg->mg_listkva));
+ printf("%s %p %08x %08x %08x %08x %p\n",
+ dd == mg->mg_dma_d[i].tx_pend ? ">" :
+ dd == mg->mg_dma_d[i].tx_cur ? "*" : " ",
+ dd, addr, dd->next, dd->status,
+ dd->data, dd->mbuf);
+ dd = dd->nextdesc;
+ } while (dd != mg->mg_dma_d[i].tx_pend);
+ }
+ for (i = 0; dir & MUSYCC_SREQ_RX && i < 32; i++) {
+ if (md->rx_headp[i] == 0)
+ continue;
+
+ printf("==================================================\n");
+ printf("RX DMA Ring for channel %d\n", i);
+ printf("prod: %p cnt: %d\n",
+ mg->mg_dma_d[i].rx_prod, mg->mg_dma_d[i].rx_cnt);
+ printf(" %8s %8s %8s %8s %10s\n",
+ "addr", "paddr", "next", "status", "data", "mbuf");
+ dd = mg->mg_dma_d[i].rx_prod;
+ do {
+ addr = htole32(base + ((caddr_t)dd - mg->mg_listkva));
+ printf("%p %08x %08x %08x %08x %p\n", dd, addr,
+ dd->next, dd->status, dd->data, dd->mbuf);
+ dd = dd->nextdesc;
+ } while (dd != mg->mg_dma_d[i].rx_prod);
+ }
+}
+#endif
diff --git a/sys/dev/pci/musycc_obsd.c b/sys/dev/pci/musycc_obsd.c
new file mode 100644
index 00000000000..6e73a9ae77f
--- /dev/null
+++ b/sys/dev/pci/musycc_obsd.c
@@ -0,0 +1,299 @@
+/* $OpenBSD: musycc_obsd.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: musycc_obsd.c,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_sppp.h>
+
+#include <dev/pci/musyccvar.h>
+#include <dev/pci/musyccreg.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+int musycc_match(struct device *, void *, void *);
+int ebus_match(struct device *, void *, void *);
+void musycc_softc_attach(struct device *, struct device *, void *);
+void ebus_softc_attach(struct device *, struct device *, void *);
+int ebus_print(void *, const char *);
+
+struct cfattach musycc_ca = {
+ sizeof(struct musycc_softc), musycc_match, musycc_softc_attach
+};
+
+struct cfattach ebus_ca = {
+ sizeof(struct ebus_softc), ebus_match, ebus_softc_attach
+};
+
+struct cfdriver musycc_cd = {
+ NULL, "musycc", DV_DULL
+};
+
+struct cfdriver ebus_cd = {
+ NULL, "ebus", DV_DULL
+};
+
+SLIST_HEAD(, musycc_softc) msc_list = SLIST_HEAD_INITIALIZER(msc_list);
+
+const struct pci_matchid musycc_pci_devices[] = {
+ { PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_MUSYCC8478 },
+ { PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_MUSYCC8474 },
+ { PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_MUSYCC8472 },
+ { PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_MUSYCC8471 }
+};
+
+int
+musycc_match(struct device *parent, void *match, void *aux)
+{
+ int rv;
+ struct pci_attach_args *pa = aux;
+
+ rv = pci_matchbyid((struct pci_attach_args *)aux, musycc_pci_devices,
+ sizeof(musycc_pci_devices)/sizeof(musycc_pci_devices[0]));
+ if (rv != 0 && pa->pa_function == 0)
+ return (rv);
+ return (0);
+}
+
+int
+ebus_match(struct device *parent, void *match, void *aux)
+{
+ int rv;
+ struct pci_attach_args *pa = aux;
+
+ rv = pci_matchbyid((struct pci_attach_args *)aux, musycc_pci_devices,
+ sizeof(musycc_pci_devices)/sizeof(musycc_pci_devices[0]));
+ if (rv != 0 && pa->pa_function == 1)
+ return (rv);
+ return (0);
+}
+
+void
+musycc_softc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct musycc_softc *sc = (struct musycc_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+
+ if (pci_mapreg_map(pa, MUSYCC_PCI_BAR,
+ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &sc->mc_st, &sc->mc_sh, NULL, &sc->mc_iosize, 0)) {
+ printf(": can't map mem space\n");
+ return;
+ }
+ sc->mc_dmat = pa->pa_dmat;
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_CONEXANT_MUSYCC8478:
+ sc->mc_ngroups = 8;
+ sc->mc_nports = 8;
+ break;
+ case PCI_PRODUCT_CONEXANT_MUSYCC8474:
+ sc->mc_ngroups = 4;
+ sc->mc_nports = 4;
+ break;
+ case PCI_PRODUCT_CONEXANT_MUSYCC8472:
+ sc->mc_ngroups = 2;
+ sc->mc_nports = 2;
+ break;
+ case PCI_PRODUCT_CONEXANT_MUSYCC8471:
+ sc->mc_ngroups = 1;
+ sc->mc_nports = 1;
+ break;
+ }
+
+ sc->bus = parent->dv_unit;
+ sc->device = pa->pa_device;
+ SLIST_INSERT_HEAD(&msc_list, sc, list);
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pa, &ih)) {
+ printf(": couldn't map interrupt\n");
+ bus_space_unmap(sc->mc_st, sc->mc_sh, sc->mc_iosize);
+ return;
+ }
+
+ intrstr = pci_intr_string(pc, ih);
+ sc->mc_ih = pci_intr_establish(pc, ih, IPL_NET, musycc_intr, sc,
+ self->dv_xname);
+ if (sc->mc_ih == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ bus_space_unmap(sc->mc_st, sc->mc_sh, sc->mc_iosize);
+ return;
+ }
+
+ printf(": %s\n", intrstr);
+ return;
+}
+
+void
+ebus_softc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ebus_dev rom;
+ struct musycc_attach_args ma;
+ struct ebus_softc *esc = (struct ebus_softc *)self;
+ struct musycc_softc *sc;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+#if 0
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+#endif
+ struct musycc_rom baseconf;
+ struct musycc_rom_framer framerconf;
+ bus_size_t iosize, offset;
+ int i;
+
+ /* find HDLC controller softc ... */
+ SLIST_FOREACH(sc, &msc_list, list)
+ if (sc->bus == parent->dv_unit && sc->device == pa->pa_device)
+ break;
+ if (sc == NULL) {
+ printf(": corresponding hdlc controller not found\n");
+ return;
+ }
+
+ /* ... and link them together */
+ esc->ec_hdlc = sc;
+ sc->mc_ebus = esc;
+
+ if (pci_mapreg_map(pa, MUSYCC_PCI_BAR,
+ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &esc->ec_st, &esc->ec_sh, NULL, &iosize, 0)) {
+ printf(": can't map mem space\n");
+ pci_intr_disestablish(pc, sc->mc_ih);
+ bus_space_unmap(sc->mc_st, sc->mc_sh, sc->mc_iosize);
+ return;
+ }
+ esc->ec_dmat = pa->pa_dmat;
+
+#if 0
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pa, &ih)) {
+ printf(": couldn't map interrupt\n");
+ goto failed;
+ }
+
+ intrstr = pci_intr_string(pc, ih);
+ esc->ec_ih = pci_intr_establish(pc, ih, IPL_NET, ebus_intr, esc,
+ self->dv_xname);
+ if (esc->ec_ih == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ goto failed;
+ }
+
+ /* XXX this printf should actually move to the end of the function */
+ printf(": %s\n", intrstr);
+#endif
+
+ if (ebus_attach_device(&rom, esc->ec_hdlc, 0, 0x400) != 0) {
+ printf(": failed to map rom @ %05p\n", 0);
+ goto failed;
+ }
+
+ offset = 0;
+ ebus_read_buf(&rom, offset, &baseconf, sizeof(baseconf));
+ offset += sizeof(baseconf);
+
+ if (baseconf.magic != MUSYCC_ROM_MAGIC) {
+ printf(": bad rom\n");
+ goto failed;
+ }
+
+ /* Do generic parts of attach. */
+ if (musycc_attach_common(sc, baseconf.portmap, baseconf.portmode))
+ goto failed;
+
+ /* map and reset leds */
+ /* (15 * 0x4000) << 2 */
+ esc->ec_ledbase = ntohl(baseconf.ledbase);
+ esc->ec_ledmask = baseconf.ledmask;
+ ebus_set_led(esc, 0);
+
+ printf(": card rev %d \n", ntohs(baseconf.rev));
+
+ for (i = 0; i < baseconf.numframer; i++) {
+ if (offset >= 0x400) {
+ printf(": bad rom\n");
+ goto failed;
+ }
+ ebus_read_buf(&rom, offset, &framerconf, sizeof(framerconf));
+ offset += sizeof(framerconf);
+
+ strlcpy(ma.ma_product, baseconf.product, sizeof(ma.ma_product));
+ ma.ma_base = ntohl(framerconf.base);
+ ma.ma_size = ntohl(framerconf.size);
+ ma.ma_type = ntohl(framerconf.type);
+ ma.ma_gnum = framerconf.gnum;
+ ma.ma_port = framerconf.port;
+ ma.ma_slot = framerconf.slot;
+
+ (void)config_found(&sc->mc_dev, &ma, ebus_print);
+ }
+
+ return;
+failed:
+ /* Failed! */
+ pci_intr_disestablish(pc, sc->mc_ih);
+ if (esc->ec_ih != NULL)
+ pci_intr_disestablish(pc, esc->ec_ih);
+ bus_space_unmap(sc->mc_st, sc->mc_sh, sc->mc_iosize);
+ bus_space_unmap(esc->ec_st, esc->ec_sh, iosize);
+ return;
+}
+
+int
+ebus_print(void *aux, const char *pnp)
+{
+ struct musycc_attach_args *ma = aux;
+
+ if (pnp)
+ printf("framer at %s port %d slot %c",
+ pnp, ma->ma_port, ma->ma_slot);
+ else
+ printf(" port %d slot %c", ma->ma_port, ma->ma_slot);
+ return (UNCONF);
+}
+
diff --git a/sys/dev/pci/musyccreg.h b/sys/dev/pci/musyccreg.h
new file mode 100644
index 00000000000..2861715e3a5
--- /dev/null
+++ b/sys/dev/pci/musyccreg.h
@@ -0,0 +1,256 @@
+/* $OpenBSD: musyccreg.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: musyccreg.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef __MUSYCCREG_H__
+#define __MUSYCCREG_H__
+
+#define MUSYCC_PCI_BAR 0x10 /* offset of Base Address Register */
+
+/* Group Base Pointer -- per Group unique */
+#define MUSYCC_GROUPBASE(x) (0x0800 * (x))
+/* Dual Address Cycle Base Pointer */
+#define MUSYCC_DACB_PTR 0x0004
+/* Service Request Descriptor -- per Group unique */
+#define MUSYCC_SERREQ(x) (0x0008 + 0x0800 * (x))
+/* Interrupt Status Descriptor */
+#define MUSYCC_INTRSTATUS 0x000c
+#define MUSYCC_INTCNT_MASK 0x00007fff
+#define MUSYCC_INTFULL 0x00008000
+#define MUSYCC_NEXTINT_GET(x) (((x) >> 16) & 0x7fff)
+#define MUSYCC_NEXTINT_SET(x) (((x) & 0x7fff) << 16)
+
+/* Global Configuration Descriptor */
+#define MUSYCC_GLOBALCONF 0x0600
+/* Interrupt Queue Descriptor */
+#define MUSYCC_INTQPTR 0x0604
+#define MUSYCC_INTQLEN 0x0608
+
+/* group structure [page 5-6], this puppy needs to be 2k aligned */
+struct musycc_grpdesc {
+ u_int32_t tx_headp[32]; /* transmit head ptr */
+ u_int32_t tx_msgp[32]; /* transmit msg ptr */
+ u_int32_t rx_headp[32]; /* receive head ptr */
+ u_int32_t rx_msgp[32]; /* receive msg ptr */
+ u_int8_t tx_tsmap[128]; /* transmit timeslot map */
+ u_int8_t tx_submap[256]; /* transmit sub channel map */
+ u_int32_t tx_cconf[32]; /* transmit channel config */
+ u_int8_t rx_tsmap[128]; /* receive timeslot map */
+ u_int8_t rx_submap[256]; /* receive sub channel map */
+ u_int32_t rx_cconf[32]; /* receive channel config */
+ u_int32_t global_conf; /* global config */
+ u_int32_t int_queuep; /* interrupt queue ptr */
+ u_int32_t int_queuelen; /* interrupt queue len */
+ u_int32_t group_conf; /* group config */
+ u_int32_t memprot; /* memory protection */
+ u_int32_t msglen_conf; /* message length config */
+ u_int32_t port_conf; /* serial port config */
+};
+
+/* Global Configuration Descriptor [page 5-10] */
+#define MUSYCC_CONF_PORTMAP 0x00000003 /* group -> port mapping */
+#define MUSYCC_CONF_INTB 0x00000004 /* if set INTB is disabled */
+#define MUSYCC_CONF_INTA 0x00000008 /* if set INTA is disabled */
+#define MUSYCC_CONF_ELAPSE_GET(x) \
+ (((x) >> 4) & 0x7) /* get elapse value */
+#define MUSYCC_CONF_ELAPSE_SET(x) \
+ ((x & 0x7) << 4) /* set elapse value */
+#define MUSYCC_CONF_ALAPSE_GET(x) \
+ (((x) >> 8) & 0x3) /* get alapse value */
+#define MUSYCC_CONF_ALAPSE_SET(x) \
+ ((x & 0x3) << 8) /* set alapse value */
+#define MUSYCC_CONF_MPUSEL 0x00000400 /* EBUS mode, 1 = intel style */
+#define MUSYCC_CONF_ECKEN 0x00000800 /* EBUS clock enable */
+#define MUSYCC_CONF_BLAPSE_GET(x) \
+ (((x) >> 12) & 0x7) /* get blapse value */
+#define MUSYCC_CONF_BLAPSE_SET(x) \
+ ((x & 0x7) << 12) /* set blapse value */
+
+/* Interrupt Descriptor [page 5-41] */
+#define MUSYCC_INTD_BLEN 0x00001fff /* size of data on EOB & EOM */
+#define MUSYCC_INTD_ILOST 0x00008000 /* Interrupt Lost */
+#define MUSYCC_INTD_DIR 0x80000000 /* transmit specific int */
+#define MUSYCC_INTD_GRP(x) \
+ ((((x) >> 29) & 0x3) | (((x) >> 12) & 0x4)) /* Group Number [0-7] */
+#define MUSYCC_INTD_CHAN(x) \
+ (((x) >> 24) & 0x1f) /* Channel Number [0-31] */
+#define MUSYCC_INTD_EVENT(x) \
+ (((x) >> 20) & 0xf) /* Event that caused the int */
+#define MUSYCC_INTD_ERROR(x) \
+ (((x) >> 16) & 0xf) /* Error that caused the int */
+
+/* possible Interrupt Events */
+#define MUSYCC_INTEV_NONE 0 /* No Event to report */
+#define MUSYCC_INTEV_SACK 1 /* Service Request Ack */
+#define MUSYCC_INTEV_EOB 2 /* End of Buffer */
+#define MUSYCC_INTEV_EOM 3 /* End of Message */
+#define MUSYCC_INTEV_EOP 4 /* End of Padfill */
+#define MUSYCC_INTEV_CHABT 5 /* Change to Abort Code */
+#define MUSYCC_INTEV_CHIC 6 /* Change to Idle Code */
+#define MUSYCC_INTEV_FREC 7 /* Frame Recovery */
+#define MUSYCC_INTEV_SINC 8 /* SS7 SUERM Octet Count inc */
+#define MUSYCC_INTEV_SDEC 9 /* SS7 SUERM Octet Count dec */
+#define MUSYCC_INTEV_SFILT 10 /* SS7 Filtered Message */
+
+/* possible Interrupt Errors */
+#define MUSYCC_INTERR_NONE 0 /* No Error to report */
+#define MUSYCC_INTERR_BUFF 1 /* Buffer Error */
+#define MUSYCC_INTERR_COFA 2 /* Change of Frame Alignment */
+#define MUSYCC_INTERR_ONR 3 /* Owner-Bit Error */
+#define MUSYCC_INTERR_PROT 4 /* Mem Protection Violation */
+#define MUSYCC_INTERR_OOF 8 /* Out of Frame */
+#define MUSYCC_INTERR_FCS 9 /* Frame Check Sequence Error */
+#define MUSYCC_INTERR_ALIGN 10 /* Octet Alignment Error */
+#define MUSYCC_INTERR_ABT 11 /* Abort Termination */
+#define MUSYCC_INTERR_LNG 12 /* Long Message */
+#define MUSYCC_INTERR_SHT 13 /* Short Message */
+#define MUSYCC_INTERR_SUERR 14 /* SS7 Signal Unit Error */
+#define MUSYCC_INTERR_PERR 15 /* PCI Bus Parity Error */
+
+/* Service Request Descriptor [page 5-14] */
+#define MUSYCC_SREQ_MASK 0x001f /* Generic SREQ/Channel Mask */
+#define MUSYCC_SREQ_CHSET(x) \
+ ((x) & MUSYCC_SREQ_MASK) /* shortcut */
+#define MUSYCC_SREQ_TXDIR 0x0020 /* Transmit Direction */
+#define MUSYCC_SREQ_SET(x) \
+ (((x) & MUSYCC_SREQ_MASK) << 8) /* Service Request */
+
+#define MUSYCC_SREQ_RX 0x1 /* Receive Request */
+#define MUSYCC_SREQ_TX 0x2 /* Transmit Request */
+#define MUSYCC_SREQ_BOTH 0x3 /* both directions */
+#define MUSYCC_SREQ_NOWAIT 0x8
+#define MUSYCC_SREQ_NONE 0xffffffff
+
+/* Group Configuration Descriptor [page 5-16] */
+#define MUSYCC_GRCFG_RXENBL 0x0001 /* Receiver Enabled */
+#define MUSYCC_GRCFG_TXENBL 0x0002 /* Transmitter Enabled */
+#define MUSYCC_GRCFG_SUBDSBL 0x0004 /* Subchanneling Disabled */
+#define MUSYCC_GRCFG_OOFABT 0x0008 /* OOF Message Processing */
+#define MUSYCC_GRCFG_MSKOOF 0x0010 /* OOF Interrupt Disabled */
+#define MUSYCC_GRCFG_MSKCOFA 0x0020 /* COFA Interrupt Disabled */
+#define MUSYCC_GRCFG_MCENBL 0x0040 /* Msg Config Bits Copy */
+#define MUSYCC_GRCFG_INHRBSD 0x0100 /* Inihibit RX Buf Stat Desc */
+#define MUSYCC_GRCFG_INHTBSD 0x0200 /* Inihibit TX Buf Stat Desc */
+#define MUSYCC_GRCFG_POLL16 0x0400 /* Poll at all 16 frame sync */
+#define MUSYCC_GRCFG_POLL32 0x0800 /* Poll at all 32 frame sync */
+#define MUSYCC_GRCFG_POLL64 0x0C00 /* Poll at all 64 frame sync */
+#define MUSYCC_GRCFG_SFALIGN 0x8000 /* Super Frame Alignment */
+#define MUSYCC_GRCFG_SUETMASK 0x3f0000 /* SS7 SUERR Threshold */
+
+/* Port Configuration Descriptor [page 5-19] */
+#define MUSYCC_PORT_MODEMASK 0x007 /* Port Mode Mask */
+#define MUSYCC_PORT_MODE_T1 0 /* T1 - 24 time slots */
+#define MUSYCC_PORT_MODE_E1 1 /* E1 - 32 time slots */
+#define MUSYCC_PORT_MODE_2E1 2 /* 2*E1 - 64 time slots */
+#define MUSYCC_PORT_MODE_4E1 3 /* 4*E1 - 128 time slots */
+#define MUSYCC_PORT_MODE_N64 4 /* N*64 mode */
+#define MUSYCC_PORT_TDAT_EDGE 0x010 /* TX Data on rising Edge */
+#define MUSYCC_PORT_TSYNC_EDGE 0x020 /* TX Frame Sync on rising E */
+#define MUSYCC_PORT_RDAT_EDGE 0x040 /* RX Data on rising Edge */
+#define MUSYCC_PORT_RSYNC_EDGE 0x080 /* RX Frame Sync on rising E */
+#define MUSYCC_PORT_ROOF_EDGE 0x100 /* RX OOF on rising Edge */
+#define MUSYCC_PORT_TRITX 0x200 /* TX Three-state disabled */
+
+/* Message Length Descriptor [page 5-20] */
+#define MUSYCC_MAXFRM_MAX 4094 /* maximum message length */
+#define MUSYCC_MAXFRM_MASK 0x0eff
+#define MUSYCC_MAXFRM2_SHIFT 16
+
+/* Time Slot Descriptor [page 5-23] */
+#define MUSYCC_TSLOT_ENABLED 0x80 /* timeslot enabled */
+#define MUSYCC_TSLOT_56K 0x20 /* 56kbps timeslots */
+#define MUSYCC_TSLOT_SUB 0x40 /* subchannel timeslots */
+#define MUSYCC_TSLOT_MASK 0x1f /* channel number mask */
+#define MUSYCC_TSLOT_CHAN(x) \
+ ((x) & MUSYCC_TSLOT_MASK) /* masked channel number */
+
+/* Channel Configuration Descriptor [page 5-27] */
+#define MUSYCC_CHAN_MSKBUFF 0x00000002 /* BUFF & ONR Intr disabled */
+#define MUSYCC_CHAN_MSKEOM 0x00000004 /* EOM Interrupt disabled */
+#define MUSYCC_CHAN_MSKMSG 0x00000008 /* LNG, FCS, ALIGN, ABT mask */
+#define MUSYCC_CHAN_MSKIDLE 0x00000010 /* CHABT, CHIC, SHT Intr mask */
+#define MUSYCC_CHAN_MSKSFILT 0x00000020 /* SS7 SFILT Interrupt mask */
+#define MUSYCC_CHAN_MSKSDEC 0x00000040 /* SS7 SDEC Interrupt mask */
+#define MUSYCC_CHAN_MSKSINC 0x00000080 /* SS7 SINC Interrupt mask */
+#define MUSYCC_CHAN_MSKSUERR 0x00000100 /* SS7 SUERR Interrupt mask */
+#define MUSYCC_CHAN_FCS 0x00000200 /* FCS checksum disable */
+#define MUSYCC_CHAN_MAXLEN1 0x00000400 /* Msg Len Max via MAXFRM1 */
+#define MUSYCC_CHAN_MAXLEN2 0x00000800 /* Msg Len Max via MAXFRM1 */
+#define MUSYCC_CHAN_EOPI 0x00008000 /* End of Padfill Int enable */
+#define MUSYCC_CHAN_INV 0x00800000 /* Data Inversion */
+#define MUSYCC_CHAN_PADJ 0x80000000 /* Pad Count Adjust enabled */
+
+#define MUSYCC_CHAN_PROTO_GET(x) \
+ (((x) >> 12) & 0x7) /* get line protocol */
+#define MUSYCC_CHAN_PROTO_SET(x) \
+ ((x & 0x7) << 12) /* set line protocol */
+#define MUSYCC_PROTO_TRANSPARENT 0 /* raw stream */
+#define MUSYCC_PROTO_SS7HDLC 1 /* SS7 HDLC messages */
+#define MUSYCC_PROTO_HDLC16 2 /* basic HDLC with 16 bit FCS */
+#define MUSYCC_PROTO_HDLC32 3 /* basic HDLC with 32 bit FCS */
+
+#define MUSYCC_CHAN_BUFLEN_GET(x) \
+ (((x) >> 16) & 0x3f) /* get FIFO Buffer Length */
+#define MUSYCC_CHAN_BUFLEN_SET(x) \
+ (((x) & 0x3F) << 16) /* set FIFO Buffer Length */
+#define MUSYCC_CHAN_BUFIDX_GET(x) \
+ (((x) >> 24) & 0x3f) /* get FIFO Buffer Index */
+#define MUSYCC_CHAN_BUFIDX_SET(x) \
+ (((x) & 0x3F) << 24) /* set FIFO Buffer Index */
+
+
+/* Tx / Rx Buffer Descriptor [page 5-33] */
+#define MUSYCC_STATUS_LEN(x) \
+ ((x) & 0x3fff) /* length of dma buffer */
+#define MUSYCC_STATUS_REPEAT 0x00008000 /* repeat buffer */
+#define MUSYCC_STATUS_ERROR 0x000f0000
+#define MUSYCC_STATUS_EOBI 0x10000000 /* end of buffer interrupt */
+#define MUSYCC_STATUS_EOM 0x20000000 /* end of message */
+#define MUSYCC_STATUS_NOPOLL 0x40000000 /* don't poll for new descr */
+#define MUSYCC_STATUS_OWNER 0x80000000
+
+
+/*
+ * ROM data structures
+ */
+
+struct musycc_rom {
+ u_int16_t magic;
+#define MUSYCC_ROM_MAGIC (htons(0xacc0))
+ u_int8_t rev; /* rev. of the card */
+ u_int8_t vers; /* version of the rom */
+ char product[64];
+ u_int8_t portmap; /* portmap config */
+ u_int8_t portmode; /* port mode e.g. 2*E1 */
+ u_int8_t numframer; /* # of sub-configs */
+ u_int8_t ledmask; /* mask for led register */
+ u_int32_t ledbase; /* base of the led register */
+ u_int32_t rfu[2]; /* RFU */
+};
+
+struct musycc_rom_framer {
+ u_int32_t type;
+ u_int32_t base;
+ u_int32_t size;
+ u_int8_t gnum;
+ u_int8_t port;
+ char slot;
+ u_int8_t flags;
+ u_int32_t rfu[2]; /* RFU */
+};
+#endif
diff --git a/sys/dev/pci/musyccvar.h b/sys/dev/pci/musyccvar.h
new file mode 100644
index 00000000000..a45ed09f660
--- /dev/null
+++ b/sys/dev/pci/musyccvar.h
@@ -0,0 +1,234 @@
+/* $OpenBSD: musyccvar.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+/* $Id: musyccvar.h,v 1.1 2005/08/13 22:49:48 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
+ * Written by: Claudio Jeker <jeker@accoom.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef __MUSYCCVAR_H__
+#define __MUSYCCVAR_H__
+
+#include <sys/queue.h>
+
+#define PPP_HEADER_LEN 4 /* should be globaly defined by sppp */
+
+/* some defaults */
+#define MUSYCC_NUMCHAN 32 /* 32 channels per group */
+#define MUSYCC_NUMPORT 8 /* max 8 ports per controller */
+#define MUSYCC_SREQNUM 16 /* pending SREQ */
+#define MUSYCC_SREQMASK (MUSYCC_SREQNUM - 1)
+
+/* dma ring sizes */
+#define MUSYCC_DMA_CNT 256
+#define MUSYCC_DMA_MAPSIZE (MUSYCC_DMA_CNT * sizeof(struct dma_desc))
+#define MUSYCC_DMA_MIN 3
+#define MUSYCC_DMA_MAX 64
+
+struct musycc_softc;
+struct ebus_softc;
+
+/* DMA descriptor for data */
+struct dma_desc {
+ u_int32_t status;
+ u_int32_t data;
+ u_int32_t next;
+ /* Software only */
+ struct mbuf *mbuf;
+ struct dma_desc *nextdesc;
+ bus_dmamap_t map;
+};
+
+#define MUSYCC_INTLEN 512 /* 512 pending interrups is enough */
+struct musycc_intdesc {
+ u_int32_t md_intrq[MUSYCC_INTLEN];
+};
+
+struct musycc_dma_data {
+ /*
+ * received dma ring. rx_prod points to the frist descriptors that
+ * is under musycc control (first empty).
+ */
+ struct dma_desc *rx_prod;
+ int rx_cnt;
+
+ struct dma_desc *tx_pend; /* finished pointer */
+ struct dma_desc *tx_cur; /* current insertion pointer */
+ int tx_cnt; /* number of descriptors */
+ int tx_use; /* number of used descriptors */
+ int tx_pkts; /* number of packets in queue */
+};
+
+enum musycc_state {
+ CHAN_FLOAT, /* unconnected channel */
+ CHAN_IDLE,
+ CHAN_RUNNING,
+ CHAN_FAULT,
+ CHAN_TRANSIENT /* dummy state to protect ongoing state changes */
+};
+
+enum musycc_event {
+ EV_NULL, /* null event, ignore */
+ EV_ACTIVATE, /* activate channel go to running state */
+ EV_STOP, /* stop dma engine */
+ EV_IDLE, /* free timeslots et al. and go to idle state */
+ EV_WATCHDOG /* watchdog event, stop dma engine */
+};
+
+/* group structure */
+struct musycc_group {
+ struct musycc_softc *mg_hdlc; /* main controller */
+ struct musycc_grpdesc *mg_group; /* group descriptor */
+ u_int8_t mg_gnum; /* group number */
+ u_int8_t mg_port; /* port number */
+ u_int8_t mg_loaded; /* sreq(5) done? */
+ u_int64_t mg_fifomask; /* fifo allocation mask */
+
+ struct channel_softc *mg_channels[MUSYCC_NUMCHAN];
+ struct musycc_dma_data mg_dma_d[MUSYCC_NUMCHAN];
+ struct dma_desc *mg_freelist;
+ int mg_freecnt;
+
+ struct {
+ u_int32_t sreq;
+ enum musycc_event event;
+ } mg_sreq[MUSYCC_SREQNUM];
+ int mg_sreqpend;
+ int mg_sreqprod;
+
+ struct dma_desc *mg_dma_pool;
+ bus_dma_tag_t mg_dmat; /* bus dma tag */
+ caddr_t mg_listkva;
+ bus_dmamap_t mg_listmap;
+ bus_dma_segment_t mg_listseg[1];
+ int mg_listnseg;
+ bus_dmamap_t mg_tx_sparemap;
+ bus_dmamap_t mg_rx_sparemap;
+};
+
+/* attach arguments for framer devices */
+struct musycc_attach_args {
+ char ma_product[64];
+ bus_size_t ma_base;
+ bus_size_t ma_size;
+ u_int32_t ma_type;
+ u_int8_t ma_gnum;
+ u_int8_t ma_port;
+ char ma_slot;
+};
+
+/* generic ebus device handle */
+struct ebus_dev {
+ bus_size_t base;
+ bus_size_t size;
+ bus_space_tag_t st;
+ bus_space_handle_t sh;
+};
+
+/* Softc for each HDLC channel config */
+struct channel_softc {
+ struct sppp cc_ppp; /* sppp network attachement */
+ struct ifnet *cc_ifp; /* pointer to the active ifp */
+ struct musycc_group *cc_group;
+ struct device *cc_parent; /* parent framer */
+
+ u_int32_t cc_tslots; /* timeslot map */
+ int cc_unit;
+ enum musycc_state cc_state; /* state machine info */
+ u_int8_t cc_channel; /* HDLC channel */
+ u_int8_t cc_locked;
+};
+
+/* Softc for the HDLC Controller (function 0) */
+struct musycc_softc {
+ struct device mc_dev; /* generic device structures */
+ void *mc_ih; /* interrupt handler cookie */
+ bus_space_tag_t mc_st; /* bus space tag */
+ bus_space_handle_t mc_sh; /* bus space handle */
+ bus_dma_tag_t mc_dmat; /* bus dma tag */
+ bus_size_t mc_iosize; /* size of bus space */
+
+ caddr_t mc_groupkva; /* group configuration mem */
+ bus_dmamap_t mc_cfgmap;
+ bus_dma_segment_t mc_cfgseg[1];
+ bus_dmamap_t mc_intrmap;
+ bus_dma_segment_t mc_intrseg[1];
+ int mc_cfgnseg;
+ int mc_intrnseg;
+
+ struct musycc_group *mc_groups; /* mc_ngroups groups */
+ struct musycc_intdesc *mc_intrd;
+ u_int32_t mc_global_conf; /* global config descriptor */
+ u_int32_t mc_intrqptr; /* interrupt queue pointer */
+ int mc_ngroups;
+ int mc_nports;
+
+ int bus, device; /* location of card */
+ struct ebus_softc *mc_ebus; /* corresponding EBUS bridge */
+ SLIST_ENTRY(musycc_softc) list; /* list of all hdlc ctrls */
+};
+
+/* Softc for the EBUS bridge (function 1) */
+struct ebus_softc {
+ struct device ec_dev; /* generic device structures */
+ void *ec_ih; /* interrupt handler cookie */
+ bus_space_tag_t ec_st; /* bus space tag */
+ bus_space_handle_t ec_sh; /* bus space handle */
+ bus_dma_tag_t ec_dmat; /* bus dma tag */
+ struct musycc_softc *ec_hdlc; /* corresponding HDLC
+ controller */
+ bus_size_t ec_ledbase;
+ u_int8_t ec_ledmask;
+};
+
+int musycc_attach_common(struct musycc_softc *, u_int32_t, u_int32_t);
+int musycc_init_channel(struct channel_softc *, char);
+void musycc_stop_channel(struct channel_softc *);
+void musycc_free_channel(struct musycc_group *, int);
+void musycc_start(struct ifnet *);
+void musycc_watchdog(struct ifnet *);
+
+int musycc_intr(void *);
+int ebus_intr(void *);
+
+/* EBUS API */
+int ebus_attach_device(struct ebus_dev *, struct musycc_softc *,
+ bus_size_t, bus_size_t);
+u_int8_t ebus_read(struct ebus_dev *, bus_size_t);
+void ebus_write(struct ebus_dev *, bus_size_t, u_int8_t);
+void ebus_read_buf(struct ebus_dev *, bus_size_t, void *, size_t);
+void ebus_set_led(struct ebus_softc *, u_int8_t);
+
+/* channel API */
+struct channel_softc *musycc_channel_create(const char *, u_int8_t);
+void musycc_attach_sppp(struct channel_softc *,
+ int (*)(struct ifnet *, u_long, caddr_t));
+int musycc_channel_attach(struct musycc_softc *,
+ struct channel_softc *, struct device *, u_int8_t);
+void musycc_channel_detach(struct ifnet *);
+
+
+#ifndef ACCOOM_DEBUG
+#define ACCOOM_PRINTF(n, x)
+#else
+extern int accoom_debug;
+
+#define ACCOOM_PRINTF(n, x) \
+ do { \
+ if (accoom_debug >= n) \
+ printf x; \
+ } while (0)
+#endif
+
+#endif