diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2005-08-13 22:49:49 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2005-08-13 22:49:49 +0000 |
commit | 629ca807ea9692b75199c888af8d722c434eb738 (patch) | |
tree | 7780b366add71aac45b3284c938030b461aeb2aa /sys/dev/pci | |
parent | 4b6938935c0f118d9f178d89c3fa610b6cff1f1f (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.c | 948 | ||||
-rw-r--r-- | sys/dev/pci/bt8370reg.h | 393 | ||||
-rw-r--r-- | sys/dev/pci/if_art.c | 363 | ||||
-rw-r--r-- | sys/dev/pci/if_art.h | 83 | ||||
-rw-r--r-- | sys/dev/pci/musycc.c | 1941 | ||||
-rw-r--r-- | sys/dev/pci/musycc_obsd.c | 299 | ||||
-rw-r--r-- | sys/dev/pci/musyccreg.h | 256 | ||||
-rw-r--r-- | sys/dev/pci/musyccvar.h | 234 |
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 |