diff options
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/DEVNAMES | 3 | ||||
| -rw-r--r-- | sys/dev/pci/Makefile | 4 | ||||
| -rw-r--r-- | sys/dev/pci/files.pci | 7 | ||||
| -rw-r--r-- | sys/dev/pci/if_lmc.c | 5531 | ||||
| -rw-r--r-- | sys/dev/pci/if_lmc.h | 1396 |
5 files changed, 4 insertions, 6937 deletions
diff --git a/sys/dev/DEVNAMES b/sys/dev/DEVNAMES index 1f42a33c0a9..b208d628b0e 100644 --- a/sys/dev/DEVNAMES +++ b/sys/dev/DEVNAMES @@ -1,4 +1,4 @@ -# $NetBSD: DEVNAMES,v 1.318 2018/09/23 09:21:03 maxv Exp $ +# $NetBSD: DEVNAMES,v 1.319 2018/12/12 07:04:05 maxv Exp $ # # This file contains all used device names and defined attributes in # alphabetical order. New devices added to the system somewhere should first @@ -748,7 +748,6 @@ lkkbd vax lkms vax lm MI lm700x MI -lmc MI lmenv MI lms bebox lms i386 diff --git a/sys/dev/pci/Makefile b/sys/dev/pci/Makefile index 58345a928a3..d1fde7b90ae 100644 --- a/sys/dev/pci/Makefile +++ b/sys/dev/pci/Makefile @@ -1,11 +1,11 @@ -# $NetBSD: Makefile,v 1.14 2015/03/28 14:41:28 msaitoh Exp $ +# $NetBSD: Makefile,v 1.15 2018/12/12 07:04:05 maxv Exp $ # use 'make -f Makefile.pcidevs' to make pcidevs.h and pcidevs_data.h INCSDIR= /usr/include/dev/pci # Only install includes which are used by userland -INCS= amrreg.h amrio.h if_lmc.h mlyio.h mlyreg.h \ +INCS= amrreg.h amrio.h mlyio.h mlyreg.h \ pcidevs.h pcidevs_data.h pciio.h pcireg.h \ tgareg.h twereg.h tweio.h diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 9da8dc86956..74726789450 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $NetBSD: files.pci,v 1.411 2018/12/07 09:36:26 msaitoh Exp $ +# $NetBSD: files.pci,v 1.412 2018/12/12 07:04:05 maxv Exp $ # # Config file and device description for machine-independent PCI code. # Included by ports that need it. Requires that the SCSI files be @@ -426,11 +426,6 @@ file dev/pci/if_tl.c tl attach ntwoc at pci with ntwoc_pci file dev/pci/if_ntwoc_pci.c ntwoc_pci -# Lan Media Corporation T1/HSSI/DS3 driver -device lmc: ifnet, sppp -attach lmc at pci -file dev/pci/if_lmc.c lmc - # Essential Communications HIPPI interface # device declaration in sys/conf/files attach esh at pci with esh_pci diff --git a/sys/dev/pci/if_lmc.c b/sys/dev/pci/if_lmc.c deleted file mode 100644 index 14173c6311b..00000000000 --- a/sys/dev/pci/if_lmc.c +++ /dev/null @@ -1,5531 +0,0 @@ -/* $NetBSD: if_lmc.c,v 1.68 2018/12/09 11:14:02 jdolecek Exp $ */ - -/*- - * Copyright (c) 2002-2006 David Boggs. <boggs@boggs.palo-alto.ca.us> - * All rights reserved. - * - * BSD LICENSE: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * GNU GENERAL PUBLIC LICENSE: - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * DESCRIPTION: - * - * This is an open-source Unix device driver for PCI-bus WAN interface cards. - * It sends and receives packets in HDLC frames over synchronous links. - * A generic PC plus Unix plus some LMC cards makes an OPEN router. - * This driver works with FreeBSD, NetBSD, OpenBSD, BSD/OS and Linux. - * It has been tested on i386 (32-bit little-end), PowerPC (32-bit - * big-end), Sparc (64-bit big-end), and Alpha (64-bit little-end) - * architectures. - * - * HISTORY AND AUTHORS: - * - * Ron Crane had the neat idea to use a Fast Ethernet chip as a PCI - * interface and add an Ethernet-to-HDLC gate array to make a WAN card. - * David Boggs designed the Ethernet-to-HDLC gate arrays and PC cards. - * We did this at our company, LAN Media Corporation (LMC). - * SBE Corp aquired LMC and continues to make the cards. - * - * Since the cards use Tulip Ethernet chips, we started with Matt Thomas' - * ubiquitous "de" driver. Michael Graff stripped out the Ethernet stuff - * and added HSSI stuff. Basil Gunn ported it to Solaris (lost) and - * Rob Braun ported it to Linux. Andrew Stanley-Jones added support - * for three more cards and wrote the first version of lmcconfig. - * During 2002-5 David Boggs rewrote it and now feels responsible for it. - * - * RESPONSIBLE INDIVIDUAL: - * - * Send bug reports and improvements to <boggs@boggs.palo-alto.ca.us>. - */ - -# include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_lmc.c,v 1.68 2018/12/09 11:14:02 jdolecek Exp $"); -# include <sys/param.h> /* OS version */ -# include "opt_inet.h" /* INET6, INET */ -# include "opt_altq_enabled.h" /* ALTQ */ -# define IOREF_CSR 1 /* 1=IO refs; 0=MEM refs */ -# define IFNET 1 -# define NETDEV 0 -# define NAPI 0 -# define SPPP 1 -# define P2P 0 -# define GEN_HDLC 0 -# define SYNC_PPP 0 -# define NETGRAPH 0 -# define DEVICE_POLLING 0 -# -# include <sys/systm.h> -# include <sys/kernel.h> -# include <sys/module.h> -# include <sys/mbuf.h> -# include <sys/socket.h> -# include <sys/sockio.h> -# include <sys/device.h> -# include <sys/reboot.h> -# include <sys/kauth.h> -# include <sys/proc.h> -# include <net/if.h> -# include <net/if_types.h> -# include <net/if_media.h> -# include <net/netisr.h> -# include <sys/bus.h> -# include <sys/intr.h> -# include <machine/lock.h> -# include <machine/types.h> -# include <dev/pci/pcivar.h> -# if INET || INET6 -# include <netinet/in.h> -# include <netinet/in_var.h> -# endif -# if SPPP -# include <net/if_spppvar.h> -# endif -# include <net/bpf.h> -# if !defined(ALTQ) -# define ALTQ 0 -# endif -/* and finally... */ -# include "if_lmc.h" - - - - -/* The SROM is a generic 93C46 serial EEPROM (64 words by 16 bits). */ -/* Data is set up before the RISING edge of CLK; CLK is parked low. */ -static void /* context: process */ -srom_shift_bits(softc_t *sc, u_int32_t data, u_int32_t len) - { - u_int32_t csr = READ_CSR(sc, TLP_SROM_MII); - for (; len>0; len--) - { /* MSB first */ - if (data & (1<<(len-1))) - csr |= TLP_SROM_DIN; /* DIN setup */ - else - csr &= ~TLP_SROM_DIN; /* DIN setup */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr |= TLP_SROM_CLK; /* CLK rising edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr &= ~TLP_SROM_CLK; /* CLK falling edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - } - } - -/* Data is sampled on the RISING edge of CLK; CLK is parked low. */ -static u_int16_t /* context: process */ -srom_read(softc_t *sc, u_int8_t addr) - { - int i; - u_int32_t csr; - u_int16_t data; - - /* Enable SROM access. */ - csr = (TLP_SROM_SEL | TLP_SROM_RD | TLP_MII_MDOE); - WRITE_CSR(sc, TLP_SROM_MII, csr); - /* CS rising edge prepares SROM for a new cycle. */ - csr |= TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* assert CS */ - srom_shift_bits(sc, 6, 4); /* issue read cmd */ - srom_shift_bits(sc, addr, 6); /* issue address */ - for (data=0, i=16; i>=0; i--) /* read ->17<- bits of data */ - { /* MSB first */ - csr = READ_CSR(sc, TLP_SROM_MII); /* DOUT sampled */ - data = (data<<1) | ((csr & TLP_SROM_DOUT) ? 1:0); - csr |= TLP_SROM_CLK; /* CLK rising edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr &= ~TLP_SROM_CLK; /* CLK falling edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - } - /* Disable SROM access. */ - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOE); - - return data; - } - -/* The SROM is formatted by the mfgr and should NOT be written! */ -/* But lmcconfig can rewrite it in case it gets overwritten somehow. */ -static void /* context: process */ -srom_write(softc_t *sc, u_int8_t addr, u_int16_t data) - { - u_int32_t csr; - int i; - - /* Enable SROM access. */ - csr = (TLP_SROM_SEL | TLP_SROM_RD | TLP_MII_MDOE); - WRITE_CSR(sc, TLP_SROM_MII, csr); - - /* Issue write-enable command. */ - csr |= TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* assert CS */ - srom_shift_bits(sc, 4, 4); /* issue write enable cmd */ - srom_shift_bits(sc, 63, 6); /* issue address */ - csr &= ~TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* deassert CS */ - - /* Issue erase command. */ - csr |= TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* assert CS */ - srom_shift_bits(sc, 7, 4); /* issue erase cmd */ - srom_shift_bits(sc, addr, 6); /* issue address */ - csr &= ~TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* deassert CS */ - - /* Issue write command. */ - csr |= TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* assert CS */ - for (i=0; i<10; i++) /* 100 ms max wait */ - if ((READ_CSR(sc, TLP_SROM_MII) & TLP_SROM_DOUT)==0) SLEEP(10000); - srom_shift_bits(sc, 5, 4); /* issue write cmd */ - srom_shift_bits(sc, addr, 6); /* issue address */ - srom_shift_bits(sc, data, 16); /* issue data */ - csr &= ~TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* deassert CS */ - - /* Issue write-disable command. */ - csr |= TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* assert CS */ - for (i=0; i<10; i++) /* 100 ms max wait */ - if ((READ_CSR(sc, TLP_SROM_MII) & TLP_SROM_DOUT)==0) SLEEP(10000); - srom_shift_bits(sc, 4, 4); /* issue write disable cmd */ - srom_shift_bits(sc, 0, 6); /* issue address */ - csr &= ~TLP_SROM_CS; - WRITE_CSR(sc, TLP_SROM_MII, csr); /* deassert CS */ - - /* Disable SROM access. */ - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOE); - } - -/* Not all cards have BIOS roms. */ -/* The BIOS ROM is an AMD 29F010 1Mbit (128K by 8) EEPROM. */ -static u_int8_t /* context: process */ -bios_read(softc_t *sc, u_int32_t addr) - { - u_int32_t srom_mii; - - /* Load the BIOS rom address register. */ - WRITE_CSR(sc, TLP_BIOS_ROM, addr); - - /* Enable the BIOS rom. */ - srom_mii = TLP_BIOS_SEL | TLP_BIOS_RD | TLP_MII_MDOE; - WRITE_CSR(sc, TLP_SROM_MII, srom_mii); - - /* Wait at least 20 PCI cycles. */ - DELAY(20); - - /* Read the BIOS rom data. */ - srom_mii = READ_CSR(sc, TLP_SROM_MII); - - /* Disable the BIOS rom. */ - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOE); - - return (u_int8_t)srom_mii & 0xFF; - } - -static void /* context: process */ -bios_write_phys(softc_t *sc, u_int32_t addr, u_int8_t data) - { - u_int32_t srom_mii; - - /* Load the BIOS rom address register. */ - WRITE_CSR(sc, TLP_BIOS_ROM, addr); - - /* Enable the BIOS rom. */ - srom_mii = TLP_BIOS_SEL | TLP_BIOS_WR | TLP_MII_MDOE; - - /* Load the data into the data register. */ - srom_mii = (srom_mii & 0xFFFFFF00) | (data & 0xFF); - WRITE_CSR(sc, TLP_SROM_MII, srom_mii); - - /* Wait at least 20 PCI cycles. */ - DELAY(20); - - /* Disable the BIOS rom. */ - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOE); - } - -static void /* context: process */ -bios_write(softc_t *sc, u_int32_t addr, u_int8_t data) - { - u_int8_t read_data; - - /* this sequence enables writing */ - bios_write_phys(sc, 0x5555, 0xAA); - bios_write_phys(sc, 0x2AAA, 0x55); - bios_write_phys(sc, 0x5555, 0xA0); - bios_write_phys(sc, addr, data); - - /* Wait for the write operation to complete. */ - for (;;) /* interruptible syscall */ - { - for (;;) - { - read_data = bios_read(sc, addr); - if ((read_data & 0x80) == (data & 0x80)) break; - if (read_data & 0x20) - { /* Data sheet says read it again. */ - read_data = bios_read(sc, addr); - if ((read_data & 0x80) == (data & 0x80)) break; - if (sc->config.debug) - printf("%s: bios_write() failed; rom addr=0x%x\n", - NAME_UNIT, addr); - return; - } - } - read_data = bios_read(sc, addr); - if (read_data == data) break; - } - } - -static void /* context: process */ -bios_erase(softc_t *sc) - { - unsigned char read_data; - - /* This sequence enables erasing: */ - bios_write_phys(sc, 0x5555, 0xAA); - bios_write_phys(sc, 0x2AAA, 0x55); - bios_write_phys(sc, 0x5555, 0x80); - bios_write_phys(sc, 0x5555, 0xAA); - bios_write_phys(sc, 0x2AAA, 0x55); - bios_write_phys(sc, 0x5555, 0x10); - - /* Wait for the erase operation to complete. */ - for (;;) /* interruptible syscall */ - { - for (;;) - { - read_data = bios_read(sc, 0); - if (read_data & 0x80) break; - if (read_data & 0x20) - { /* Data sheet says read it again. */ - read_data = bios_read(sc, 0); - if (read_data & 0x80) break; - if (sc->config.debug) - printf("%s: bios_erase() failed\n", NAME_UNIT); - return; - } - } - read_data = bios_read(sc, 0); - if (read_data == 0xFF) break; - } - } - -/* MDIO is 3-stated between tranactions. */ -/* MDIO is set up before the RISING edge of MDC; MDC is parked low. */ -static void /* context: process */ -mii_shift_bits(softc_t *sc, u_int32_t data, u_int32_t len) - { - u_int32_t csr = READ_CSR(sc, TLP_SROM_MII); - for (; len>0; len--) - { /* MSB first */ - if (data & (1<<(len-1))) - csr |= TLP_MII_MDOUT; /* MDOUT setup */ - else - csr &= ~TLP_MII_MDOUT; /* MDOUT setup */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr |= TLP_MII_MDC; /* MDC rising edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr &= ~TLP_MII_MDC; /* MDC falling edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - } - } - -/* The specification for the MII is IEEE Std 802.3 clause 22. */ -/* MDIO is sampled on the RISING edge of MDC; MDC is parked low. */ -static u_int16_t /* context: process */ -mii_read(softc_t *sc, u_int8_t regad) - { - int i; - u_int32_t csr; - u_int16_t data = 0; - - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOUT); - - mii_shift_bits(sc, 0xFFFFF, 20); /* preamble */ - mii_shift_bits(sc, 0xFFFFF, 20); /* preamble */ - mii_shift_bits(sc, 1, 2); /* start symbol */ - mii_shift_bits(sc, 2, 2); /* read op */ - mii_shift_bits(sc, 0, 5); /* phyad=0 */ - mii_shift_bits(sc, regad, 5); /* regad */ - csr = READ_CSR(sc, TLP_SROM_MII); - csr |= TLP_MII_MDOE; - WRITE_CSR(sc, TLP_SROM_MII, csr); - mii_shift_bits(sc, 0, 2); /* turn-around */ - for (i=15; i>=0; i--) /* data */ - { /* MSB first */ - csr = READ_CSR(sc, TLP_SROM_MII); /* MDIN sampled */ - data = (data<<1) | ((csr & TLP_MII_MDIN) ? 1:0); - csr |= TLP_MII_MDC; /* MDC rising edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - csr &= ~TLP_MII_MDC; /* MDC falling edge */ - WRITE_CSR(sc, TLP_SROM_MII, csr); - } - return data; - } - -static void /* context: process */ -mii_write(softc_t *sc, u_int8_t regad, u_int16_t data) - { - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOUT); - mii_shift_bits(sc, 0xFFFFF, 20); /* preamble */ - mii_shift_bits(sc, 0xFFFFF, 20); /* preamble */ - mii_shift_bits(sc, 1, 2); /* start symbol */ - mii_shift_bits(sc, 1, 2); /* write op */ - mii_shift_bits(sc, 0, 5); /* phyad=0 */ - mii_shift_bits(sc, regad, 5); /* regad */ - mii_shift_bits(sc, 2, 2); /* turn-around */ - mii_shift_bits(sc, data, 16); /* data */ - WRITE_CSR(sc, TLP_SROM_MII, TLP_MII_MDOE); - if (regad == 16) sc->led_state = data; /* a small optimization */ - } - -static void -mii16_set_bits(softc_t *sc, u_int16_t bits) - { - u_int16_t mii16 = mii_read(sc, 16); - mii16 |= bits; - mii_write(sc, 16, mii16); - } - -static void -mii16_clr_bits(softc_t *sc, u_int16_t bits) - { - u_int16_t mii16 = mii_read(sc, 16); - mii16 &= ~bits; - mii_write(sc, 16, mii16); - } - -static void -mii17_set_bits(softc_t *sc, u_int16_t bits) - { - u_int16_t mii17 = mii_read(sc, 17); - mii17 |= bits; - mii_write(sc, 17, mii17); - } - -static void -mii17_clr_bits(softc_t *sc, u_int16_t bits) - { - u_int16_t mii17 = mii_read(sc, 17); - mii17 &= ~bits; - mii_write(sc, 17, mii17); - } - -/* - * Watchdog code is more readable if it refreshes LEDs - * once a second whether they need it or not. - * But MII refs take 150 uSecs each, so remember the last value - * written to MII16 and avoid LED writes that do nothing. - */ - -static void -led_off(softc_t *sc, u_int16_t led) - { - if ((led & sc->led_state) == led) return; - mii16_set_bits(sc, led); - } - -static void -led_on(softc_t *sc, u_int16_t led) - { - if ((led & sc->led_state) == 0) return; - mii16_clr_bits(sc, led); - } - -static void -led_inv(softc_t *sc, u_int16_t led) - { - u_int16_t mii16 = mii_read(sc, 16); - mii16 ^= led; - mii_write(sc, 16, mii16); - } - -/* - * T1 & T3 framer registers are accessed through MII regs 17 & 18. - * Write the address to MII reg 17 then R/W data through MII reg 18. - * The hardware interface is an Intel-style 8-bit muxed A/D bus. - */ -static void -framer_write(softc_t *sc, u_int16_t addr, u_int8_t data) - { - mii_write(sc, 17, addr); - mii_write(sc, 18, data); - } - -static u_int8_t -framer_read(softc_t *sc, u_int16_t addr) - { - mii_write(sc, 17, addr); - return (u_int8_t)mii_read(sc, 18); - } - -/* Tulip's hardware implementation of General Purpose IO - * (GPIO) pins makes life difficult for software. - * Bits 7-0 in the Tulip GPIO CSR are used for two purposes - * depending on the state of bit 8. - * If bit 8 is 0 then bits 7-0 are "data" bits. - * If bit 8 is 1 then bits 7-0 are "direction" bits. - * If a direction bit is one, the data bit is an output. - * The problem is that the direction bits are WRITE-ONLY. - * Software must remember the direction bits in a shadow copy. - * (sc->gpio_dir) in order to change some but not all of the bits. - * All accesses to the Tulip GPIO register use these five procedures. - */ - -static void -gpio_make_input(softc_t *sc, u_int32_t bits) - { - sc->gpio_dir &= ~bits; - WRITE_CSR(sc, TLP_GPIO, TLP_GPIO_DIR | (sc->gpio_dir)); - } - -static void -gpio_make_output(softc_t *sc, u_int32_t bits) - { - sc->gpio_dir |= bits; - WRITE_CSR(sc, TLP_GPIO, TLP_GPIO_DIR | (sc->gpio_dir)); - } - -static u_int32_t -gpio_read(softc_t *sc) - { - return READ_CSR(sc, TLP_GPIO); - } - -static void -gpio_set_bits(softc_t *sc, u_int32_t bits) - { - WRITE_CSR(sc, TLP_GPIO, (gpio_read(sc) | bits) & 0xFF); - } - -static void -gpio_clr_bits(softc_t *sc, u_int32_t bits) - { - WRITE_CSR(sc, TLP_GPIO, (gpio_read(sc) & ~bits) & 0xFF); - } - -/* Reset ALL of the flip-flops in the gate array to zero. */ -/* This does NOT change the gate array programming. */ -/* Called during initialization so it must not sleep. */ -static void /* context: kernel (boot) or process (syscall) */ -xilinx_reset(softc_t *sc) - { - /* Drive RESET low to force initialization. */ - gpio_clr_bits(sc, GPIO_RESET); - gpio_make_output(sc, GPIO_RESET); - - /* Hold RESET low for more than 10 uSec. */ - DELAY(50); - - /* Done with RESET; make it an input. */ - gpio_make_input(sc, GPIO_RESET); - } - -/* Load Xilinx gate array program from on-board rom. */ -/* This changes the gate array programming. */ -static void /* context: process */ -xilinx_load_from_rom(softc_t *sc) - { - int i; - - /* Drive MODE low to load from ROM rather than GPIO. */ - gpio_clr_bits(sc, GPIO_MODE); - gpio_make_output(sc, GPIO_MODE); - - /* Drive DP & RESET low to force configuration. */ - gpio_clr_bits(sc, GPIO_RESET | GPIO_DP); - gpio_make_output(sc, GPIO_RESET | GPIO_DP); - - /* Hold RESET & DP low for more than 10 uSec. */ - DELAY(50); - - /* Done with RESET & DP; make them inputs. */ - gpio_make_input(sc, GPIO_DP | GPIO_RESET); - - /* BUSY-WAIT for Xilinx chip to configure itself from ROM bits. */ - for (i=0; i<100; i++) /* 1 sec max delay */ - if ((gpio_read(sc) & GPIO_DP)==0) SLEEP(10000); - - /* Done with MODE; make it an input. */ - gpio_make_input(sc, GPIO_MODE); - } - -/* Load the Xilinx gate array program from userland bits. */ -/* This changes the gate array programming. */ -static int /* context: process */ -xilinx_load_from_file(softc_t *sc, char *addr, u_int32_t len) - { - char *data; - int i, j, error; - - /* Get some pages to hold the Xilinx bits; biggest file is < 6 KB. */ - if (len > 8192) return EFBIG; /* too big */ - data = malloc(len, M_TEMP, M_WAITOK); - if (data == NULL) return ENOMEM; - - /* Copy the Xilinx bits from userland. */ - if ((error = copyin(addr, data, len))) - { - free(data, M_TEMP); - return error; - } - - /* Drive MODE high to load from GPIO rather than ROM. */ - gpio_set_bits(sc, GPIO_MODE); - gpio_make_output(sc, GPIO_MODE); - - /* Drive DP & RESET low to force configuration. */ - gpio_clr_bits(sc, GPIO_RESET | GPIO_DP); - gpio_make_output(sc, GPIO_RESET | GPIO_DP); - - /* Hold RESET & DP low for more than 10 uSec. */ - DELAY(50); - - /* Done with RESET & DP; make them inputs. */ - gpio_make_input(sc, GPIO_RESET | GPIO_DP); - - /* BUSY-WAIT for Xilinx chip to clear its config memory. */ - gpio_make_input(sc, GPIO_INIT); - for (i=0; i<10000; i++) /* 1 sec max delay */ - if ((gpio_read(sc) & GPIO_INIT)==0) SLEEP(10000); - - /* Configure CLK and DATA as outputs. */ - gpio_set_bits(sc, GPIO_CLK); /* park CLK high */ - gpio_make_output(sc, GPIO_CLK | GPIO_DATA); - - /* Write bits to Xilinx; CLK is parked HIGH. */ - /* DATA is set up before the RISING edge of CLK. */ - for (i=0; i<len; i++) - for (j=0; j<8; j++) - { /* LSB first */ - if (data[i] & (1<<j)) - gpio_set_bits(sc, GPIO_DATA); /* DATA setup */ - else - gpio_clr_bits(sc, GPIO_DATA); /* DATA setup */ - gpio_clr_bits(sc, GPIO_CLK); /* CLK falling edge */ - gpio_set_bits(sc, GPIO_CLK); /* CLK rising edge */ - } - - /* Stop driving all Xilinx-related signals. */ - /* Pullup and pulldown resistors take over. */ - gpio_make_input(sc, GPIO_CLK | GPIO_DATA | GPIO_MODE); - - free(data, M_TEMP); - - return 0; - } - -/* Write fragments of a command into the synthesized oscillator. */ -/* DATA is set up before the RISING edge of CLK. CLK is parked low. */ -static void -synth_shift_bits(softc_t *sc, u_int32_t data, u_int32_t len) - { - int i; - - for (i=0; i<len; i++) - { /* LSB first */ - if (data & (1<<i)) - gpio_set_bits(sc, GPIO_DATA); /* DATA setup */ - else - gpio_clr_bits(sc, GPIO_DATA); /* DATA setup */ - gpio_set_bits(sc, GPIO_CLK); /* CLK rising edge */ - gpio_clr_bits(sc, GPIO_CLK); /* CLK falling edge */ - } - } - -/* Write a command to the synthesized oscillator on SSI and HSSIc. */ -static void /* context: process */ -synth_write(softc_t *sc, struct synth *synth) - { - /* SSI cards have a programmable prescaler */ - if (sc->status.card_type == CSID_LMC_SSI) - { - if (synth->prescale == 9) /* divide by 512 */ - mii17_set_bits(sc, MII17_SSI_PRESCALE); - else /* divide by 32 */ - mii17_clr_bits(sc, MII17_SSI_PRESCALE); - } - - gpio_clr_bits(sc, GPIO_DATA | GPIO_CLK); - gpio_make_output(sc, GPIO_DATA | GPIO_CLK); - - /* SYNTH is a low-true chip enable for the AV9110 chip. */ - gpio_set_bits(sc, GPIO_SSI_SYNTH); - gpio_make_output(sc, GPIO_SSI_SYNTH); - gpio_clr_bits(sc, GPIO_SSI_SYNTH); - - /* Serially shift the command into the AV9110 chip. */ - synth_shift_bits(sc, synth->n, 7); - synth_shift_bits(sc, synth->m, 7); - synth_shift_bits(sc, synth->v, 1); - synth_shift_bits(sc, synth->x, 2); - synth_shift_bits(sc, synth->r, 2); - synth_shift_bits(sc, 0x16, 5); /* enable clk/x output */ - - /* SYNTH (chip enable) going high ends the command. */ - gpio_set_bits(sc, GPIO_SSI_SYNTH); - gpio_make_input(sc, GPIO_SSI_SYNTH); - - /* Stop driving serial-related signals; pullups/pulldowns take over. */ - gpio_make_input(sc, GPIO_DATA | GPIO_CLK); - - /* remember the new synthesizer parameters */ - if (&sc->config.synth != synth) sc->config.synth = *synth; - } - -/* Write a command to the DAC controlling the VCXO on some T3 adapters. */ -/* The DAC is a TI-TLV5636: 12-bit resolution and a serial interface. */ -/* DATA is set up before the FALLING edge of CLK. CLK is parked HIGH. */ -static void /* context: process */ -dac_write(softc_t *sc, u_int16_t data) - { - int i; - - /* Prepare to use DATA and CLK. */ - gpio_set_bits(sc, GPIO_DATA | GPIO_CLK); - gpio_make_output(sc, GPIO_DATA | GPIO_CLK); - - /* High-to-low transition prepares DAC for new value. */ - gpio_set_bits(sc, GPIO_T3_DAC); - gpio_make_output(sc, GPIO_T3_DAC); - gpio_clr_bits(sc, GPIO_T3_DAC); - - /* Serially shift command bits into DAC. */ - for (i=0; i<16; i++) - { /* MSB first */ - if (data & (1<<(15-i))) - gpio_set_bits(sc, GPIO_DATA); /* DATA setup */ - else - gpio_clr_bits(sc, GPIO_DATA); /* DATA setup */ - gpio_clr_bits(sc, GPIO_CLK); /* CLK falling edge */ - gpio_set_bits(sc, GPIO_CLK); /* CLK rising edge */ - } - - /* Done with DAC; make it an input; loads new value into DAC. */ - gpio_set_bits(sc, GPIO_T3_DAC); - gpio_make_input(sc, GPIO_T3_DAC); - - /* Stop driving serial-related signals; pullups/pulldowns take over. */ - gpio_make_input(sc, GPIO_DATA | GPIO_CLK); - } - -/* Begin HSSI card code */ - -static struct card hssi_card = - { - .ident = hssi_ident, - .watchdog = hssi_watchdog, - .ioctl = hssi_ioctl, - .attach = hssi_attach, - .detach = hssi_detach, - }; - -static void -hssi_ident(softc_t *sc) - { - printf(", EIA-613"); - } - -static void /* context: softirq */ -hssi_watchdog(softc_t *sc) - { - u_int16_t mii16 = mii_read(sc, 16) & MII16_HSSI_MODEM; - - sc->status.link_state = STATE_UP; - - led_inv(sc, MII16_HSSI_LED_UL); /* Software is alive. */ - led_on(sc, MII16_HSSI_LED_LL); /* always on (SSI cable) */ - - /* Check the transmit clock. */ - if (sc->status.tx_speed == 0) - { - led_on(sc, MII16_HSSI_LED_UR); - sc->status.link_state = STATE_DOWN; - } - else - led_off(sc, MII16_HSSI_LED_UR); - - /* Is the modem ready? */ - if ((mii16 & MII16_HSSI_CA)==0) - { - led_off(sc, MII16_HSSI_LED_LR); - sc->status.link_state = STATE_DOWN; - } - else - led_on(sc, MII16_HSSI_LED_LR); - - /* Print the modem control signals if they changed. */ - if ((sc->config.debug) && (mii16 != sc->last_mii16)) - { - const char *on = "ON ", *off = "OFF"; - printf("%s: TA=%s CA=%s LA=%s LB=%s LC=%s TM=%s\n", NAME_UNIT, - (mii16 & MII16_HSSI_TA) ? on : off, - (mii16 & MII16_HSSI_CA) ? on : off, - (mii16 & MII16_HSSI_LA) ? on : off, - (mii16 & MII16_HSSI_LB) ? on : off, - (mii16 & MII16_HSSI_LC) ? on : off, - (mii16 & MII16_HSSI_TM) ? on : off); - } - - /* SNMP one-second-report */ - sc->status.snmp.hssi.sigs = mii16 & MII16_HSSI_MODEM; - - /* Remember this state until next time. */ - sc->last_mii16 = mii16; - - /* If a loop back is in effect, link status is UP */ - if (sc->config.loop_back != CFG_LOOP_NONE) - sc->status.link_state = STATE_UP; - } - -static int /* context: process */ -hssi_ioctl(softc_t *sc, struct ioctl *ioctl) - { - int error = 0; - - if (ioctl->cmd == IOCTL_SNMP_SIGS) - { - u_int16_t mii16 = mii_read(sc, 16); - mii16 &= ~MII16_HSSI_MODEM; - mii16 |= (MII16_HSSI_MODEM & ioctl->data); - mii_write(sc, 16, mii16); - } - else if (ioctl->cmd == IOCTL_SET_STATUS) - { - if (ioctl->data) - mii16_set_bits(sc, MII16_HSSI_TA); - else - mii16_clr_bits(sc, MII16_HSSI_TA); - } - else - error = EINVAL; - - return error; - } - -/* Must not sleep. */ -static void -hssi_attach(softc_t *sc, struct config *config) - { - if (config == NULL) /* startup config */ - { - sc->status.card_type = READ_PCI_CFG(sc, TLP_CSID); - sc->config.crc_len = CFG_CRC_16; - sc->config.loop_back = CFG_LOOP_NONE; - sc->config.tx_clk_src = CFG_CLKMUX_ST; - sc->config.dte_dce = CFG_DTE; - sc->config.synth.n = 52; /* 52.000 Mbs */ - sc->config.synth.m = 5; - sc->config.synth.v = 0; - sc->config.synth.x = 0; - sc->config.synth.r = 0; - sc->config.synth.prescale = 2; - } - else if (config != &sc->config) /* change config */ - { - u_int32_t *old_synth = (u_int32_t *)&sc->config.synth; - u_int32_t *new_synth = (u_int32_t *)&config->synth; - if ((sc->config.crc_len == config->crc_len) && - (sc->config.loop_back == config->loop_back) && - (sc->config.tx_clk_src == config->tx_clk_src) && - (sc->config.dte_dce == config->dte_dce) && - (*old_synth == *new_synth)) - return; /* nothing changed */ - sc->config.crc_len = config->crc_len; - sc->config.loop_back = config->loop_back; - sc->config.tx_clk_src = config->tx_clk_src; - sc->config.dte_dce = config->dte_dce; - *old_synth = *new_synth; - } - /* If (config == &sc->config) then the FPGA microcode - * was just initialized and the current config should - * be reloaded into the card. - */ - - /* set CRC length */ - if (sc->config.crc_len == CFG_CRC_32) - mii16_set_bits(sc, MII16_HSSI_CRC32); - else - mii16_clr_bits(sc, MII16_HSSI_CRC32); - - /* Assert pin LA in HSSI conn: ask modem for local loop. */ - if (sc->config.loop_back == CFG_LOOP_LL) - mii16_set_bits(sc, MII16_HSSI_LA); - else - mii16_clr_bits(sc, MII16_HSSI_LA); - - /* Assert pin LB in HSSI conn: ask modem for remote loop. */ - if (sc->config.loop_back == CFG_LOOP_RL) - mii16_set_bits(sc, MII16_HSSI_LB); - else - mii16_clr_bits(sc, MII16_HSSI_LB); - - if (sc->status.card_type == CSID_LMC_HSSI) - { - /* set TXCLK src */ - if (sc->config.tx_clk_src == CFG_CLKMUX_ST) - gpio_set_bits(sc, GPIO_HSSI_TXCLK); - else - gpio_clr_bits(sc, GPIO_HSSI_TXCLK); - gpio_make_output(sc, GPIO_HSSI_TXCLK); - } - else if (sc->status.card_type == CSID_LMC_HSSIc) - { /* cPCI HSSI rev C has extra features */ - /* Set TXCLK source. */ - u_int16_t mii16 = mii_read(sc, 16); - mii16 &= ~MII16_HSSI_CLKMUX; - mii16 |= (sc->config.tx_clk_src&3)<<13; - mii_write(sc, 16, mii16); - - /* cPCI HSSI implements loopback towards the net. */ - if (sc->config.loop_back == CFG_LOOP_LINE) - mii16_set_bits(sc, MII16_HSSI_LOOP); - else - mii16_clr_bits(sc, MII16_HSSI_LOOP); - - /* Set DTE/DCE mode. */ - if (sc->config.dte_dce == CFG_DCE) - gpio_set_bits(sc, GPIO_HSSI_DCE); - else - gpio_clr_bits(sc, GPIO_HSSI_DCE); - gpio_make_output(sc, GPIO_HSSI_DCE); - - /* Program the synthesized oscillator. */ - synth_write(sc, &sc->config.synth); - } - } - -static void -hssi_detach(softc_t *sc) - { - mii16_clr_bits(sc, MII16_HSSI_TA); - led_on(sc, MII16_LED_ALL); - } - -/* End HSSI card code */ - -/* Begin DS3 card code */ - -static struct card t3_card = - { - .ident = t3_ident, - .watchdog = t3_watchdog, - .ioctl = t3_ioctl, - .attach = t3_attach, - .detach = t3_detach, - }; - -static void -t3_ident(softc_t *sc) - { - printf(", TXC03401 rev B"); - } - -static void /* context: softirq */ -t3_watchdog(softc_t *sc) - { - u_int16_t CV; - u_int8_t CERR, PERR, MERR, FERR, FEBE; - u_int8_t ctl1, stat16, feac; - u_int16_t mii16; - - sc->status.link_state = STATE_UP; - - /* Read the alarm registers. */ - ctl1 = framer_read(sc, T3CSR_CTL1); - stat16 = framer_read(sc, T3CSR_STAT16); - mii16 = mii_read(sc, 16); - - /* Always ignore the RTLOC alarm bit. */ - stat16 &= ~STAT16_RTLOC; - - /* Software is alive. */ - led_inv(sc, MII16_DS3_LED_GRN); - - /* Receiving Alarm Indication Signal (AIS). */ - if (stat16 & STAT16_RAIS) /* receiving ais */ - led_on(sc, MII16_DS3_LED_BLU); - else if (ctl1 & CTL1_TXAIS) /* sending ais */ - led_inv(sc, MII16_DS3_LED_BLU); - else - led_off(sc, MII16_DS3_LED_BLU); - - /* Receiving Remote Alarm Indication (RAI). */ - if (stat16 & STAT16_XERR) /* receiving rai */ - led_on(sc, MII16_DS3_LED_YEL); - else if ((ctl1 & CTL1_XTX) == 0) /* sending rai */ - led_inv(sc, MII16_DS3_LED_YEL); - else - led_off(sc, MII16_DS3_LED_YEL); - - /* If certain status bits are set then the link is 'down'. */ - /* The bad bits are: rxlos rxoof rxais rxidl xerr. */ - if (stat16 & ~(STAT16_FEAC | STAT16_SEF)) - sc->status.link_state = STATE_DOWN; - - /* Declare local Red Alarm if the link is down. */ - if (sc->status.link_state == STATE_DOWN) - led_on(sc, MII16_DS3_LED_RED); - else if (sc->loop_timer) /* loopback is active */ - led_inv(sc, MII16_DS3_LED_RED); - else - led_off(sc, MII16_DS3_LED_RED); - - /* Print latched error bits if they changed. */ - if ((sc->config.debug) && ((stat16 & ~STAT16_FEAC) != sc->last_stat16)) - { - const char *on = "ON ", *off = "OFF"; - printf("%s: RLOS=%s ROOF=%s RAIS=%s RIDL=%s SEF=%s XERR=%s\n", - NAME_UNIT, - (stat16 & STAT16_RLOS) ? on : off, - (stat16 & STAT16_ROOF) ? on : off, - (stat16 & STAT16_RAIS) ? on : off, - (stat16 & STAT16_RIDL) ? on : off, - (stat16 & STAT16_SEF) ? on : off, - (stat16 & STAT16_XERR) ? on : off); - } - - /* Check and print error counters if non-zero. */ - CV = framer_read(sc, T3CSR_CVHI)<<8; - CV += framer_read(sc, T3CSR_CVLO); - PERR = framer_read(sc, T3CSR_PERR); - CERR = framer_read(sc, T3CSR_CERR); - FERR = framer_read(sc, T3CSR_FERR); - MERR = framer_read(sc, T3CSR_MERR); - FEBE = framer_read(sc, T3CSR_FEBE); - - /* CV is invalid during LOS. */ - if (stat16 & STAT16_RLOS) CV = 0; - /* CERR & FEBE are invalid in M13 mode */ - if (sc->config.format == CFG_FORMAT_T3M13) CERR = FEBE = 0; - /* FEBE is invalid during AIS. */ - if (stat16 & STAT16_RAIS) FEBE = 0; - if (sc->config.debug && (CV || PERR || CERR || FERR || MERR || FEBE)) - printf("%s: CV=%u PERR=%u CERR=%u FERR=%u MERR=%u FEBE=%u\n", - NAME_UNIT, CV, PERR, CERR, FERR, MERR, FEBE); - - /* Driver keeps crude link-level error counters (SNMP is better). */ - sc->status.cntrs.lcv_errs += CV; - sc->status.cntrs.par_errs += PERR; - sc->status.cntrs.cpar_errs += CERR; - sc->status.cntrs.frm_errs += FERR; - sc->status.cntrs.mfrm_errs += MERR; - sc->status.cntrs.febe_errs += FEBE; - - /* Check for FEAC messages (FEAC not defined in M13 mode). */ - if (FORMAT_T3CPAR && (stat16 & STAT16_FEAC)) do - { - feac = framer_read(sc, T3CSR_FEAC_STK); - if ((feac & FEAC_STK_VALID)==0) break; - /* Ignore RxFEACs while a far end loopback has been requested. */ - if (sc->status.snmp.t3.line & TLOOP_FAR_LINE) continue; - switch (feac & FEAC_STK_FEAC) - { - case T3BOP_LINE_UP: break; - case T3BOP_LINE_DOWN: break; - case T3BOP_LOOP_DS3: - { - if (sc->last_FEAC == T3BOP_LINE_DOWN) - { - if (sc->config.debug) - printf("%s: Received a 'line loopback deactivate' FEAC msg\n", NAME_UNIT); - mii16_clr_bits(sc, MII16_DS3_LNLBK); - sc->loop_timer = 0; - } - if (sc->last_FEAC == T3BOP_LINE_UP) - { - if (sc->config.debug) - printf("%s: Received a 'line loopback activate' FEAC msg\n", NAME_UNIT); - mii16_set_bits(sc, MII16_DS3_LNLBK); - sc->loop_timer = 300; - } - break; - } - case T3BOP_OOF: - { - if (sc->config.debug) - printf("%s: Received a 'far end LOF' FEAC msg\n", NAME_UNIT); - break; - } - case T3BOP_IDLE: - { - if (sc->config.debug) - printf("%s: Received a 'far end IDL' FEAC msg\n", NAME_UNIT); - break; - } - case T3BOP_AIS: - { - if (sc->config.debug) - printf("%s: Received a 'far end AIS' FEAC msg\n", NAME_UNIT); - break; - } - case T3BOP_LOS: - { - if (sc->config.debug) - printf("%s: Received a 'far end LOS' FEAC msg\n", NAME_UNIT); - break; - } - default: - { - if (sc->config.debug) - printf("%s: Received a 'type 0x%02X' FEAC msg\n", NAME_UNIT, feac & FEAC_STK_FEAC); - break; - } - } - sc->last_FEAC = feac & FEAC_STK_FEAC; - } while (feac & FEAC_STK_MORE); - stat16 &= ~STAT16_FEAC; - - /* Send Service-Affecting priority FEAC messages */ - if (((sc->last_stat16 ^ stat16) & 0xF0) && (FORMAT_T3CPAR)) - { - /* Transmit continuous FEACs */ - framer_write(sc, T3CSR_CTL14, - framer_read(sc, T3CSR_CTL14) & ~CTL14_FEAC10); - if (stat16 & STAT16_RLOS) - framer_write(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_LOS); - else if (stat16 & STAT16_ROOF) - framer_write(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_OOF); - else if (stat16 & STAT16_RAIS) - framer_write(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_AIS); - else if (stat16 & STAT16_RIDL) - framer_write(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_IDLE); - else - framer_write(sc, T3CSR_TX_FEAC, CTL5_EMODE); - } - - /* Start sending RAI, Remote Alarm Indication. */ - if ((stat16 & STAT16_ROOF) && !(stat16 & STAT16_RLOS) && - !(sc->last_stat16 & STAT16_ROOF)) - framer_write(sc, T3CSR_CTL1, ctl1 &= ~CTL1_XTX); - /* Stop sending RAI, Remote Alarm Indication. */ - else if (!(stat16 & STAT16_ROOF) && (sc->last_stat16 & STAT16_ROOF)) - framer_write(sc, T3CSR_CTL1, ctl1 |= CTL1_XTX); - - /* Start sending AIS, Alarm Indication Signal */ - if ((stat16 & STAT16_RLOS) && !(sc->last_stat16 & STAT16_RLOS)) - { - mii16_set_bits(sc, MII16_DS3_FRAME); - framer_write(sc, T3CSR_CTL1, ctl1 | CTL1_TXAIS); - } - /* Stop sending AIS, Alarm Indication Signal */ - else if (!(stat16 & STAT16_RLOS) && (sc->last_stat16 & STAT16_RLOS)) - { - mii16_clr_bits(sc, MII16_DS3_FRAME); - framer_write(sc, T3CSR_CTL1, ctl1 & ~CTL1_TXAIS); - } - - /* Time out loopback requests. */ - if (sc->loop_timer) - if (--sc->loop_timer == 0) - if (mii16 & MII16_DS3_LNLBK) - { - if (sc->config.debug) - printf("%s: Timeout: Loop Down after 300 seconds\n", NAME_UNIT); - mii16_clr_bits(sc, MII16_DS3_LNLBK); /* line loopback off */ - } - - /* SNMP error counters */ - sc->status.snmp.t3.lcv = CV; - sc->status.snmp.t3.pcv = PERR; - sc->status.snmp.t3.ccv = CERR; - sc->status.snmp.t3.febe = FEBE; - - /* SNMP Line Status */ - sc->status.snmp.t3.line = 0; - if (!(ctl1 & CTL1_XTX)) sc->status.snmp.t3.line |= TLINE_TX_RAI; - if (stat16 & STAT16_XERR) sc->status.snmp.t3.line |= TLINE_RX_RAI; - if (ctl1 & CTL1_TXAIS) sc->status.snmp.t3.line |= TLINE_TX_AIS; - if (stat16 & STAT16_RAIS) sc->status.snmp.t3.line |= TLINE_RX_AIS; - if (stat16 & STAT16_ROOF) sc->status.snmp.t3.line |= TLINE_LOF; - if (stat16 & STAT16_RLOS) sc->status.snmp.t3.line |= TLINE_LOS; - if (stat16 & STAT16_SEF) sc->status.snmp.t3.line |= T3LINE_SEF; - - /* SNMP Loopback Status */ - sc->status.snmp.t3.loop &= ~TLOOP_FAR_LINE; - if (sc->config.loop_back == CFG_LOOP_TULIP) - sc->status.snmp.t3.loop |= TLOOP_NEAR_OTHER; - if (ctl1 & CTL1_3LOOP) sc->status.snmp.t3.loop |= TLOOP_NEAR_INWARD; - if (mii16 & MII16_DS3_TRLBK) sc->status.snmp.t3.loop |= TLOOP_NEAR_OTHER; - if (mii16 & MII16_DS3_LNLBK) sc->status.snmp.t3.loop |= TLOOP_NEAR_LINE; -/*if (ctl12 & CTL12_RTPLOOP) sc->status.snmp.t3.loop |= TLOOP_NEAR_PAYLOAD; */ - - /* Remember this state until next time. */ - sc->last_stat16 = stat16; - - /* If an INWARD loopback is in effect, link status is UP */ - if (sc->config.loop_back != CFG_LOOP_NONE) /* XXX INWARD ONLY */ - sc->status.link_state = STATE_UP; - } - -static void /* context: process */ -t3_send_dbl_feac(softc_t *sc, int feac1, int feac2) - { - u_int8_t tx_feac; - int i; - - /* The FEAC transmitter could be sending a continuous */ - /* FEAC msg when told to send a double FEAC message. */ - /* So save the current state of the FEAC transmitter. */ - tx_feac = framer_read(sc, T3CSR_TX_FEAC); - /* Load second FEAC code and stop FEAC transmitter. */ - framer_write(sc, T3CSR_TX_FEAC, CTL5_EMODE + feac2); - /* FEAC transmitter sends 10 more FEACs and then stops. */ - SLEEP(20000); /* sending one FEAC takes 1700 uSecs */ - /* Load first FEAC code and start FEAC transmitter. */ - framer_write(sc, T3CSR_DBL_FEAC, CTL13_DFEXEC + feac1); - /* Wait for double FEAC sequence to complete -- about 70 ms. */ - for (i=0; i<10; i++) /* max delay 100 ms */ - if (framer_read(sc, T3CSR_DBL_FEAC) & CTL13_DFEXEC) SLEEP(10000); - /* Flush received FEACS; do not respond to our own loop cmd! */ - while (framer_read(sc, T3CSR_FEAC_STK) & FEAC_STK_VALID) DELAY(1); - /* Restore previous state of the FEAC transmitter. */ - /* If it was sending a continous FEAC, it will resume. */ - framer_write(sc, T3CSR_TX_FEAC, tx_feac); - } - -static int /* context: process */ -t3_ioctl(softc_t *sc, struct ioctl *ioctl) - { - int error = 0; - - switch (ioctl->cmd) - { - case IOCTL_SNMP_SEND: /* set opstatus? */ - { - if (sc->config.format != CFG_FORMAT_T3CPAR) - error = EINVAL; - else if (ioctl->data == TSEND_LINE) - { - sc->status.snmp.t3.loop |= TLOOP_FAR_LINE; - t3_send_dbl_feac(sc, T3BOP_LINE_UP, T3BOP_LOOP_DS3); - } - else if (ioctl->data == TSEND_RESET) - { - t3_send_dbl_feac(sc, T3BOP_LINE_DOWN, T3BOP_LOOP_DS3); - sc->status.snmp.t3.loop &= ~TLOOP_FAR_LINE; - } - else - error = EINVAL; - break; - } - case IOCTL_SNMP_LOOP: /* set opstatus = test? */ - { - if (ioctl->data == CFG_LOOP_NONE) - { - mii16_clr_bits(sc, MII16_DS3_FRAME); - mii16_clr_bits(sc, MII16_DS3_TRLBK); - mii16_clr_bits(sc, MII16_DS3_LNLBK); - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) & ~CTL1_3LOOP); - framer_write(sc, T3CSR_CTL12, - framer_read(sc, T3CSR_CTL12) & ~(CTL12_RTPLOOP | CTL12_RTPLLEN)); - } - else if (ioctl->data == CFG_LOOP_LINE) - mii16_set_bits(sc, MII16_DS3_LNLBK); - else if (ioctl->data == CFG_LOOP_OTHER) - mii16_set_bits(sc, MII16_DS3_TRLBK); - else if (ioctl->data == CFG_LOOP_INWARD) - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) | CTL1_3LOOP); - else if (ioctl->data == CFG_LOOP_DUAL) - { - mii16_set_bits(sc, MII16_DS3_LNLBK); - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) | CTL1_3LOOP); - } - else if (ioctl->data == CFG_LOOP_PAYLOAD) - { - mii16_set_bits(sc, MII16_DS3_FRAME); - framer_write(sc, T3CSR_CTL12, - framer_read(sc, T3CSR_CTL12) | CTL12_RTPLOOP); - framer_write(sc, T3CSR_CTL12, - framer_read(sc, T3CSR_CTL12) | CTL12_RTPLLEN); - DELAY(25); /* at least two frames (22 uS) */ - framer_write(sc, T3CSR_CTL12, - framer_read(sc, T3CSR_CTL12) & ~CTL12_RTPLLEN); - } - else - error = EINVAL; - break; - } - case IOCTL_SET_STATUS: - { -#if 0 - if (ioctl->data) - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) & ~CTL1_TXIDL); - else /* off */ - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) | CTL1_TXIDL); -#endif - break; - } - default: - error = EINVAL; - break; - } - - return error; - } - -/* Must not sleep. */ -static void -t3_attach(softc_t *sc, struct config *config) - { - int i; - u_int8_t ctl1; - - if (config == NULL) /* startup config */ - { - sc->status.card_type = CSID_LMC_T3; - sc->config.crc_len = CFG_CRC_16; - sc->config.loop_back = CFG_LOOP_NONE; - sc->config.format = CFG_FORMAT_T3CPAR; - sc->config.cable_len = 10; /* meters */ - sc->config.scrambler = CFG_SCRAM_DL_KEN; - sc->config.tx_clk_src = CFG_CLKMUX_INT; - - /* Center the VCXO -- get within 20 PPM of 44736000. */ - dac_write(sc, 0x9002); /* set Vref = 2.048 volts */ - dac_write(sc, 2048); /* range is 0..4095 */ - } - else if (config != &sc->config) /* change config */ - { - if ((sc->config.crc_len == config->crc_len) && - (sc->config.loop_back == config->loop_back) && - (sc->config.format == config->format) && - (sc->config.cable_len == config->cable_len) && - (sc->config.scrambler == config->scrambler) && - (sc->config.tx_clk_src == config->tx_clk_src)) - return; /* nothing changed */ - sc->config.crc_len = config->crc_len; - sc->config.loop_back = config->loop_back; - sc->config.format = config->format; - sc->config.cable_len = config->cable_len; - sc->config.scrambler = config->scrambler; - sc->config.tx_clk_src = config->tx_clk_src; - } - - /* Set cable length. */ - if (sc->config.cable_len > 30) - mii16_clr_bits(sc, MII16_DS3_ZERO); - else - mii16_set_bits(sc, MII16_DS3_ZERO); - - /* Set payload scrambler polynomial. */ - if (sc->config.scrambler == CFG_SCRAM_LARS) - mii16_set_bits(sc, MII16_DS3_POLY); - else - mii16_clr_bits(sc, MII16_DS3_POLY); - - /* Set payload scrambler on/off. */ - if (sc->config.scrambler == CFG_SCRAM_OFF) - mii16_clr_bits(sc, MII16_DS3_SCRAM); - else - mii16_set_bits(sc, MII16_DS3_SCRAM); - - /* Set CRC length. */ - if (sc->config.crc_len == CFG_CRC_32) - mii16_set_bits(sc, MII16_DS3_CRC32); - else - mii16_clr_bits(sc, MII16_DS3_CRC32); - - /* Loopback towards host thru the line interface. */ - if (sc->config.loop_back == CFG_LOOP_OTHER) - mii16_set_bits(sc, MII16_DS3_TRLBK); - else - mii16_clr_bits(sc, MII16_DS3_TRLBK); - - /* Loopback towards network thru the line interface. */ - if (sc->config.loop_back == CFG_LOOP_LINE) - mii16_set_bits(sc, MII16_DS3_LNLBK); - else if (sc->config.loop_back == CFG_LOOP_DUAL) - mii16_set_bits(sc, MII16_DS3_LNLBK); - else - mii16_clr_bits(sc, MII16_DS3_LNLBK); - - /* Configure T3 framer chip; write EVERY writeable register. */ - ctl1 = CTL1_SER | CTL1_XTX; - if (sc->config.format == CFG_FORMAT_T3M13) ctl1 |= CTL1_M13MODE; - if (sc->config.loop_back == CFG_LOOP_INWARD) ctl1 |= CTL1_3LOOP; - if (sc->config.loop_back == CFG_LOOP_DUAL) ctl1 |= CTL1_3LOOP; - framer_write(sc, T3CSR_CTL1, ctl1); - framer_write(sc, T3CSR_TX_FEAC, CTL5_EMODE); - framer_write(sc, T3CSR_CTL8, CTL8_FBEC); - framer_write(sc, T3CSR_CTL12, CTL12_DLCB1 | CTL12_C21 | CTL12_MCB1); - framer_write(sc, T3CSR_DBL_FEAC, 0); - framer_write(sc, T3CSR_CTL14, CTL14_RGCEN | CTL14_TGCEN); - framer_write(sc, T3CSR_INTEN, 0); - framer_write(sc, T3CSR_CTL20, CTL20_CVEN); - - /* Clear error counters and latched error bits */ - /* that may have happened while initializing. */ - for (i=0; i<21; i++) framer_read(sc, i); - } - -static void -t3_detach(softc_t *sc) - { - framer_write(sc, T3CSR_CTL1, - framer_read(sc, T3CSR_CTL1) | CTL1_TXIDL); - led_on(sc, MII16_LED_ALL); - } - -/* End DS3 card code */ - -/* Begin SSI card code */ - -static struct card ssi_card = - { - .ident = ssi_ident, - .watchdog = ssi_watchdog, - .ioctl = ssi_ioctl, - .attach = ssi_attach, - .detach = ssi_detach, - }; - -static void -ssi_ident(softc_t *sc) - { - printf(", LTC1343/44"); - } - -static void /* context: softirq */ -ssi_watchdog(softc_t *sc) - { - u_int16_t cable; - u_int16_t mii16 = mii_read(sc, 16) & MII16_SSI_MODEM; - - sc->status.link_state = STATE_UP; - - /* Software is alive. */ - led_inv(sc, MII16_SSI_LED_UL); - - /* Check the transmit clock. */ - if (sc->status.tx_speed == 0) - { - led_on(sc, MII16_SSI_LED_UR); - sc->status.link_state = STATE_DOWN; - } - else - led_off(sc, MII16_SSI_LED_UR); - - /* Check the external cable. */ - cable = mii_read(sc, 17); - cable = cable & MII17_SSI_CABLE_MASK; - cable = cable >> MII17_SSI_CABLE_SHIFT; - if (cable == 7) - { - led_off(sc, MII16_SSI_LED_LL); /* no cable */ - sc->status.link_state = STATE_DOWN; - } - else - led_on(sc, MII16_SSI_LED_LL); - - /* The unit at the other end of the cable is ready if: */ - /* DTE mode and DCD pin is asserted */ - /* DCE mode and DSR pin is asserted */ - if (((sc->config.dte_dce == CFG_DTE) && !(mii16 & MII16_SSI_DCD)) || - ((sc->config.dte_dce == CFG_DCE) && !(mii16 & MII16_SSI_DSR))) - { - led_off(sc, MII16_SSI_LED_LR); - sc->status.link_state = STATE_DOWN; - } - else - led_on(sc, MII16_SSI_LED_LR); - - if (sc->config.debug && (cable != sc->status.cable_type)) - printf("%s: SSI cable type changed to '%s'\n", - NAME_UNIT, ssi_cables[cable]); - sc->status.cable_type = cable; - - /* Print the modem control signals if they changed. */ - if ((sc->config.debug) && (mii16 != sc->last_mii16)) - { - const char *on = "ON ", *off = "OFF"; - printf("%s: DTR=%s DSR=%s RTS=%s CTS=%s DCD=%s RI=%s LL=%s RL=%s TM=%s\n", - NAME_UNIT, - (mii16 & MII16_SSI_DTR) ? on : off, - (mii16 & MII16_SSI_DSR) ? on : off, - (mii16 & MII16_SSI_RTS) ? on : off, - (mii16 & MII16_SSI_CTS) ? on : off, - (mii16 & MII16_SSI_DCD) ? on : off, - (mii16 & MII16_SSI_RI) ? on : off, - (mii16 & MII16_SSI_LL) ? on : off, - (mii16 & MII16_SSI_RL) ? on : off, - (mii16 & MII16_SSI_TM) ? on : off); - } - - /* SNMP one-second report */ - sc->status.snmp.ssi.sigs = mii16 & MII16_SSI_MODEM; - - /* Remember this state until next time. */ - sc->last_mii16 = mii16; - - /* If a loop back is in effect, link status is UP */ - if (sc->config.loop_back != CFG_LOOP_NONE) - sc->status.link_state = STATE_UP; - } - -static int /* context: process */ -ssi_ioctl(softc_t *sc, struct ioctl *ioctl) - { - int error = 0; - - if (ioctl->cmd == IOCTL_SNMP_SIGS) - { - u_int16_t mii16 = mii_read(sc, 16); - mii16 &= ~MII16_SSI_MODEM; - mii16 |= (MII16_SSI_MODEM & ioctl->data); - mii_write(sc, 16, mii16); - } - else if (ioctl->cmd == IOCTL_SET_STATUS) - { - if (ioctl->data) - mii16_set_bits(sc, (MII16_SSI_DTR | MII16_SSI_RTS | MII16_SSI_DCD)); - else - mii16_clr_bits(sc, (MII16_SSI_DTR | MII16_SSI_RTS | MII16_SSI_DCD)); - } - else - error = EINVAL; - - return error; - } - -/* Must not sleep. */ -static void -ssi_attach(softc_t *sc, struct config *config) - { - if (config == NULL) /* startup config */ - { - sc->status.card_type = CSID_LMC_SSI; - sc->config.crc_len = CFG_CRC_16; - sc->config.loop_back = CFG_LOOP_NONE; - sc->config.tx_clk_src = CFG_CLKMUX_ST; - sc->config.dte_dce = CFG_DTE; - sc->config.synth.n = 51; /* 1.536 MHz */ - sc->config.synth.m = 83; - sc->config.synth.v = 1; - sc->config.synth.x = 1; - sc->config.synth.r = 1; - sc->config.synth.prescale = 4; - } - else if (config != &sc->config) /* change config */ - { - u_int32_t *old_synth = (u_int32_t *)&sc->config.synth; - u_int32_t *new_synth = (u_int32_t *)&config->synth; - if ((sc->config.crc_len == config->crc_len) && - (sc->config.loop_back == config->loop_back) && - (sc->config.tx_clk_src == config->tx_clk_src) && - (sc->config.dte_dce == config->dte_dce) && - (*old_synth == *new_synth)) - return; /* nothing changed */ - sc->config.crc_len = config->crc_len; - sc->config.loop_back = config->loop_back; - sc->config.tx_clk_src = config->tx_clk_src; - sc->config.dte_dce = config->dte_dce; - *old_synth = *new_synth; - } - - /* Disable the TX clock driver while programming the oscillator. */ - gpio_clr_bits(sc, GPIO_SSI_DCE); - gpio_make_output(sc, GPIO_SSI_DCE); - - /* Program the synthesized oscillator. */ - synth_write(sc, &sc->config.synth); - - /* Set DTE/DCE mode. */ - /* If DTE mode then DCD & TXC are received. */ - /* If DCE mode then DCD & TXC are driven. */ - /* Boards with MII rev=4.0 do not drive DCD. */ - if (sc->config.dte_dce == CFG_DCE) - gpio_set_bits(sc, GPIO_SSI_DCE); - else - gpio_clr_bits(sc, GPIO_SSI_DCE); - gpio_make_output(sc, GPIO_SSI_DCE); - - /* Set CRC length. */ - if (sc->config.crc_len == CFG_CRC_32) - mii16_set_bits(sc, MII16_SSI_CRC32); - else - mii16_clr_bits(sc, MII16_SSI_CRC32); - - /* Loop towards host thru cable drivers and receivers. */ - /* Asserts DCD at the far end of a null modem cable. */ - if (sc->config.loop_back == CFG_LOOP_PINS) - mii16_set_bits(sc, MII16_SSI_LOOP); - else - mii16_clr_bits(sc, MII16_SSI_LOOP); - - /* Assert pin LL in modem conn: ask modem for local loop. */ - /* Asserts TM at the far end of a null modem cable. */ - if (sc->config.loop_back == CFG_LOOP_LL) - mii16_set_bits(sc, MII16_SSI_LL); - else - mii16_clr_bits(sc, MII16_SSI_LL); - - /* Assert pin RL in modem conn: ask modem for remote loop. */ - if (sc->config.loop_back == CFG_LOOP_RL) - mii16_set_bits(sc, MII16_SSI_RL); - else - mii16_clr_bits(sc, MII16_SSI_RL); - } - -static void -ssi_detach(softc_t *sc) - { - mii16_clr_bits(sc, (MII16_SSI_DTR | MII16_SSI_RTS | MII16_SSI_DCD)); - led_on(sc, MII16_LED_ALL); - } - -/* End SSI card code */ - -/* Begin T1E1 card code */ - -static struct card t1_card = - { - .ident = t1_ident, - .watchdog = t1_watchdog, - .ioctl = t1_ioctl, - .attach = t1_attach, - .detach = t1_detach, - }; - -static void -t1_ident(softc_t *sc) - { - printf(", Bt837%x rev %x", - framer_read(sc, Bt8370_DID)>>4, - framer_read(sc, Bt8370_DID)&0x0F); - } - -static void /* context: softirq */ -t1_watchdog(softc_t *sc) - { - u_int16_t LCV = 0, FERR = 0, CRC = 0, FEBE = 0; - u_int8_t alm1, alm3, loop, isr0; - int i; - - sc->status.link_state = STATE_UP; - - /* Read the alarm registers */ - alm1 = framer_read(sc, Bt8370_ALM1); - alm3 = framer_read(sc, Bt8370_ALM3); - loop = framer_read(sc, Bt8370_LOOP); - isr0 = framer_read(sc, Bt8370_ISR0); - - /* Always ignore the SIGFRZ alarm bit, */ - alm1 &= ~ALM1_SIGFRZ; - if (FORMAT_T1ANY) /* ignore RYEL in T1 modes */ - alm1 &= ~ALM1_RYEL; - else if (FORMAT_E1NONE) /* ignore all alarms except LOS */ - alm1 &= ALM1_RLOS; - - /* Software is alive. */ - led_inv(sc, MII16_T1_LED_GRN); - - /* Receiving Alarm Indication Signal (AIS). */ - if (alm1 & ALM1_RAIS) /* receiving ais */ - led_on(sc, MII16_T1_LED_BLU); - else if (alm1 & ALM1_RLOS) /* sending ais */ - led_inv(sc, MII16_T1_LED_BLU); - else - led_off(sc, MII16_T1_LED_BLU); - - /* Receiving Remote Alarm Indication (RAI). */ - if (alm1 & (ALM1_RMYEL | ALM1_RYEL)) /* receiving rai */ - led_on(sc, MII16_T1_LED_YEL); - else if (alm1 & ALM1_RLOF) /* sending rai */ - led_inv(sc, MII16_T1_LED_YEL); - else - led_off(sc, MII16_T1_LED_YEL); - - /* If any alarm bits are set then the link is 'down'. */ - /* The bad bits are: rmyel ryel rais ralos rlos rlof. */ - /* Some alarm bits have been masked by this point. */ - if (alm1) sc->status.link_state = STATE_DOWN; - - /* Declare local Red Alarm if the link is down. */ - if (sc->status.link_state == STATE_DOWN) - led_on(sc, MII16_T1_LED_RED); - else if (sc->loop_timer) /* loopback is active */ - led_inv(sc, MII16_T1_LED_RED); - else - led_off(sc, MII16_T1_LED_RED); - - /* Print latched error bits if they changed. */ - if ((sc->config.debug) && (alm1 != sc->last_alm1)) - { - const char *on = "ON ", *off = "OFF"; - printf("%s: RLOF=%s RLOS=%s RALOS=%s RAIS=%s RYEL=%s RMYEL=%s\n", - NAME_UNIT, - (alm1 & ALM1_RLOF) ? on : off, - (alm1 & ALM1_RLOS) ? on : off, - (alm1 & ALM1_RALOS) ? on : off, - (alm1 & ALM1_RAIS) ? on : off, - (alm1 & ALM1_RYEL) ? on : off, - (alm1 & ALM1_RMYEL) ? on : off); - } - - /* Check and print error counters if non-zero. */ - LCV = framer_read(sc, Bt8370_LCV_LO) + - (framer_read(sc, Bt8370_LCV_HI)<<8); - if (!FORMAT_E1NONE) - FERR = framer_read(sc, Bt8370_FERR_LO) + - (framer_read(sc, Bt8370_FERR_HI)<<8); - if (FORMAT_E1CRC || FORMAT_T1ESF) - CRC = framer_read(sc, Bt8370_CRC_LO) + - (framer_read(sc, Bt8370_CRC_HI)<<8); - if (FORMAT_E1CRC) - FEBE = framer_read(sc, Bt8370_FEBE_LO) + - (framer_read(sc, Bt8370_FEBE_HI)<<8); - /* Only LCV is valid if Out-Of-Frame */ - if (FORMAT_E1NONE) FERR = CRC = FEBE = 0; - if ((sc->config.debug) && (LCV || FERR || CRC || FEBE)) - printf("%s: LCV=%u FERR=%u CRC=%u FEBE=%u\n", - NAME_UNIT, LCV, FERR, CRC, FEBE); - - /* Driver keeps crude link-level error counters (SNMP is better). */ - sc->status.cntrs.lcv_errs += LCV; - sc->status.cntrs.frm_errs += FERR; - sc->status.cntrs.crc_errs += CRC; - sc->status.cntrs.febe_errs += FEBE; - - /* Check for BOP messages in the ESF Facility Data Link. */ - if ((FORMAT_T1ESF) && (framer_read(sc, Bt8370_ISR1) & 0x80)) - { - u_int8_t bop_code = framer_read(sc, Bt8370_RBOP) & 0x3F; - - switch (bop_code) - { - case T1BOP_OOF: - { - if ((sc->config.debug) && !(sc->last_alm1 & ALM1_RMYEL)) - printf("%s: Receiving a 'yellow alarm' BOP msg\n", NAME_UNIT); - break; - } - case T1BOP_LINE_UP: - { - if (sc->config.debug) - printf("%s: Received a 'line loopback activate' BOP msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, LOOP_LINE); - sc->loop_timer = 305; - break; - } - case T1BOP_LINE_DOWN: - { - if (sc->config.debug) - printf("%s: Received a 'line loopback deactivate' BOP msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, - framer_read(sc, Bt8370_LOOP) & ~LOOP_LINE); - sc->loop_timer = 0; - break; - } - case T1BOP_PAY_UP: - { - if (sc->config.debug) - printf("%s: Received a 'payload loopback activate' BOP msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, LOOP_PAYLOAD); - sc->loop_timer = 305; - break; - } - case T1BOP_PAY_DOWN: - { - if (sc->config.debug) - printf("%s: Received a 'payload loopback deactivate' BOP msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, - framer_read(sc, Bt8370_LOOP) & ~LOOP_PAYLOAD); - sc->loop_timer = 0; - break; - } - default: - { - if (sc->config.debug) - printf("%s: Received a type 0x%02X BOP msg\n", NAME_UNIT, bop_code); - break; - } - } - } - - /* Check for HDLC pkts in the ESF Facility Data Link. */ - if ((FORMAT_T1ESF) && (framer_read(sc, Bt8370_ISR2) & 0x70)) - { - /* while (not fifo-empty && not start-of-msg) flush fifo */ - while ((framer_read(sc, Bt8370_RDL1_STAT) & 0x0C)==0) - framer_read(sc, Bt8370_RDL1); - /* If (not fifo-empty), then begin processing fifo contents. */ - if ((framer_read(sc, Bt8370_RDL1_STAT) & 0x0C) == 0x08) - { - u_int8_t msg[64]; - u_int8_t stat = framer_read(sc, Bt8370_RDL1); - sc->status.cntrs.fdl_pkts++; - for (i=0; i<(stat & 0x3F); i++) - msg[i] = framer_read(sc, Bt8370_RDL1); - /* Is this FDL message a T1.403 performance report? */ - if (((stat & 0x3F)==11) && - ((msg[0]==0x38) || (msg[0]==0x3A)) && - (msg[1]==1) && (msg[2]==3)) - /* Copy 4 PRs from FDL pkt to SNMP struct. */ - memcpy(sc->status.snmp.t1.prm, msg+3, 8); - } - } - - /* Check for inband loop up/down commands. */ - if (FORMAT_T1ANY) - { - u_int8_t isr6 = framer_read(sc, Bt8370_ISR6); - u_int8_t alarm2 = framer_read(sc, Bt8370_ALM2); - u_int8_t tlb = framer_read(sc, Bt8370_TLB); - - /* Inband Code == Loop Up && On Transition && Inband Tx Inactive */ - if ((isr6 & 0x40) && (alarm2 & 0x40) && !(tlb & 1)) - { /* CSU loop up is 10000 10000 ... */ - if (sc->config.debug) - printf("%s: Received a 'CSU Loop Up' inband msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, LOOP_LINE); /* Loop up */ - sc->loop_timer = 305; - } - /* Inband Code == Loop Down && On Transition && Inband Tx Inactive */ - if ((isr6 & 0x80) && (alarm2 & 0x80) && !(tlb & 1)) - { /* CSU loop down is 100 100 100 ... */ - if (sc->config.debug) - printf("%s: Received a 'CSU Loop Down' inband msg\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, - framer_read(sc, Bt8370_LOOP) & ~LOOP_LINE); /* loop down */ - sc->loop_timer = 0; - } - } - - /* Manually send Yellow Alarm BOP msgs. */ - if (FORMAT_T1ESF) - { - u_int8_t isr7 = framer_read(sc, Bt8370_ISR7); - - if ((isr7 & 0x02) && (alm1 & 0x02)) /* RLOF on-transition */ - { /* Start sending continuous Yellow Alarm BOP messages. */ - framer_write(sc, Bt8370_BOP, RBOP_25 | TBOP_CONT); - framer_write(sc, Bt8370_TBOP, 0x00); /* send BOP; order matters */ - } - else if ((isr7 & 0x02) && !(alm1 & 0x02)) /* RLOF off-transition */ - { /* Stop sending continuous Yellow Alarm BOP messages. */ - framer_write(sc, Bt8370_BOP, RBOP_25 | TBOP_OFF); - } - } - - /* Time out loopback requests. */ - if (sc->loop_timer) - if (--sc->loop_timer == 0) - if (loop) - { - if (sc->config.debug) - printf("%s: Timeout: Loop Down after 300 seconds\n", NAME_UNIT); - framer_write(sc, Bt8370_LOOP, loop & ~(LOOP_PAYLOAD | LOOP_LINE)); - } - - /* RX Test Pattern status */ - if ((sc->config.debug) && (isr0 & 0x10)) - printf("%s: RX Test Pattern Sync\n", NAME_UNIT); - - /* SNMP Error Counters */ - sc->status.snmp.t1.lcv = LCV; - sc->status.snmp.t1.fe = FERR; - sc->status.snmp.t1.crc = CRC; - sc->status.snmp.t1.febe = FEBE; - - /* SNMP Line Status */ - sc->status.snmp.t1.line = 0; - if (alm1 & ALM1_RMYEL) sc->status.snmp.t1.line |= TLINE_RX_RAI; - if (alm1 & ALM1_RYEL) sc->status.snmp.t1.line |= TLINE_RX_RAI; - if (alm1 & ALM1_RLOF) sc->status.snmp.t1.line |= TLINE_TX_RAI; - if (alm1 & ALM1_RAIS) sc->status.snmp.t1.line |= TLINE_RX_AIS; - if (alm1 & ALM1_RLOS) sc->status.snmp.t1.line |= TLINE_TX_AIS; - if (alm1 & ALM1_RLOF) sc->status.snmp.t1.line |= TLINE_LOF; - if (alm1 & ALM1_RLOS) sc->status.snmp.t1.line |= TLINE_LOS; - if (alm3 & ALM3_RMAIS) sc->status.snmp.t1.line |= T1LINE_RX_TS16_AIS; - if (alm3 & ALM3_SRED) sc->status.snmp.t1.line |= T1LINE_TX_TS16_LOMF; - if (alm3 & ALM3_SEF) sc->status.snmp.t1.line |= T1LINE_SEF; - if (isr0 & 0x10) sc->status.snmp.t1.line |= T1LINE_RX_TEST; - if ((alm1 & ALM1_RMYEL) && (FORMAT_E1CAS)) - sc->status.snmp.t1.line |= T1LINE_RX_TS16_LOMF; - - /* SNMP Loopback Status */ - sc->status.snmp.t1.loop &= ~(TLOOP_FAR_LINE | TLOOP_FAR_PAYLOAD); - if (sc->config.loop_back == CFG_LOOP_TULIP) - sc->status.snmp.t1.loop |= TLOOP_NEAR_OTHER; - if (loop & LOOP_PAYLOAD) sc->status.snmp.t1.loop |= TLOOP_NEAR_PAYLOAD; - if (loop & LOOP_LINE) sc->status.snmp.t1.loop |= TLOOP_NEAR_LINE; - if (loop & LOOP_ANALOG) sc->status.snmp.t1.loop |= TLOOP_NEAR_OTHER; - if (loop & LOOP_FRAMER) sc->status.snmp.t1.loop |= TLOOP_NEAR_INWARD; - - /* Remember this state until next time. */ - sc->last_alm1 = alm1; - - /* If an INWARD loopback is in effect, link status is UP */ - if (sc->config.loop_back != CFG_LOOP_NONE) /* XXX INWARD ONLY */ - sc->status.link_state = STATE_UP; - } - -static void /* context: process */ -t1_send_bop(softc_t *sc, int bop_code) - { - u_int8_t bop; - int i; - - /* The BOP transmitter could be sending a continuous */ - /* BOP msg when told to send this BOP_25 message. */ - /* So save and restore the state of the BOP machine. */ - bop = framer_read(sc, Bt8370_BOP); - framer_write(sc, Bt8370_BOP, RBOP_OFF | TBOP_OFF); - for (i=0; i<40; i++) /* max delay 400 ms. */ - if (framer_read(sc, Bt8370_BOP_STAT) & 0x80) SLEEP(10000); - /* send 25 repetitions of bop_code */ - framer_write(sc, Bt8370_BOP, RBOP_OFF | TBOP_25); - framer_write(sc, Bt8370_TBOP, bop_code); /* order matters */ - /* wait for tx to stop */ - for (i=0; i<40; i++) /* max delay 400 ms. */ - if (framer_read(sc, Bt8370_BOP_STAT) & 0x80) SLEEP(10000); - /* Restore previous state of the BOP machine. */ - framer_write(sc, Bt8370_BOP, bop); - } - -static int /* context: process */ -t1_ioctl(softc_t *sc, struct ioctl *ioctl) - { - int error = 0; - - switch (ioctl->cmd) - { - case IOCTL_SNMP_SEND: /* set opstatus? */ - { - switch (ioctl->data) - { - case TSEND_NORMAL: - { - framer_write(sc, Bt8370_TPATT, 0x00); /* tx pattern generator off */ - framer_write(sc, Bt8370_RPATT, 0x00); /* rx pattern detector off */ - framer_write(sc, Bt8370_TLB, 0x00); /* tx inband generator off */ - break; - } - case TSEND_LINE: - { - if (FORMAT_T1ESF) - t1_send_bop(sc, T1BOP_LINE_UP); - else if (FORMAT_T1SF) - { - framer_write(sc, Bt8370_LBP, 0x08); /* 10000 10000 ... */ - framer_write(sc, Bt8370_TLB, 0x05); /* 5 bits, framed, start */ - } - sc->status.snmp.t1.loop |= TLOOP_FAR_LINE; - break; - } - case TSEND_PAYLOAD: - { - t1_send_bop(sc, T1BOP_PAY_UP); - sc->status.snmp.t1.loop |= TLOOP_FAR_PAYLOAD; - break; - } - case TSEND_RESET: - { - if (sc->status.snmp.t1.loop == TLOOP_FAR_LINE) - { - if (FORMAT_T1ESF) - t1_send_bop(sc, T1BOP_LINE_DOWN); - else if (FORMAT_T1SF) - { - framer_write(sc, Bt8370_LBP, 0x24); /* 100100 100100 ... */ - framer_write(sc, Bt8370_TLB, 0x09); /* 6 bits, framed, start */ - } - sc->status.snmp.t1.loop &= ~TLOOP_FAR_LINE; - } - if (sc->status.snmp.t1.loop == TLOOP_FAR_PAYLOAD) - { - t1_send_bop(sc, T1BOP_PAY_DOWN); - sc->status.snmp.t1.loop &= ~TLOOP_FAR_PAYLOAD; - } - break; - } - case TSEND_QRS: - { - framer_write(sc, Bt8370_TPATT, 0x1E); /* framed QRSS */ - break; - } - default: - { - error = EINVAL; - break; - } - } - break; - } - case IOCTL_SNMP_LOOP: /* set opstatus = test? */ - { - u_int8_t new_loop = 0; - - if (ioctl->data == CFG_LOOP_NONE) - new_loop = 0; - else if (ioctl->data == CFG_LOOP_PAYLOAD) - new_loop = LOOP_PAYLOAD; - else if (ioctl->data == CFG_LOOP_LINE) - new_loop = LOOP_LINE; - else if (ioctl->data == CFG_LOOP_OTHER) - new_loop = LOOP_ANALOG; - else if (ioctl->data == CFG_LOOP_INWARD) - new_loop = LOOP_FRAMER; - else if (ioctl->data == CFG_LOOP_DUAL) - new_loop = LOOP_DUAL; - else - error = EINVAL; - if (!error) - { - framer_write(sc, Bt8370_LOOP, new_loop); - sc->config.loop_back = ioctl->data; - } - break; - } - case IOCTL_SET_STATUS: - { -#if 0 - if (ioctl->data) - mii16_set_bits(sc, MII16_T1_XOE); - else - mii16_clr_bits(sc, MII16_T1_XOE); -#endif - break; - } - default: - error = EINVAL; - break; - } - - return error; - } - -/* Must not sleep. */ -static void -t1_attach(softc_t *sc, struct config *config) - { - int i; - u_int8_t pulse, lbo, gain; - - if (config == NULL) /* startup config */ - { - /* Disable transmitter output drivers. */ - mii16_clr_bits(sc, MII16_T1_XOE); - /* Bt8370 occasionally powers up in a loopback mode. */ - /* Data sheet says zero LOOP reg and do a sw-reset. */ - framer_write(sc, Bt8370_LOOP, 0x00); /* no loopback */ - framer_write(sc, Bt8370_CR0, 0x80); /* sw-reset */ - for (i=0; i<10; i++) /* wait for sw-reset to clear; max 10 ms */ - if (framer_read(sc, Bt8370_CR0) & 0x80) DELAY(1000); - - sc->status.card_type = CSID_LMC_T1E1; - sc->config.crc_len = CFG_CRC_16; - sc->config.loop_back = CFG_LOOP_NONE; - sc->config.tx_clk_src = CFG_CLKMUX_RT; /* loop timed */ -#if 1 /* USA */ /* decide using time zone? */ - sc->config.format = CFG_FORMAT_T1ESF; -#else /* REST OF PLANET */ - sc->config.format = CFG_FORMAT_E1FASCRC; -#endif - sc->config.time_slots = 0xFFFFFFFF; - sc->config.cable_len = 10; - sc->config.tx_pulse = CFG_PULSE_AUTO; - sc->config.rx_gain_max = CFG_GAIN_AUTO; - sc->config.tx_lbo = CFG_LBO_AUTO; - } - else if (config != &sc->config) /* change config */ - { - if ((sc->config.crc_len == config->crc_len) && - (sc->config.loop_back == config->loop_back) && - (sc->config.tx_clk_src == config->tx_clk_src) && - (sc->config.format == config->format) && - (sc->config.time_slots == config->time_slots) && - (sc->config.cable_len == config->cable_len) && - (sc->config.tx_pulse == config->tx_pulse) && - (sc->config.rx_gain_max == config->rx_gain_max) && - (sc->config.tx_lbo == config->tx_lbo)) - return; /* nothing changed */ - sc->config.crc_len = config->crc_len; - sc->config.loop_back = config->loop_back; - sc->config.tx_clk_src = config->tx_clk_src; - sc->config.format = config->format; - sc->config.cable_len = config->cable_len; - sc->config.time_slots = config->time_slots; - sc->config.tx_pulse = config->tx_pulse; - sc->config.rx_gain_max = config->rx_gain_max; - sc->config.tx_lbo = config->tx_lbo; - } - - /* Set CRC length. */ - if (sc->config.crc_len == CFG_CRC_32) - mii16_set_bits(sc, MII16_T1_CRC32); - else - mii16_clr_bits(sc, MII16_T1_CRC32); - - /* Invert HDLC payload data in SF/AMI mode. */ - /* HDLC stuff bits satisfy T1 pulse density. */ - if (FORMAT_T1SF) - mii16_set_bits(sc, MII16_T1_INVERT); - else - mii16_clr_bits(sc, MII16_T1_INVERT); - - /* Set the transmitter output impedance. */ - if (FORMAT_E1ANY) mii16_set_bits(sc, MII16_T1_Z); - - /* 001:CR0 -- Control Register 0 - T1/E1 and frame format */ - framer_write(sc, Bt8370_CR0, sc->config.format); - - /* 002:JAT_CR -- Jitter Attenuator Control Register */ - if (sc->config.tx_clk_src == CFG_CLKMUX_RT) /* loop timing */ - framer_write(sc, Bt8370_JAT_CR, 0xA3); /* JAT in RX path */ - else - { /* 64-bit elastic store; free-running JCLK and CLADO */ - framer_write(sc, Bt8370_JAT_CR, 0x4B); /* assert jcenter */ - framer_write(sc, Bt8370_JAT_CR, 0x43); /* release jcenter */ - } - - /* 00C-013:IERn -- Interrupt Enable Registers */ - for (i=Bt8370_IER7; i<=Bt8370_IER0; i++) - framer_write(sc, i, 0); /* no interrupts; polled */ - - /* 014:LOOP -- loopbacks */ - if (sc->config.loop_back == CFG_LOOP_PAYLOAD) - framer_write(sc, Bt8370_LOOP, LOOP_PAYLOAD); - else if (sc->config.loop_back == CFG_LOOP_LINE) - framer_write(sc, Bt8370_LOOP, LOOP_LINE); - else if (sc->config.loop_back == CFG_LOOP_OTHER) - framer_write(sc, Bt8370_LOOP, LOOP_ANALOG); - else if (sc->config.loop_back == CFG_LOOP_INWARD) - framer_write(sc, Bt8370_LOOP, LOOP_FRAMER); - else if (sc->config.loop_back == CFG_LOOP_DUAL) - framer_write(sc, Bt8370_LOOP, LOOP_DUAL); - else - framer_write(sc, Bt8370_LOOP, 0x00); /* no loopback */ - - /* 015:DL3_TS -- Data Link 3 */ - framer_write(sc, Bt8370_DL3_TS, 0x00); /* disabled */ - - /* 018:PIO -- Programmable I/O */ - framer_write(sc, Bt8370_PIO, 0xFF); /* all pins are outputs */ - - /* 019:POE -- Programmable Output Enable */ - framer_write(sc, Bt8370_POE, 0x00); /* all outputs are enabled */ - - /* 01A;CMUX -- Clock Input Mux */ - if (sc->config.tx_clk_src == CFG_CLKMUX_EXT) - framer_write(sc, Bt8370_CMUX, 0x0C); /* external timing */ - else - framer_write(sc, Bt8370_CMUX, 0x0F); /* internal timing */ - - /* 020:LIU_CR -- Line Interface Unit Config Register */ - framer_write(sc, Bt8370_LIU_CR, 0xC1); /* reset LIU, squelch */ - - /* 022:RLIU_CR -- RX Line Interface Unit Config Reg */ - /* Errata sheet says do not use freeze-short, but we do anyway! */ - framer_write(sc, Bt8370_RLIU_CR, 0xB1); /* AGC=2048, Long Eye */ - - /* Select Rx sensitivity based on cable length. */ - if ((gain = sc->config.rx_gain_max) == CFG_GAIN_AUTO) - { - if (sc->config.cable_len > 2000) - gain = CFG_GAIN_EXTEND; - else if (sc->config.cable_len > 1000) - gain = CFG_GAIN_LONG; - else if (sc->config.cable_len > 100) - gain = CFG_GAIN_MEDIUM; - else - gain = CFG_GAIN_SHORT; - } - - /* 024:VGA_MAX -- Variable Gain Amplifier Max gain */ - framer_write(sc, Bt8370_VGA_MAX, gain); - - /* 028:PRE_EQ -- Pre Equalizer */ - if (gain == CFG_GAIN_EXTEND) - framer_write(sc, Bt8370_PRE_EQ, 0xE6); /* ON; thresh 6 */ - else - framer_write(sc, Bt8370_PRE_EQ, 0xA6); /* OFF; thresh 6 */ - - /* 038-03C:GAINn -- RX Equalizer gain thresholds */ - framer_write(sc, Bt8370_GAIN0, 0x24); - framer_write(sc, Bt8370_GAIN1, 0x28); - framer_write(sc, Bt8370_GAIN2, 0x2C); - framer_write(sc, Bt8370_GAIN3, 0x30); - framer_write(sc, Bt8370_GAIN4, 0x34); - - /* 040:RCR0 -- Receiver Control Register 0 */ - if (FORMAT_T1ESF) - framer_write(sc, Bt8370_RCR0, 0x05); /* B8ZS, 2/5 FErrs */ - else if (FORMAT_T1SF) - framer_write(sc, Bt8370_RCR0, 0x84); /* AMI, 2/5 FErrs */ - else if (FORMAT_E1NONE) - framer_write(sc, Bt8370_RCR0, 0x41); /* HDB3, rabort */ - else if (FORMAT_E1CRC) - framer_write(sc, Bt8370_RCR0, 0x09); /* HDB3, 3 FErrs or 915 CErrs */ - else /* E1 no CRC */ - framer_write(sc, Bt8370_RCR0, 0x19); /* HDB3, 3 FErrs */ - - /* 041:RPATT -- Receive Test Pattern configuration */ - framer_write(sc, Bt8370_RPATT, 0x3E); /* looking for framed QRSS */ - - /* 042:RLB -- Receive Loop Back code detector config */ - framer_write(sc, Bt8370_RLB, 0x09); /* 6 bits down; 5 bits up */ - - /* 043:LBA -- Loop Back Activate code */ - framer_write(sc, Bt8370_LBA, 0x08); /* 10000 10000 10000 ... */ - - /* 044:LBD -- Loop Back Deactivate code */ - framer_write(sc, Bt8370_LBD, 0x24); /* 100100 100100 100100 ... */ - - /* 045:RALM -- Receive Alarm signal configuration */ - framer_write(sc, Bt8370_RALM, 0x0C); /* yel_intg rlof_intg */ - - /* 046:LATCH -- Alarm/Error/Counter Latch register */ - framer_write(sc, Bt8370_LATCH, 0x1F); /* stop_cnt latch_{cnt,err,alm} */ - - /* Select Pulse Shape based on cable length (T1 only). */ - if ((pulse = sc->config.tx_pulse) == CFG_PULSE_AUTO) - { - if (FORMAT_T1ANY) - { - if (sc->config.cable_len > 200) - pulse = CFG_PULSE_T1CSU; - else if (sc->config.cable_len > 160) - pulse = CFG_PULSE_T1DSX4; - else if (sc->config.cable_len > 120) - pulse = CFG_PULSE_T1DSX3; - else if (sc->config.cable_len > 80) - pulse = CFG_PULSE_T1DSX2; - else if (sc->config.cable_len > 40) - pulse = CFG_PULSE_T1DSX1; - else - pulse = CFG_PULSE_T1DSX0; - } - else - pulse = CFG_PULSE_E1TWIST; - } - - /* Select Line Build Out based on cable length (T1CSU only). */ - if ((lbo = sc->config.tx_lbo) == CFG_LBO_AUTO) - { - if (pulse == CFG_PULSE_T1CSU) - { - if (sc->config.cable_len > 1500) - lbo = CFG_LBO_0DB; - else if (sc->config.cable_len > 1000) - lbo = CFG_LBO_7DB; - else if (sc->config.cable_len > 500) - lbo = CFG_LBO_15DB; - else - lbo = CFG_LBO_22DB; - } - else - lbo = 0; - } - - /* 068:TLIU_CR -- Transmit LIU Control Register */ - framer_write(sc, Bt8370_TLIU_CR, (0x40 | (lbo & 0x30) | (pulse & 0x0E))); - - /* 070:TCR0 -- Transmit Framer Configuration */ - framer_write(sc, Bt8370_TCR0, sc->config.format>>1); - - /* 071:TCR1 -- Transmitter Configuration */ - if (FORMAT_T1SF) - framer_write(sc, Bt8370_TCR1, 0x43); /* tabort, AMI PDV enforced */ - else - framer_write(sc, Bt8370_TCR1, 0x41); /* tabort, B8ZS or HDB3 */ - - /* 072:TFRM -- Transmit Frame format MYEL YEL MF FE CRC FBIT */ - if (sc->config.format == CFG_FORMAT_T1ESF) - framer_write(sc, Bt8370_TFRM, 0x0B); /* - YEL MF - CRC FBIT */ - else if (sc->config.format == CFG_FORMAT_T1SF) - framer_write(sc, Bt8370_TFRM, 0x19); /* - YEL MF - - FBIT */ - else if (sc->config.format == CFG_FORMAT_E1FAS) - framer_write(sc, Bt8370_TFRM, 0x11); /* - YEL - - - FBIT */ - else if (sc->config.format == CFG_FORMAT_E1FASCRC) - framer_write(sc, Bt8370_TFRM, 0x1F); /* - YEL MF FE CRC FBIT */ - else if (sc->config.format == CFG_FORMAT_E1FASCAS) - framer_write(sc, Bt8370_TFRM, 0x31); /* MYEL YEL - - - FBIT */ - else if (sc->config.format == CFG_FORMAT_E1FASCRCCAS) - framer_write(sc, Bt8370_TFRM, 0x3F); /* MYEL YEL MF FE CRC FBIT */ - else if (sc->config.format == CFG_FORMAT_E1NONE) - framer_write(sc, Bt8370_TFRM, 0x00); /* NO FRAMING BITS AT ALL! */ - - /* 073:TERROR -- Transmit Error Insert */ - framer_write(sc, Bt8370_TERROR, 0x00); /* no errors, please! */ - - /* 074:TMAN -- Transmit Manual Sa-byte/FEBE configuration */ - framer_write(sc, Bt8370_TMAN, 0x00); /* none */ - - /* 075:TALM -- Transmit Alarm Signal Configuration */ - if (FORMAT_E1ANY) - framer_write(sc, Bt8370_TALM, 0x38); /* auto_myel auto_yel auto_ais */ - else if (FORMAT_T1ANY) - framer_write(sc, Bt8370_TALM, 0x18); /* auto_yel auto_ais */ - - /* 076:TPATT -- Transmit Test Pattern Configuration */ - framer_write(sc, Bt8370_TPATT, 0x00); /* disabled */ - - /* 077:TLB -- Transmit Inband Loopback Code Configuration */ - framer_write(sc, Bt8370_TLB, 0x00); /* disabled */ - - /* 090:CLAD_CR -- Clack Rate Adapter Configuration */ - if (FORMAT_T1ANY) - framer_write(sc, Bt8370_CLAD_CR, 0x06); /* loop filter gain 1/2^6 */ - else - framer_write(sc, Bt8370_CLAD_CR, 0x08); /* loop filter gain 1/2^8 */ - - /* 091:CSEL -- CLAD frequency Select */ - if (FORMAT_T1ANY) - framer_write(sc, Bt8370_CSEL, 0x55); /* 1544 kHz */ - else - framer_write(sc, Bt8370_CSEL, 0x11); /* 2048 kHz */ - - /* 092:CPHASE -- CLAD Phase detector */ - if (FORMAT_T1ANY) - framer_write(sc, Bt8370_CPHASE, 0x22); /* phase compare @ 386 kHz */ - else - framer_write(sc, Bt8370_CPHASE, 0x00); /* phase compare @ 2048 kHz */ - - if (FORMAT_T1ESF) /* BOP & PRM are enabled in T1ESF mode only. */ - { - /* 0A0:BOP -- Bit Oriented Protocol messages */ - framer_write(sc, Bt8370_BOP, RBOP_25 | TBOP_OFF); - /* 0A4:DL1_TS -- Data Link 1 Time Slot Enable */ - framer_write(sc, Bt8370_DL1_TS, 0x40); /* FDL bits in odd frames */ - /* 0A6:DL1_CTL -- Data Link 1 Control */ - framer_write(sc, Bt8370_DL1_CTL, 0x03); /* FCS mode, TX on, RX on */ - /* 0A7:RDL1_FFC -- Rx Data Link 1 Fifo Fill Control */ - framer_write(sc, Bt8370_RDL1_FFC, 0x30); /* assert "near full" at 48 */ - /* 0AA:PRM -- Performance Report Messages */ - framer_write(sc, Bt8370_PRM, 0x80); - } - - /* 0D0:SBI_CR -- System Bus Interface Configuration Register */ - if (FORMAT_T1ANY) - framer_write(sc, Bt8370_SBI_CR, 0x47); /* 1.544 with 24 TS +Fbits */ - else - framer_write(sc, Bt8370_SBI_CR, 0x46); /* 2.048 with 32 TS */ - - /* 0D1:RSB_CR -- Receive System Bus Configuration Register */ - /* Change RINDO & RFSYNC on falling edge of RSBCLKI. */ - framer_write(sc, Bt8370_RSB_CR, 0x70); - - /* 0D2,0D3:RSYNC_{TS,BIT} -- Receive frame Sync offset */ - framer_write(sc, Bt8370_RSYNC_BIT, 0x00); - framer_write(sc, Bt8370_RSYNC_TS, 0x00); - - /* 0D4:TSB_CR -- Transmit System Bus Configuration Register */ - /* Change TINDO & TFSYNC on falling edge of TSBCLKI. */ - framer_write(sc, Bt8370_TSB_CR, 0x30); - - /* 0D5,0D6:TSYNC_{TS,BIT} -- Transmit frame Sync offset */ - framer_write(sc, Bt8370_TSYNC_BIT, 0x00); - framer_write(sc, Bt8370_TSYNC_TS, 0x00); - - /* 0D7:RSIG_CR -- Receive SIGnalling Configuration Register */ - framer_write(sc, Bt8370_RSIG_CR, 0x00); - - /* Assign and configure 64Kb TIME SLOTS. */ - /* TS24..TS1 must be assigned for T1, TS31..TS0 for E1. */ - /* Timeslots with no user data have RINDO and TINDO off. */ - for (sc->status.time_slots = 0, i=0; i<32; i++) - { - /* 0E0-0FF:SBCn -- System Bus Per-Channel Control */ - if (FORMAT_T1ANY && (i==0 || i>24)) - framer_write(sc, Bt8370_SBCn +i, 0x00); /* not assigned in T1 mode */ - else if (FORMAT_E1ANY && (i==0) && !FORMAT_E1NONE) - framer_write(sc, Bt8370_SBCn +i, 0x01); /* assigned, TS0 o/h bits */ - else if (FORMAT_E1CAS && (i==16) && !FORMAT_E1NONE) - framer_write(sc, Bt8370_SBCn +i, 0x01); /* assigned, TS16 o/h bits */ - else if ((sc->status.time_slots |= (sc->config.time_slots & (1<<i)))) - framer_write(sc, Bt8370_SBCn +i, 0x0D); /* assigned, RINDO, TINDO */ - else - framer_write(sc, Bt8370_SBCn +i, 0x01); /* assigned, idle */ - - /* 100-11F:TPCn -- Transmit Per-Channel Control */ - if (FORMAT_E1CAS && (i==0)) - framer_write(sc, Bt8370_TPCn +i, 0x30); /* tidle, sig=0000 (MAS) */ - else if (FORMAT_E1CAS && (i==16)) - framer_write(sc, Bt8370_TPCn +i, 0x3B); /* tidle, sig=1011 (XYXX) */ - else if ((sc->config.time_slots & (1<<i)) == 0) - framer_write(sc, Bt8370_TPCn +i, 0x20); /* tidle: use TSLIP_LOn */ - else - framer_write(sc, Bt8370_TPCn +i, 0x00); /* nothing special */ - - /* 140-15F:TSLIP_LOn -- Transmit PCM Slip Buffer */ - framer_write(sc, Bt8370_TSLIP_LOn +i, 0x7F); /* idle chan data */ - /* 180-19F:RPCn -- Receive Per-Channel Control */ - framer_write(sc, Bt8370_RPCn +i, 0x00); /* nothing special */ - } - - /* Enable transmitter output drivers. */ - mii16_set_bits(sc, MII16_T1_XOE); - } - -static void -t1_detach(softc_t *sc) - { - led_on(sc, MII16_LED_ALL); - } - -/* End T1E1 card code */ - - -#if SYNC_PPP /* Linux */ - -static struct stack sync_ppp_stack = - { - .ioctl = sync_ppp_ioctl, - .type = sync_ppp_type, - .mtu = sync_ppp_mtu, - .watchdog = sync_ppp_watchdog, - .open = sync_ppp_open, - .attach = sync_ppp_attach, - .detach = sync_ppp_detach, - }; - -static int /* context: process */ -sync_ppp_ioctl(softc_t *sc, struct ifreq *ifr, int cmd) - { - return sppp_do_ioctl(sc->netdev, ifr, cmd); - } - -static int /* context: interrupt */ -sync_ppp_type(softc_t *sc, struct sk_buff *skb) - { - return htons(ETH_P_WAN_PPP); - } - -static int /* context: process */ -sync_ppp_mtu(softc_t *sc, int mtu) - { - return ((mtu < 128) || (mtu > PPP_MTU)) ? -EINVAL : 0; - } - -static void /* context: softirq */ -sync_ppp_watchdog(softc_t *sc) - { - /* Notice when the link comes up. */ - if ((sc->last_link_state != STATE_UP) && - (sc->status.link_state == STATE_UP)) - sppp_reopen(sc->netdev); - - /* Notice when the link goes down. */ - if ((sc->last_link_state == STATE_UP) && - (sc->status.link_state != STATE_UP)) - sppp_close(sc->netdev); - - /* Report current line protocol. */ - sc->status.stack = STACK_SYNC_PPP; - if (sc->sppp->pp_flags & PP_CISCO) - sc->status.proto = PROTO_C_HDLC; - else - sc->status.proto = PROTO_PPP; - - /* Report keep-alive status. */ - sc->status.keep_alive = sc->sppp->pp_flags & PP_KEEPALIVE; - } - -static int /* never fails */ -sync_ppp_open(softc_t *sc, struct config *config) - { - /* Refresh the keep_alive flag. */ - if (config->keep_alive) - sc->sppp->pp_flags |= PP_KEEPALIVE; - else - sc->sppp->pp_flags &= ~PP_KEEPALIVE; - sc->config.keep_alive = config->keep_alive; - - /* Done if proto is not changing. */ - if (config->proto == sc->config.proto) - return 0; - - /* Close */ - sppp_close(sc->netdev); - - /* Change line protocol. */ - switch (config->proto) - { - case PROTO_PPP: - sc->sppp->pp_flags &= ~PP_CISCO; - sc->netdev->type = ARPHRD_PPP; - sc->config.proto = PROTO_PPP; - break; - default: - case PROTO_C_HDLC: - sc->sppp->pp_flags |= PP_CISCO; - sc->netdev->type = ARPHRD_CISCO; - sc->config.proto = PROTO_C_HDLC; - break; - } - - /* Open */ - sppp_open(sc->netdev); - - return 0; - } - -static int /* never fails */ -sync_ppp_attach(softc_t *sc, struct config *config) - { - sc->ppd = &sc->ppp_dev; /* struct ppp_device* */ - sc->netdev->priv = &sc->ppd; /* struct ppp_device** */ - sc->ppp_dev.dev = sc->netdev; - sc->sppp = &sc->ppp_dev.sppp; - - sppp_attach(&sc->ppp_dev); - sc->netdev->do_ioctl = netdev_ioctl; - config->keep_alive = 1; - - sc->config.stack = STACK_SYNC_PPP; - sc->stack = &sync_ppp_stack; - - return 0; - } - -static int /* never fails */ -sync_ppp_detach(softc_t *sc) - { - sppp_close(sc->netdev); - sppp_detach(sc->netdev); - - netdev_setup(sc->netdev); - sc->config.stack = STACK_NONE; - sc->config.proto = PROTO_NONE; - sc->stack = NULL; - - return 0; - } - -#endif /* SYNC_PPP */ - -#if GEN_HDLC /* Linux only */ - -static struct stack gen_hdlc_stack = - { - .ioctl = gen_hdlc_ioctl, - .type = gen_hdlc_type, - .mtu = gen_hdlc_mtu, - .watchdog = gen_hdlc_watchdog, - .open = gen_hdlc_open, - .attach = gen_hdlc_attach, - .detach = gen_hdlc_detach, - }; - -static int /* context: process */ -gen_hdlc_ioctl(softc_t *sc, struct ifreq *ifr, int cmd) - { - te1_settings settings; - int error = 0; - - if (cmd == SIOCWANDEV) - switch (ifr->ifr_settings.type) - { - case IF_GET_IFACE: /* get interface config */ - { - unsigned int size; - - /* NOTE: This assumes struct sync_serial_settings has the */ - /* same layout as the first part of struct te1_settings. */ - if (sc->status.card_type == CSID_LMC_T1E1) - { - if (FORMAT_T1ANY) ifr->ifr_settings.type = IF_IFACE_T1; - if (FORMAT_E1ANY) ifr->ifr_settings.type = IF_IFACE_E1; - size = sizeof(te1_settings); - } - else - { - ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; - size = sizeof(sync_serial_settings); - } - if (ifr->ifr_settings.size < size) - { - ifr->ifr_settings.size = size; - return -ENOBUFS; - } - ifr->ifr_settings.size = size; - - if (sc->config.tx_clk_src == CFG_CLKMUX_ST) - settings.clock_type = CLOCK_EXT; - if (sc->config.tx_clk_src == CFG_CLKMUX_INT) - settings.clock_type = CLOCK_TXINT; - if (sc->config.tx_clk_src == CFG_CLKMUX_RT) - settings.clock_type = CLOCK_TXFROMRX; - settings.loopback = (sc->config.loop_back != CFG_LOOP_NONE) ? 1:0; - settings.clock_rate = sc->status.tx_speed; - if (sc->status.card_type == CSID_LMC_T1E1) - settings.slot_map = sc->status.time_slots; - - error = copy_to_user(ifr->ifr_settings.ifs_ifsu.te1, - &settings, size); - break; - } - case IF_IFACE_SYNC_SERIAL: /* set interface config */ - case IF_IFACE_T1: - case IF_IFACE_E1: - { - struct config config = sc->config; - - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ifr->ifr_settings.size > sizeof(te1_settings)) - return -ENOBUFS; - error = copy_from_user(&settings, - ifr->ifr_settings.ifs_ifsu.te1, sizeof(te1_settings)); - - if (settings.clock_type == CLOCK_EXT) - config.tx_clk_src = CFG_CLKMUX_ST; - else if (settings.clock_type == CLOCK_TXINT) - config.tx_clk_src = CFG_CLKMUX_INT; - else if (settings.clock_type == CLOCK_TXFROMRX) - config.tx_clk_src = CFG_CLKMUX_RT; - - if (settings.loopback) - config.loop_back = CFG_LOOP_TULIP; - else - config.loop_back = CFG_LOOP_NONE; - - tulip_loop(sc, &config); - sc->card->attach(sc, &config); - break; - } - default: /* Pass the rest to the line pkg. */ - { - error = hdlc_ioctl(sc->netdev, ifr, cmd); - break; - } - } - else - error = -EINVAL; - - return error; - } - -static int /* context: interrupt */ -gen_hdlc_type(softc_t *sc, struct sk_buff *skb) - { - return hdlc_type_trans(skb, sc->netdev); - } - -static int /* context: process */ -gen_hdlc_mtu(softc_t *sc, int mtu) - { - return ((mtu < 68) || (mtu > HDLC_MAX_MTU)) ? -EINVAL : 0; - } - -static void /* context: softirq */ -gen_hdlc_watchdog(softc_t *sc) - { - /* Notice when the link comes up. */ - if ((sc->last_link_state != STATE_UP) && - (sc->status.link_state == STATE_UP)) - hdlc_set_carrier(1, sc->netdev); - - /* Notice when the link goes down. */ - if ((sc->last_link_state == STATE_UP) && - (sc->status.link_state != STATE_UP)) - hdlc_set_carrier(0, sc->netdev); - - /* Report current line protocol. */ - sc->status.stack = STACK_GEN_HDLC; - switch (sc->hdlcdev->proto.id) - { - case IF_PROTO_PPP: - { - struct sppp* sppp = &sc->hdlcdev->state.ppp.pppdev.sppp; - sc->status.keep_alive = sppp->pp_flags & PP_KEEPALIVE; - sc->status.proto = PROTO_PPP; - break; - } - case IF_PROTO_CISCO: - sc->status.proto = PROTO_C_HDLC; - break; - case IF_PROTO_FR: - sc->status.proto = PROTO_FRM_RLY; - break; - case IF_PROTO_HDLC: - sc->status.proto = PROTO_IP_HDLC; - break; - case IF_PROTO_X25: - sc->status.proto = PROTO_X25; - break; - case IF_PROTO_HDLC_ETH: - sc->status.proto = PROTO_ETH_HDLC; - break; - default: - sc->status.proto = PROTO_NONE; - break; - } - } - -static int -gen_hdlc_open(softc_t *sc, struct config *config) - { - int error = 0; - - /* Refresh the keep_alive flag. */ - if (sc->hdlcdev->proto.id == IF_PROTO_PPP) - { - struct sppp* sppp = &sc->hdlcdev->state.ppp.pppdev.sppp; - if (config->keep_alive) - sppp->pp_flags |= PP_KEEPALIVE; - else - sppp->pp_flags &= ~PP_KEEPALIVE; - sc->config.keep_alive = config->keep_alive; - } - - /* Done if proto is not changing. */ - if (config->proto == sc->config.proto) - return 0; - - /* Close */ - hdlc_close(sc->netdev); - - /* Generic-HDLC gets protocol params using copy_from_user(). - * This is a problem for a kernel-resident device driver. - * Luckily, PPP does not need any params so no copy_from_user(). - */ - - /* Change line protocol. */ - if (config->proto == PROTO_PPP) - { - struct ifreq ifr; - ifr.ifr_settings.size = 0; - ifr.ifr_settings.type = IF_PROTO_PPP; - hdlc_ioctl(sc->netdev, &ifr, SIOCWANDEV); - } - /* Changing to any protocol other than PPP */ - /* requires using the 'sethdlc' program. */ - - /* Open */ - if ((error = hdlc_open(sc->netdev))) - { - if (sc->config.debug) - printk("%s: hdlc_open(): error %d\n", NAME_UNIT, error); - if (error == -ENOSYS) - printk("%s: Try 'sethdlc %s hdlc|ppp|cisco|fr'\n", - NAME_UNIT, NAME_UNIT); - sc->config.proto = PROTO_NONE; - } - else - sc->config.proto = config->proto; - - return error; - } - -static int /* never fails */ -gen_hdlc_attach(softc_t *sc, struct config *config) - { - sc->netdev->priv = sc->hdlcdev; - - /* hdlc_attach(sc->netdev); */ - sc->netdev->mtu = HDLC_MAX_MTU; - sc->hdlcdev->attach = gen_hdlc_card_params; - sc->hdlcdev->xmit = netdev_start; - config->keep_alive = 1; - - sc->config.stack = STACK_GEN_HDLC; - sc->stack = &gen_hdlc_stack; - - return 0; - } - -static int /* never fails */ -gen_hdlc_detach(softc_t *sc) - { - hdlc_close(sc->netdev); - /* hdlc_detach(sc->netdev); */ - hdlc_proto_detach(sc->hdlcdev); - memset(&sc->hdlcdev->proto, 0, sizeof sc->hdlcdev->proto); - - netdev_setup(sc->netdev); - sc->config.stack = STACK_NONE; - sc->config.proto = PROTO_NONE; - sc->stack = NULL; - - return 0; - } - -static int -gen_hdlc_card_params(struct net_device *netdev, - unsigned short encoding, unsigned short parity) - { - softc_t *sc = NETDEV2SC(netdev); - struct config config = sc->config; - - /* Encoding does not seem to apply to synchronous interfaces, */ - /* but Parity seems to be generic-HDLC's name for CRC. */ - if (parity == PARITY_CRC32_PR1_CCITT) - config.crc_len = CFG_CRC_32; - if (parity == PARITY_CRC16_PR1_CCITT) - config.crc_len = CFG_CRC_16; - sc->card->attach(sc, &config); - - return 0; - } - -#endif /* GEN_HDLC */ - -#if P2P /* BSD/OS */ - -static struct stack p2p_stack = - { - .ioctl = p2p_stack_ioctl, - .input = p2p_stack_input, - .output = p2p_stack_output, - .watchdog = p2p_stack_watchdog, - .open = p2p_stack_open, - .attach = p2p_stack_attach, - .detach = p2p_stack_detach, - }; - -static int /* context: process */ -p2p_stack_ioctl(softc_t *sc, u_long cmd, void *data) - { - return p2p_ioctl(sc->ifp, cmd, data); - } - -static void /* context: interrupt */ -p2p_stack_input(softc_t *sc, struct mbuf *mbuf) - { - struct mbuf *new_mbuf = mbuf; - - while (new_mbuf) - { - sc->p2p->p2p_hdrinput(sc->p2p, new_mbuf->m_data, new_mbuf->m_len); - new_mbuf = new_mbuf->m_next; - } - sc->p2p->p2p_input(sc->p2p, NULL); - m_freem(mbuf); - } - -static void /* context: interrupt */ -p2p_stack_output(softc_t *sc) - { - if (!IFQ_IS_EMPTY(&sc->p2p->p2p_isnd)) - IFQ_DEQUEUE(&sc->p2p->p2p_isnd, sc->tx_mbuf); - else - IFQ_DEQUEUE(&sc->ifp->if_snd, sc->tx_mbuf); - } - -static void /* context: softirq */ -p2p_stack_watchdog(softc_t *sc) - { - /* Notice change in link status. */ - if ((sc->last_link_state != sc->status.link_state) && - /* if_slowtimo() can run before raw_init() has inited rawcb. */ - (sc->p2p->p2p_modem != NULL) && (rawcb.rcb_next != NULL)) - (*sc->p2p->p2p_modem)(sc->p2p, sc->status.link_state==STATE_UP); - - /* Report current line protocol. */ - sc->status.stack = STACK_P2P; - switch (sc->ifp->if_type) - { - case IFT_PPP: - sc->status.proto = PROTO_PPP; - break; - case IFT_PTPSERIAL: - sc->status.proto = PROTO_C_HDLC; - break; - case IFT_FRELAY: - sc->status.proto = PROTO_FRM_RLY; - break; - default: - sc->status.proto = PROTO_NONE; - break; - } - } - -static int -p2p_stack_open(softc_t *sc, struct config *config) - { - int error = 0; - - /* Done if proto is not changing. */ - if (config->proto == sc->config.proto) - return 0; - - if (error = p2p_stack_detach(sc)) - return error; - - /* Change line protocol. */ - switch (config->proto) - { - case PROTO_PPP: - sc->ifp->if_type = IFT_PPP; - sc->config.proto = PROTO_PPP; - break; - case PROTO_C_HDLC: - sc->ifp->if_type = IFT_PTPSERIAL; - sc->config.proto = PROTO_C_HDLC; - break; - case PROTO_FRM_RLY: - sc->ifp->if_type = IFT_FRELAY; - sc->config.proto = PROTO_FRM_RLY; - break; - default: - case PROTO_NONE: - sc->ifp->if_type = IFT_NONE; - sc->config.proto = PROTO_NONE; - return 0; - } - - error = p2p_stack_attach(sc, config); - - return error; - } - -static int -p2p_stack_attach(softc_t *sc, struct config *config) - { - int error; - - sc->p2p = &sc->p2pcom; - sc->p2p->p2p_proto = 0; /* force p2p_attach to re-init */ - - if ((error = p2p_attach(sc->p2p))) /* calls bpfattach() */ - { - if (sc->config.debug) - printf("%s: p2p_attach(): error %d\n", NAME_UNIT, error); - if (error == EPFNOSUPPORT) - printf("%s: Try 'ifconfig %s linktype ppp|frelay|chdlc'\n", - NAME_UNIT, NAME_UNIT); - sc->config.stack = STACK_NONE; /* not attached to P2P */ - return error; - } - sc->p2p->p2p_mdmctl = p2p_mdmctl; - sc->p2p->p2p_getmdm = p2p_getmdm; - - sc->config.stack = STACK_P2P; - sc->stack = &p2p_stack; - - return 0; - } - -static int -p2p_stack_detach(softc_t *sc) - { - int error = 0; - - if ((error = p2p_detach(sc->p2p))) /* calls bfpdetach() */ - { - if (sc->config.debug) - printf("%s: p2p_detach(): error %d\n", NAME_UNIT, error); - if (error == EBUSY) - printf("%s: Try 'ifconfig %s down -remove'\n", - NAME_UNIT, NAME_UNIT); - sc->config.stack = STACK_P2P; /* still attached to P2P */ - return error; - } - - ifnet_setup(sc->ifp); - sc->config.stack = STACK_NONE; - sc->config.proto = PROTO_NONE; - sc->stack = NULL; - - return error; - } - -/* Callout from P2P: */ -/* Get the state of DCD (Data Carrier Detect). */ -static int /* never fails */ -p2p_getmdm(struct p2pcom *p2p, void *result) - { - softc_t *sc = IFP2SC(&p2p->p2p_if); - - /* Non-zero is not good enough; TIOCM_CAR is 0x40. */ - *(int *)result = (sc->status.link_state==STATE_UP) ? TIOCM_CAR : 0; - - return 0; - } - -/* Callout from P2P: */ -/* Set the state of DTR (Data Terminal Ready). */ -static int /* never fails */ -p2p_mdmctl(struct p2pcom *p2p, int flag) - { - softc_t *sc = IFP2SC(&p2p->p2p_if); - - set_ready(sc, flag); - - return 0; - } - -#endif /* P2P */ - -#if SPPP /* FreeBSD, NetBSD, OpenBSD */ - -static struct stack sppp_stack = - { - .ioctl = sppp_stack_ioctl, - .input = sppp_stack_input, - .output = sppp_stack_output, - .watchdog = sppp_stack_watchdog, - .open = sppp_stack_open, - .attach = sppp_stack_attach, - .detach = sppp_stack_detach, - }; - -# if !defined(PP_FR) -# define PP_FR 0 -# endif -# if !defined(DLT_C_HDLC) -# define DLT_C_HDLC DLT_PPP -# endif -# if !defined(DLT_FRELAY) -# define DLT_FRELAY DLT_PPP -# endif - -static int /* context: process */ -sppp_stack_ioctl(softc_t *sc, u_long cmd, void *data) - { - return sppp_ioctl(sc->ifp, cmd, data); - } - -static void /* context: interrupt */ -sppp_stack_input(softc_t *sc, struct mbuf *mbuf) - { - sppp_input(sc->ifp, mbuf); - } - -static void /* context: interrupt */ -sppp_stack_output(softc_t *sc) - { - sc->tx_mbuf = sppp_dequeue(sc->ifp); - } - -static void /* context: softirq */ -sppp_stack_watchdog(softc_t *sc) - { - /* Notice when the link comes up. */ - if ((sc->last_link_state != STATE_UP) && - (sc->status.link_state == STATE_UP)) - sppp_tls(sc->sppp); - - /* Notice when the link goes down. */ - if ((sc->last_link_state == STATE_UP) && - (sc->status.link_state != STATE_UP)) - sppp_tlf(sc->sppp); - - /* Report current line protocol. */ - sc->status.stack = STACK_SPPP; - if (sc->sppp->pp_flags & PP_CISCO) - sc->status.proto = PROTO_C_HDLC; - else - sc->status.proto = PROTO_PPP; - - /* Report keep-alive status. */ - sc->status.keep_alive = sc->sppp->pp_flags & PP_KEEPALIVE; - } - -static int /* never fails */ -sppp_stack_open(softc_t *sc, struct config *config) - { - /* Refresh the keep_alive flag. */ - if (config->keep_alive) - sc->sppp->pp_flags |= PP_KEEPALIVE; - else - sc->sppp->pp_flags &= ~PP_KEEPALIVE; - sc->config.keep_alive = config->keep_alive; - - /* Done if proto is not changing. */ - if (config->proto == sc->config.proto) - return 0; - - /* Close */ - sc->ifp->if_flags &= ~IFF_UP; /* down */ - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); - - /* Change line protocol. */ - LMC_BPF_DETACH(sc); - switch (config->proto) - { - case PROTO_PPP: - { - sc->sppp->pp_flags &= ~PP_CISCO; - LMC_BPF_ATTACH(sc, DLT_PPP, 4); - sc->config.proto = PROTO_PPP; - break; - } - - default: - case PROTO_C_HDLC: - { - sc->sppp->pp_flags |= PP_CISCO; - LMC_BPF_ATTACH(sc, DLT_C_HDLC, 4); - sc->config.proto = PROTO_C_HDLC; - break; - } - - } /* switch(config->proto) */ - - /* Open */ - sc->ifp->if_flags |= IFF_UP; /* up and not running */ - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); - - return 0; - } - -static int /* never fails */ -sppp_stack_attach(softc_t *sc, struct config *config) - { - sc->sppp = &sc->spppcom; - - LMC_BPF_ATTACH(sc, DLT_RAW, 0); - sppp_attach(sc->ifp); - sc->sppp->pp_tls = sppp_tls; - sc->sppp->pp_tlf = sppp_tlf; - config->keep_alive = 1; - - sc->config.stack = STACK_SPPP; - sc->stack = &sppp_stack; - - return 0; - } - -static int /* never fails */ -sppp_stack_detach(softc_t *sc) - { - sc->ifp->if_flags &= ~IFF_UP; /* down */ - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); /* close() */ - sppp_detach(sc->ifp); - LMC_BPF_DETACH(sc); - - ifnet_setup(sc->ifp); - sc->config.stack = STACK_NONE; - sc->config.proto = PROTO_NONE; - sc->stack = NULL; - - return 0; - } - -/* Callout from SPPP: */ -static void -sppp_tls(struct sppp *sppp) - { - /* Calling pp_up/down() required by PPP mode in OpenBSD. */ - /* Calling pp_up/down() panics PPP mode in NetBSD. */ - /* Calling pp_up/down() breaks Cisco mode in FreeBSD. */ - if (!(sppp->pp_flags & PP_CISCO)) /* not Cisco */ - sppp->pp_up(sppp); - } - -/* Callout from SPPP: */ -static void -sppp_tlf(struct sppp *sppp) - { - /* Calling pp_up/down() required by PPP mode in OpenBSD. */ - /* Calling pp_up/down() panics PPP mode in NetBSD. */ - /* Calling pp_up/down() breaks Cisco mode in FreeBSD. */ - if (!(sppp->pp_flags & PP_CISCO)) /* not Cisco */ - sppp->pp_down(sppp); - } - -#endif /* SPPP */ - -/* RawIP is built into the driver. */ - -static struct stack rawip_stack = - { -#if IFNET - .ioctl = rawip_ioctl, - .input = rawip_input, - .output = rawip_output, -#elif NETDEV - .ioctl = rawip_ioctl, - .type = rawip_type, - .mtu = rawip_mtu, -#endif - .watchdog = rawip_watchdog, - .open = rawip_open, - .attach = rawip_attach, - .detach = rawip_detach, - }; - -#if IFNET - -static int /* context: process */ -rawip_ioctl(softc_t *sc, u_long cmd, void *data) - { - struct ifreq *ifr = (struct ifreq *) data; - int error = 0; - - switch (cmd) - { - case SIOCADDMULTI: - case SIOCDELMULTI: - if (sc->config.debug) - printf("%s: rawip_ioctl: SIOCADD/DELMULTI\n", NAME_UNIT); - case SIOCSIFFLAGS: - error = ifioctl_common(sc->ifp, cmd, data); - break; - case SIOCAIFADDR: - case SIOCSIFDSTADDR: - break; - case SIOCINITIFADDR: - sc->ifp->if_flags |= IFF_UP; /* a Unix tradition */ - break; - case SIOCSIFMTU: - if ((ifr->ifr_mtu < 72) || (ifr->ifr_mtu > 65535)) - error = EINVAL; - else if ((error = ifioctl_common(sc->ifp, cmd, data)) == ENETRESET) - error = 0; - break; - default: - error = EINVAL; - break; - } - - return error; - } - -static void /* context: interrupt */ -rawip_input(softc_t *sc, struct mbuf *mbuf) - { - ifnet_input(sc->ifp, mbuf); - } - -static void /* context: interrupt */ -rawip_output(softc_t *sc) - { - IFQ_DEQUEUE(&sc->ifp->if_snd, sc->tx_mbuf); - } - -#elif NETDEV - -static int /* context: process */ -rawip_ioctl(softc_t *sc, struct ifreq *ifr, int cmd) - { - if (sc->config.debug) - printk("%s: rawip_ioctl; cmd=0x%08x\n", NAME_UNIT, cmd); - return -EINVAL; - } - -static int /* context: interrupt */ -rawip_type(softc_t *sc, struct sk_buff *skb) - { - if (skb->data[0]>>4 == 4) - return htons(ETH_P_IP); - else if (skb->data[0]>>4 == 6) - return htons(ETH_P_IPV6); - else - return htons(ETH_P_HDLC); - } - -static int /* Process Context */ -rawip_mtu(softc_t *sc, int mtu) - { - return ((mtu < 72) || (mtu > 65535)) ? -EINVAL : 0; - } - -#endif /* IFNET */ - -static void /* context: softirq */ -rawip_watchdog(softc_t *sc) - { -#if IFNET - if ((sc->status.link_state == STATE_UP) && - (sc->ifp->if_flags & IFF_UP)) - sc->ifp->if_flags |= IFF_RUNNING; - if ((sc->status.link_state != STATE_UP) || - !(sc->ifp->if_flags & IFF_UP)) - sc->ifp->if_flags &= ~IFF_RUNNING; -#endif /* IFNET */ - - /* Report current line protocol. */ - sc->status.stack = STACK_RAWIP; - sc->status.proto = PROTO_IP_HDLC; - } - -static int -rawip_open(softc_t *sc, struct config *config) - { - sc->config.proto = PROTO_IP_HDLC; - - return 0; - } - -static int -rawip_attach(softc_t *sc, struct config *config) - { -#if IFNET - LMC_BPF_ATTACH(sc, DLT_RAW, 0); -#endif - - sc->config.stack = STACK_RAWIP; - sc->stack = &rawip_stack; - - return 0; - } - -static int -rawip_detach(softc_t *sc) - { -#if IFNET - LMC_BPF_DETACH(sc); - ifnet_setup(sc->ifp); -#elif NETDEV - netdev_setup(sc->netdev); -#endif - - sc->config.stack = STACK_NONE; - sc->config.proto = PROTO_NONE; - sc->stack = NULL; - - return 0; - } - -#if IFNET - -/* Called to give a newly arrived pkt to higher levels. */ -/* Called from rxintr_cleanup() with bottom_lock held. */ -/* This is only used with rawip_stack on a BSD. */ -static void -ifnet_input(struct ifnet *ifp, struct mbuf *mbuf) - { - softc_t *sc = IFP2SC(ifp); - pktqueue_t *pktq = NULL; - -# if INET - if (mbuf->m_data[0]>>4 == 4) - pktq = ip_pktq; -# endif /* INET */ - -# if INET6 - if (mbuf->m_data[0]>>4 == 6) - pktq = ip6_pktq; -# endif /* INET6 */ - - if (!pktq) - { - m_freem(mbuf); - sc->status.cntrs.idrops++; - if (sc->config.debug) - printf("%s: ifnet_input: rx pkt dropped: not IPv4 or IPv6\n", NAME_UNIT); - return; - } - - DISABLE_INTR; - if (__predict_false(!pktq_enqueue(pktq, mbuf, 0))) - { - sc->status.cntrs.idrops++; - m_freem(mbuf); - } - ENABLE_INTR; - } - -/* sppp and p2p replace this with their own proc. - * This is only used with rawip_stack on a BSD. - * This procedure is very similar to ng_rcvdata(). - */ -static int /* context: process */ -ifnet_output(struct ifnet *ifp, struct mbuf *m, - const struct sockaddr *dst, const struct rtentry *rt) - { - softc_t *sc = IFP2SC(ifp); - int error = 0; - - /* Fail if the link is down. */ - if (sc->status.link_state != STATE_UP) - { - m_freem(m); - sc->status.cntrs.odrops++; - if (sc->config.debug) - printf("%s: ifnet_output: tx pkt dropped: link down\n", NAME_UNIT); - return ENETDOWN; - } - - /* ifnet_output() ENQUEUEs in a syscall or softirq. */ - /* txintr_setup() DEQUEUEs in a hard interrupt. */ - /* Some BSD QUEUE routines are not interrupt-safe. */ - { - DISABLE_INTR; /* noop in FreeBSD */ - IFQ_ENQUEUE(&ifp->if_snd, m, error); - ENABLE_INTR; /* noop in FreeBSD */ - } - - if (error) - { - sc->status.cntrs.odrops++; - if (sc->config.debug) - printf("%s: ifnet_output: tx pkt dropped: IFQ_ENQUEUE(): error %d\n", - NAME_UNIT, error); - } - else - /* Process tx pkts; do not process rx pkts. */ - ifnet_start(ifp); - - return error; - } - -static int /* context: process */ -ifnet_ioctl(struct ifnet *ifp, u_long cmd, void *data) - { - softc_t *sc = IFP2SC(ifp); - struct ifreq *ifr = (struct ifreq *) data; - int error = 0; - - /* Aquire ioctl/watchdog interlock. */ - if ((error = TOP_LOCK(sc))) return error; - - switch (cmd) - { - /* Catch the IOCTLs used by lmcconfig. */ - case LMCIOCGSTAT: - case LMCIOCGCFG: - case LMCIOCSCFG: - case LMCIOCREAD: - case LMCIOCWRITE: - case LMCIOCTL: - error = lmc_ioctl(sc, cmd, data); - break; - - case SIOCSIFCAP: -# if DEVICE_POLLING - if ((ifr->ifr_reqcap & IFCAP_POLLING) && - !(ifp->if_capenable & IFCAP_POLLING) && - !(error = ether_poll_register(bsd_poll, ifp))) - { /* enable polling */ - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_DISABLE); - ifp->if_capenable |= IFCAP_POLLING; - } - else if (!(ifr->ifr_reqcap & IFCAP_POLLING) && - (ifp->if_capenable & IFCAP_POLLING) && - !(error = ether_poll_deregister(ifp))) - { /* disable polling */ - ifp->if_capenable &= ~IFCAP_POLLING; - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_TXRX); - } - else - error = EINVAL; -# endif /* DEVICE_POLLING */ - break; - - case SIOCSIFMEDIA: /* calls lmc_ifmedia_change() */ - case SIOCGIFMEDIA: /* calls ifmedia_status() */ - error = ifmedia_ioctl(ifp, ifr, &sc->ifm, cmd); - break; - - - /* Pass the rest to the line protocol. */ - default: - if (sc->stack) - error = sc->stack->ioctl(sc, cmd, data); - else - error = ENOSYS; - break; - } - - /* release ioctl/watchdog interlock */ - TOP_UNLOCK(sc); - - if (error && sc->config.debug) - printf("%s: ifnet_ioctl: op=IO%s%s len=%3lu grp='%c' num=%3lu err=%d\n", - NAME_UNIT, cmd&IOC_IN ? "W":"", cmd&IOC_OUT ? "R":"", - IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xFF, error); - - return error; - } - -static void /* context: process */ -ifnet_start(struct ifnet *ifp) - { - softc_t *sc = IFP2SC(ifp); - int activity; - - /* Do this FIRST! Otherwise UPs deadlock and MPs spin. */ - WRITE_CSR(sc, TLP_STATUS, READ_CSR(sc, TLP_STATUS)); - - /* If any CPU is inside this critical section, then */ - /* other CPUs should go away without doing anything. */ - if (BOTTOM_TRYLOCK(sc) == 0) - { - sc->status.cntrs.lck_intr++; - return; - } - - /* In Linux, pci_alloc_consistent() means DMA */ - /* descriptors do not need explicit syncing? */ -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - } -#endif - - do - { - activity = txintr_setup(sc); - } while (activity); - -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - } -#endif - - BOTTOM_UNLOCK(sc); - } - -static void /* context: softirq */ -ifnet_watchdog(struct ifnet *ifp) - { - softc_t *sc = IFP2SC(ifp); - struct cntrs *cntrs = &sc->status.cntrs; - - lmc_watchdog(sc); /* updates link_state */ - - if (sc->status.link_state == STATE_UP) - ifp->if_link_state = LINK_STATE_UP; - else - ifp->if_link_state = LINK_STATE_DOWN; - - /* Copy statistics from sc to ifp. */ - ifp->if_baudrate = sc->status.tx_speed; - ifp->if_ibytes = cntrs->ibytes; - ifp->if_obytes = cntrs->obytes; - ifp->if_ipackets = cntrs->ipackets; - ifp->if_opackets = cntrs->opackets; - ifp->if_ierrors = cntrs->ierrors; - ifp->if_oerrors = cntrs->oerrors; - ifp->if_iqdrops = cntrs->idrops; - - /* If the interface debug flag is set, set the driver debug flag. */ - if (sc->ifp->if_flags & IFF_DEBUG) - sc->config.debug = 1; - - /* Call this procedure again after one second. */ - ifp->if_timer = 1; - } - -/* This setup is for RawIP; SPPP and P2P change many items. */ -/* Note the similarity to linux's netdev_setup(). */ -static void -ifnet_setup(struct ifnet *ifp) - { - ifp->if_flags = IFF_POINTOPOINT; - ifp->if_flags |= IFF_SIMPLEX; - ifp->if_flags |= IFF_NOARP; - ifp->_if_input = ifnet_input; - ifp->if_output = ifnet_output; - ifp->if_start = ifnet_start; - ifp->if_ioctl = ifnet_ioctl; - ifp->if_watchdog = ifnet_watchdog; - ifp->if_timer = 1; - ifp->if_type = IFT_PTPSERIAL; - ifp->if_addrlen = 0; - ifp->if_hdrlen = 0; - ifp->if_mtu = MAX_DESC_LEN; - } - -/* Attach the ifnet kernel interface. */ -/* context: kernel (boot) or process (syscall) */ -static int -ifnet_attach(softc_t *sc) - { -# if SPPP - sc->ifp = &sc->spppcom.pp_if; -# elif P2P - sc->ifp = &sc->p2pcom.p2p_if; -# else - sc->ifp = &sc->ifnet; -# endif - - sc->ifp->if_softc = sc; - ifnet_setup(sc->ifp); - -# if DEVICE_POLLING - sc->ifp->if_capabilities |= IFCAP_POLLING; -# endif - - /* Every OS does it differently! */ - strlcpy(sc->ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); - - IFQ_SET_MAXLEN(&sc->ifp->if_snd, SNDQ_MAXLEN); - IFQ_SET_READY(&sc->ifp->if_snd); - - if_attach(sc->ifp); - - if_alloc_sadl(sc->ifp); - - ifmedia_setup(sc); - - return 0; - } - -/* Detach the ifnet kernel interface. */ -/* context: kernel (boot) or process (syscall). */ -static void -ifnet_detach(softc_t *sc) - { - ifmedia_delete_instance(&sc->ifm, IFM_INST_ANY); - -# if DEVICE_POLLING - if (sc->ifp->if_capenable & IFCAP_POLLING) - ether_poll_deregister(sc->ifp); -# endif - - IFQ_PURGE(&sc->ifp->if_snd); - - if_detach(sc->ifp); - - } - -static void -ifmedia_setup(softc_t *sc) - { - /* Initialize ifmedia mechanism. */ - ifmedia_init(&sc->ifm, IFM_OMASK | IFM_GMASK | IFM_IMASK, - lmc_ifmedia_change, ifmedia_status); - - ifmedia_add(&sc->ifm, IFM_ETHER | IFM_NONE, 0, NULL); - ifmedia_set(&sc->ifm, IFM_ETHER | IFM_NONE); - } - -/* SIOCSIFMEDIA: context: process. */ -static int -lmc_ifmedia_change(struct ifnet *ifp) - { - softc_t *sc = IFP2SC(ifp); - struct config config = sc->config; - int media = sc->ifm.ifm_media; - int error; - - - /* ifconfig lmc0 mediaopt loopback */ - if (media & IFM_LOOP) - config.loop_back = CFG_LOOP_TULIP; - else - config.loop_back = CFG_LOOP_NONE; - - error = open_proto(sc, &config); - tulip_loop(sc, &config); - sc->card->attach(sc, &config); - - return error; - } - -/* SIOCGIFMEDIA: context: process. */ -static void -ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) - { - softc_t *sc = IFP2SC(ifp); - - ifmr->ifm_status = IFM_AVALID; - if (sc->status.link_state == STATE_UP) - ifmr->ifm_status |= IFM_ACTIVE; - - if (sc->config.loop_back != CFG_LOOP_NONE) - ifmr->ifm_active |= IFM_LOOP; - - } - -#endif /* IFNET */ - -#if NETDEV - -/* This net_device method is called when IFF_UP goes true. */ -static int /* context: process */ -netdev_open(struct net_device *netdev) - { - softc_t *sc = NETDEV2SC(netdev); - - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_TXRX); - netif_start_queue(sc->netdev); - set_ready(sc, 1); - - return 0; - } - -/* This net_device method is called when IFF_UP goes false. */ -static int /* context: process */ -netdev_stop(struct net_device *netdev) - { - softc_t *sc = NETDEV2SC(netdev); - - set_ready(sc, 0); - netif_stop_queue(sc->netdev); - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_DISABLE); - - return 0; - } - -/* This net_device method hands outgoing packets to the transmitter. */ -/* With txintr_setup(), it implements output flow control. */ -static int /* context: netdev->xmit_lock held; BHs disabled */ -netdev_start(struct sk_buff *skb, struct net_device *netdev) - { - softc_t *sc = NETDEV2SC(netdev); - - if (sc->tx_skb == NULL) - { - /* Put this skb where the transmitter will see it. */ - sc->tx_skb = skb; - - /* Process tx pkts; do not process rx pkts. */ - lmc_interrupt(sc, 0, 0); - - return NETDEV_TX_OK; - } - else - { - /* txintr_setup() calls netif_wake_queue(). */ - netif_stop_queue(netdev); - return NETDEV_TX_BUSY; - } - } - -# if NAPI - -/* This net_device method services the card without interrupts. */ -/* With rxintr_cleanup(), it implements input flow control. */ -static int /* context: softirq */ -netdev_poll(struct net_device *netdev, int *budget) - { - softc_t *sc = NETDEV2SC(netdev); - int received; - - /* Handle the card interrupt with kernel ints enabled. */ - /* Allow processing up to netdev->quota incoming packets. */ - /* This is the ONLY time lmc_interrupt() may process rx pkts. */ - /* Otherwise (sc->quota == 0) and rxintr_cleanup() is a NOOP. */ - lmc_interrupt(sc, uimin(netdev->quota, *budget), 0); - - /* Report number of rx packets processed. */ - received = netdev->quota - sc->quota; - netdev->quota -= received; - *budget -= received; - - /* If quota prevented processing all rx pkts, leave rx ints disabled. */ - if (sc->quota == 0) /* this is off by one...but harmless */ - { - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_TX); - return 1; /* more pkts to handle -- reschedule */ - } - - /* Remove self from poll list. */ - netif_rx_complete(netdev); - - /* Enable card interrupts. */ - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_TXRX); - - return 0; /* all pkts handled -- success */ - } - -# endif /* NAPI */ - -/* This net_device method handles IOCTL syscalls. */ -static int /* context: process */ -netdev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) - { - softc_t *sc = NETDEV2SC(netdev); - int error = 0; - - /* Aquire ioctl/watchdog interlock. */ - if ((error = TOP_LOCK(sc))) return error; - - if ((cmd >= SIOCDEVPRIVATE) && (cmd <= SIOCDEVPRIVATE+15)) - { - struct iohdr *iohdr = (struct iohdr *)ifr; - u_int16_t direction = iohdr->direction; - u_int16_t length = iohdr->length; - char *user_addr = (char *)iohdr->iohdr; - char *kern_addr = NULL; - - if (iohdr->cookie != NGM_LMC_COOKIE) - error = -EINVAL; - - /* Emulate a BSD-style IOCTL syscall. */ - if (!error) - error = (kern_addr = kmalloc(length, GFP_KERNEL)) ? 0: -ENOMEM; - if (!error && (direction & DIR_IOW)) - error = copy_from_user(kern_addr, user_addr, length); - if (!error) - error = -lmc_ioctl(sc, (unsigned long)cmd, kern_addr); - if (!error && (direction & DIR_IOR)) - error = copy_to_user(user_addr, kern_addr, length); - kfree(kern_addr); - } - else if (sc->stack) - error = sc->stack->ioctl(sc, ifr, cmd); - else - error = -ENOSYS; -# if GEN_HDLC - /* If generic-HDLC is present but not the currently-attached - * stack, call hdlc_ioctl() anyway because proto must - * be set using SIOCWANDEV or hdlc_open() will fail. - */ - if (sc->stack != &gen_hdlc_stack) - hdlc_ioctl(sc->netdev, ifr, cmd); /* ignore error result */ -# endif - - /* Release ioctl/watchdog interlock. */ - TOP_UNLOCK(sc); - - if (error && sc->config.debug) - printk("%s: netdev_ioctl; cmd=0x%08x error=%d\n", - NAME_UNIT, cmd, error); - - return error; - } - -/* This net_device method sets the Maximum Tranmit Unit. */ -/* This driver does not limit MTU; stacks and protos do. */ -static int -netdev_mtu(struct net_device *netdev, int mtu) - { - softc_t *sc = NETDEV2SC(netdev); - int error = 0; - - if (sc->stack) - error = sc->stack->mtu(sc, mtu); - else - error = -ENOSYS; - - if (!error) - netdev->mtu = mtu; - - return error; - } - -/* This net_device method restarts the transmitter if it hangs. */ -static void /* BHs disabled */ -netdev_timeout(struct net_device *netdev) - { - softc_t *sc = NETDEV2SC(netdev); - - /* Process tx pkts; do not process rx pkts. */ - lmc_interrupt(sc, 0, 0); - } - -/* This net_device method returns a pointer to device statistics. */ -static struct net_device_stats * /* context: process */ -netdev_stats(struct net_device *netdev) - { - softc_t *sc = NETDEV2SC(netdev); - -# if GEN_HDLC - return &sc->hdlcdev->stats; -# else - return &sc->netdev_stats; -# endif - } - -static void /* context: softirq */ -netdev_watchdog(unsigned long softc) - { - softc_t *sc = (softc_t *)softc; - struct cntrs *cntrs = &sc->status.cntrs; - struct net_device_stats *stats = netdev_stats(sc->netdev); - - lmc_watchdog(sc); /* updates link_state */ - - /* Notice when the link comes up. */ - if ((sc->last_link_state != STATE_UP) && - (sc->status.link_state == STATE_UP)) - { - netif_wake_queue(sc->netdev); - netif_carrier_on(sc->netdev); - } - - /* Notice when the link goes down. */ - if ((sc->last_link_state == STATE_UP) && - (sc->status.link_state != STATE_UP)) - { - netif_tx_disable(sc->netdev); - netif_carrier_off(sc->netdev); - } - - /* Copy statistics from sc to netdev. */ - stats->rx_bytes = cntrs->ibytes; - stats->tx_bytes = cntrs->obytes; - stats->rx_packets = cntrs->ipackets; - stats->tx_packets = cntrs->opackets; - stats->rx_errors = cntrs->ierrors; - stats->tx_errors = cntrs->oerrors; - stats->rx_dropped = cntrs->idrops; - stats->rx_missed_errors = cntrs->missed; - stats->tx_dropped = cntrs->odrops; - stats->rx_fifo_errors = cntrs->fifo_over; - stats->rx_over_errors = cntrs->overruns; - stats->tx_fifo_errors = cntrs->fifo_under; -/*stats->tx_under_errors = cntrs=>underruns; */ - - /* If the interface debug flag is set, set the driver debug flag. */ - if (sc->netdev->flags & IFF_DEBUG) - sc->config.debug = 1; - - /* Call this procedure again after one second. */ - sc->wd_timer.expires = jiffies + HZ -8; /* -8 is a FUDGE factor */ - add_timer(&sc->wd_timer); - } - -/* This setup is for RawIP; Generic-HDLC changes many items. */ -/* Note the similarity to BSD's ifnet_setup(). */ -static void -netdev_setup(struct net_device *netdev) - { - netdev->flags = IFF_POINTOPOINT; - netdev->flags |= IFF_NOARP; - netdev->open = netdev_open; - netdev->stop = netdev_stop; - netdev->hard_start_xmit = netdev_start; -# if NAPI - netdev->poll = netdev_poll; - netdev->weight = 32; /* sc->rxring.num_descs; */ -# endif - netdev->rebuild_header = NULL; /* no arp */ - netdev->hard_header = NULL; /* no arp */ - netdev->do_ioctl = netdev_ioctl; - netdev->change_mtu = netdev_mtu; - netdev->tx_timeout = netdev_timeout; - netdev->get_stats = netdev_stats; - netdev->watchdog_timeo = 1 * HZ; - netdev->mtu = MAX_DESC_LEN; - netdev->type = ARPHRD_HDLC; - netdev->hard_header_len = 16; - netdev->addr_len = 0; - netdev->tx_queue_len = SNDQ_MAXLEN; -/* The receiver generates frag-lists for packets >4032 bytes. */ -/* The transmitter accepts scatter/gather lists and frag-lists. */ -/* However Linux linearizes outgoing packets since our hardware */ -/* does not compute soft checksums. All that work for nothing! */ -/*netdev->features |= NETIF_F_SG; */ -/*netdev->features |= NETIF_F_FRAGLIST; */ - } - -/* Attach the netdevice kernel interface. */ -/* context: kernel (boot) or process (syscall). */ -static int -netdev_attach(softc_t *sc) - { - int error; - -# if GEN_HDLC /* generic-hdlc line protocol pkg configured */ - - /* Allocate space for the HDLC network device struct. */ - /* Allocating a netdev and attaching to generic-HDLC should be separate. */ - if ((sc->netdev = alloc_hdlcdev(sc)) == NULL) - { - printk("%s: netdev_attach: alloc_hdlcdev() failed\n", DEVICE_NAME); - return -ENOMEM; - } - - /* Initialize the basic network device struct. */ - /* This clobbers some netdev stuff set by alloc_hdlcdev(). */ - /* Our get_stats() and change_mtu() do the right thing. */ - netdev_setup(sc->netdev); - - /* HACK: make the private eco-net pointer -> struct softc. */ - sc->netdev->ec_ptr = sc; - - /* Cross-link pcidev and netdev. */ - SET_NETDEV_DEV(sc->netdev, &sc->pcidev->dev); - sc->netdev->mem_end = pci_resource_end(sc->pcidev, 1); - sc->netdev->mem_start = pci_resource_start(sc->pcidev, 1); - sc->netdev->base_addr = pci_resource_start(sc->pcidev, 0); - sc->netdev->irq = sc->pcidev->irq; - - /* Initialize the HDLC extension to the network device. */ - sc->hdlcdev = sc->netdev->priv; - sc->hdlcdev->attach = gen_hdlc_card_params; - sc->hdlcdev->xmit = netdev_start; /* the REAL hard_start_xmit() */ - - if ((error = register_hdlc_device(sc->netdev))) - { - printk("%s: register_hdlc_device(): error %d\n", DEVICE_NAME, error); - free_netdev(sc->netdev); - return error; - } - -# else - - /* Allocate and initialize the basic network device struct. */ - if ((sc->netdev = alloc_netdev(0, DEVICE_NAME"%d", netdev_setup)) == NULL) - { - printk("%s: netdev_attach: alloc_netdev() failed\n", DEVICE_NAME); - return -ENOMEM; - } - - /* HACK: make the private eco-net pointer -> struct softc. */ - sc->netdev->ec_ptr = sc; - - /* Cross-link pcidev and netdev. */ - SET_NETDEV_DEV(sc->netdev, &sc->pcidev->dev); - sc->netdev->mem_end = pci_resource_end(sc->pcidev, 1); - sc->netdev->mem_start = pci_resource_start(sc->pcidev, 1); - sc->netdev->base_addr = pci_resource_start(sc->pcidev, 0); - sc->netdev->irq = sc->pcidev->irq; - - if ((error = register_netdev(sc->netdev))) - { - printk("%s: register_netdev(): error %d\n", DEVICE_NAME, error); - free_netdev(sc->netdev); - return error; - } - -# endif /* GEN_HDLC */ - - /* Arrange to call netdev_watchdog() once a second. */ - init_timer(&sc->wd_timer); - sc->wd_timer.expires = jiffies + HZ; /* now plus one second */ - sc->wd_timer.function = &netdev_watchdog; - sc->wd_timer.data = (unsigned long) sc; - add_timer(&sc->wd_timer); - - return 0; /* success */ - } - -/* Detach the netdevice kernel interface. */ -/* context: kernel (boot) or process (syscall). */ -static void -netdev_detach(softc_t *sc) - { - if (sc->pcidev == NULL) return; - if (sc->netdev == NULL) return; - - netdev_stop(sc->netdev); /* check for not inited */ - del_timer(&sc->wd_timer); - -# if GEN_HDLC - unregister_hdlc_device(sc->netdev); -# else - unregister_netdev(sc->netdev); -# endif - - free_netdev(sc->netdev); - } - -#endif /* NETDEV */ - - -#if BSD - -/* There are TWO VERSIONS of interrupt/DMA code: Linux & BSD. - * Handling Linux and the BSDs with CPP directives would - * make the code unreadable, so there are two versions. - * Conceptually, the two versions do the same thing and - * lmc_interrupt() does not know they are different. - * - * We are "standing on the head of a pin" in these routines. - * Tulip CSRs can be accessed, but nothing else is interrupt-safe! - * Do NOT access: MII, GPIO, SROM, BIOSROM, XILINX, SYNTH, or DAC. - */ - -/* Initialize a DMA descriptor ring. */ -/* context: kernel (boot) or process (syscall) */ -static int /* BSD version */ -create_ring(softc_t *sc, struct desc_ring *ring, int num_descs) - { - struct dma_desc *descs; - int size_descs = sizeof(struct dma_desc)*num_descs; - int i, error = 0; - - /* The DMA descriptor array must not cross a page boundary. */ - if (size_descs > PAGE_SIZE) - { - printf("%s: DMA descriptor array > PAGE_SIZE (%d)\n", NAME_UNIT, - (u_int)PAGE_SIZE); - return EINVAL; - } - - - /* Use the DMA tag passed to attach() for descriptors and buffers. */ - ring->tag = sc->pa_dmat; - - /* Allocate wired physical memory for DMA descriptor array. */ - if ((error = bus_dmamem_alloc(ring->tag, size_descs, PAGE_SIZE, 0, - ring->segs, 1, &ring->nsegs, BUS_DMA_NOWAIT))) - { - printf("%s: bus_dmamem_alloc(): error %d\n", NAME_UNIT, error); - return error; - } - - /* Map physical address to kernel virtual address. */ - if ((error = bus_dmamem_map(ring->tag, ring->segs, ring->nsegs, - size_descs, (void **)&ring->first, BUS_DMA_NOWAIT | BUS_DMA_COHERENT))) - { - printf("%s: bus_dmamem_map(): error %d\n", NAME_UNIT, error); - return error; - } - descs = ring->first; /* suppress compiler warning about aliasing */ - memset(descs, 0, size_descs); - - /* Allocate dmamap for PCI access to DMA descriptor array. */ - if ((error = bus_dmamap_create(ring->tag, size_descs, 1, - size_descs, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ring->map))) - { - printf("%s: bus_dmamap_create(): error %d\n", NAME_UNIT, error); - return error; - } - - /* Map kernel virt addr to PCI bus addr for DMA descriptor array. */ - if ((error = bus_dmamap_load(ring->tag, ring->map, descs, size_descs, - 0, BUS_DMA_NOWAIT))) - { - printf("%s: bus_dmamap_load(): error %d\n", NAME_UNIT, error); - return error; - } - ring->dma_addr = ring->map->dm_segs[0].ds_addr; - - /* Allocate dmamaps for each DMA descriptor. */ - for (i=0; i<num_descs; i++) - if ((error = bus_dmamap_create(ring->tag, MAX_DESC_LEN, 2, - MAX_CHUNK_LEN, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &descs[i].map))) - { - printf("%s: bus_dmamap_create(): error %d\n", NAME_UNIT, error); - return error; - } - - - ring->read = descs; - ring->write = descs; - ring->first = descs; - ring->last = descs + num_descs -1; - ring->last->control = TLP_DCTL_END_RING; - ring->num_descs = num_descs; - ring->size_descs = size_descs; - ring->head = NULL; - ring->tail = NULL; - - return 0; - } - -/* Destroy a DMA descriptor ring */ -/* context: kernel (boot) or process (syscall) */ -static void /* BSD version */ -destroy_ring(softc_t *sc, struct desc_ring *ring) - { - struct dma_desc *desc; - struct mbuf *m; - - /* Free queued mbufs. */ - while ((m = mbuf_dequeue(ring))) - m_freem(m); - - /* TX may have one pkt that is not on any queue. */ - if (sc->tx_mbuf) - { - m_freem(sc->tx_mbuf); - sc->tx_mbuf = NULL; - } - - /* Unmap active DMA descriptors. */ - while (ring->read != ring->write) - { - bus_dmamap_unload(ring->tag, ring->read->map); - if (ring->read++ == ring->last) ring->read = ring->first; - } - - - /* Free the dmamaps of all DMA descriptors. */ - for (desc=ring->first; desc!=ring->last+1; desc++) - if (desc->map) - bus_dmamap_destroy(ring->tag, desc->map); - /* Unmap PCI address for DMA descriptor array. */ - if (ring->dma_addr) - bus_dmamap_unload(ring->tag, ring->map); - /* Free dmamap for DMA descriptor array. */ - if (ring->map) - bus_dmamap_destroy(ring->tag, ring->map); - /* Unmap kernel address for DMA descriptor array. */ - if (ring->first) - bus_dmamem_unmap(ring->tag, (void *)ring->first, ring->size_descs); - /* Free kernel memory for DMA descriptor array. */ - if (ring->segs[0].ds_addr) - bus_dmamem_free(ring->tag, ring->segs, ring->nsegs); - - } - -/* Singly-linked tail-queues hold mbufs with active DMA. - * For RX, single mbuf clusters; for TX, mbuf chains are queued. - * NB: mbufs are linked through their m_nextpkt field. - * Callers must hold sc->bottom_lock; not otherwise locked. - */ - -/* Put an mbuf (chain) on the tail of the descriptor ring queue. */ -static void /* BSD version */ -mbuf_enqueue(struct desc_ring *ring, struct mbuf *m) - { - m->m_nextpkt = NULL; - if (ring->tail == NULL) - ring->head = m; - else - ring->tail->m_nextpkt = m; - ring->tail = m; - } - -/* Get an mbuf (chain) from the head of the descriptor ring queue. */ -static struct mbuf* /* BSD version */ -mbuf_dequeue(struct desc_ring *ring) - { - struct mbuf *m = ring->head; - if (m) - if ((ring->head = m->m_nextpkt) == NULL) - ring->tail = NULL; - return m; - } - -/* Clean up after a packet has been received. */ -static int /* BSD version */ -rxintr_cleanup(softc_t *sc) - { - struct desc_ring *ring = &sc->rxring; - struct dma_desc *first_desc, *last_desc; - struct mbuf *first_mbuf=NULL, *last_mbuf=NULL; - struct mbuf *new_mbuf; - int pkt_len, desc_len; - - /* Input packet flow control (livelock prevention): */ - /* Give pkts to higher levels only if quota is > 0. */ - if (sc->quota <= 0) return 0; - - /* This looks complicated, but remember: typically packets up */ - /* to 2048 bytes long fit in one mbuf and use one descriptor. */ - - first_desc = last_desc = ring->read; - - /* ASSERTION: If there is a descriptor in the ring and the hardware has */ - /* finished with it, then that descriptor will have RX_FIRST_DESC set. */ - if ((ring->read != ring->write) && /* descriptor ring not empty */ - !(ring->read->status & TLP_DSTS_OWNER) && /* hardware done */ - !(ring->read->status & TLP_DSTS_RX_FIRST_DESC)) /* should be set */ - panic("%s: rxintr_cleanup: rx-first-descriptor not set.\n", NAME_UNIT); - - /* First decide if a complete packet has arrived. */ - /* Run down DMA descriptors looking for one marked "last". */ - /* Bail out if an active descriptor is encountered. */ - /* Accumulate most significant bits of packet length. */ - pkt_len = 0; - for (;;) - { - if (last_desc == ring->write) return 0; /* no more descs */ - if (last_desc->status & TLP_DSTS_OWNER) return 0; /* still active */ - if (last_desc->status & TLP_DSTS_RX_LAST_DESC) break; /* end of packet */ - pkt_len += last_desc->length1 + last_desc->length2; /* entire desc filled */ - if (last_desc++->control & TLP_DCTL_END_RING) last_desc = ring->first; /* ring wrap */ - } - - /* A complete packet has arrived; how long is it? */ - /* H/w ref man shows RX pkt length as a 14-bit field. */ - /* An experiment found that only the 12 LSBs work. */ - if (((last_desc->status>>16)&0xFFF) == 0) pkt_len += 4096; /* carry-bit */ - pkt_len = (pkt_len & 0xF000) + ((last_desc->status>>16) & 0x0FFF); - /* Subtract the CRC length unless doing so would underflow. */ - if (pkt_len >= sc->config.crc_len) pkt_len -= sc->config.crc_len; - - /* Run down DMA descriptors again doing the following: - * 1) put pkt info in pkthdr of first mbuf, - * 2) link mbufs, - * 3) set mbuf lengths. - */ - first_desc = ring->read; - do - { - /* Read a DMA descriptor from the ring. */ - last_desc = ring->read; - /* Advance the ring read pointer. */ - if (ring->read++ == ring->last) ring->read = ring->first; - - /* Dequeue the corresponding cluster mbuf. */ - new_mbuf = mbuf_dequeue(ring); - if (new_mbuf == NULL) - panic("%s: rxintr_cleanup: expected an mbuf\n", NAME_UNIT); - - desc_len = last_desc->length1 + last_desc->length2; - /* If bouncing, copy bounce buf to mbuf. */ - DMA_SYNC(last_desc->map, desc_len, BUS_DMASYNC_POSTREAD); - /* Unmap kernel virtual address to PCI bus address. */ - bus_dmamap_unload(ring->tag, last_desc->map); - - /* 1) Put pkt info in pkthdr of first mbuf. */ - if (last_desc == first_desc) - { - first_mbuf = new_mbuf; - first_mbuf->m_pkthdr.len = pkt_len; /* total pkt length */ -# if IFNET - m_set_rcvif(first_mbuf, sc->ifp); /* how it got here */ -# else - m_reset_rcvif(first_mbuf); -# endif - } - else /* 2) link mbufs. */ - { - KASSERT(last_mbuf != NULL); - last_mbuf->m_next = new_mbuf; - /* M_PKTHDR should be set in the first mbuf only. */ - new_mbuf->m_flags &= ~M_PKTHDR; - } - last_mbuf = new_mbuf; - - /* 3) Set mbuf lengths. */ - new_mbuf->m_len = (pkt_len >= desc_len) ? desc_len : pkt_len; - pkt_len -= new_mbuf->m_len; - } while ((last_desc->status & TLP_DSTS_RX_LAST_DESC)==0); - - /* Decide whether to accept or to drop this packet. */ - /* RxHDLC sets MIIERR for bad CRC, abort and partial byte at pkt end. */ - if (!(last_desc->status & TLP_DSTS_RX_BAD) && - (sc->status.link_state == STATE_UP) && - (first_mbuf->m_pkthdr.len > 0)) - { - /* Optimization: copy a small pkt into a small mbuf. */ - if (first_mbuf->m_pkthdr.len <= COPY_BREAK) - { - MGETHDR(new_mbuf, M_DONTWAIT, MT_DATA); - if (new_mbuf) - { - m_copy_rcvif(new_mbuf, first_mbuf); - new_mbuf->m_pkthdr.len = first_mbuf->m_pkthdr.len; - new_mbuf->m_len = first_mbuf->m_len; - memcpy(new_mbuf->m_data, first_mbuf->m_data, - first_mbuf->m_pkthdr.len); - m_freem(first_mbuf); - first_mbuf = new_mbuf; - } - } - - /* Include CRC and one flag byte in input byte count. */ - sc->status.cntrs.ibytes += first_mbuf->m_pkthdr.len + sc->config.crc_len +1; - sc->status.cntrs.ipackets++; - - /* Berkeley Packet Filter */ - bpf_mtap_softint(sc->ifp, first_mbuf); - - /* Give this good packet to the network stacks. */ - sc->quota--; - if (sc->stack) - sc->stack->input(sc, first_mbuf); - else - { - m_freem(first_mbuf); - sc->status.cntrs.idrops++; - } - } - else if (sc->status.link_state != STATE_UP) - { - /* If the link is down, this packet is probably noise. */ - m_freem(first_mbuf); - sc->status.cntrs.idrops++; - if (sc->config.debug) - printf("%s: rxintr_cleanup: rx pkt dropped: link down\n", NAME_UNIT); - } - else /* Log and drop this bad packet. */ - { - if (sc->config.debug) - printf("%s: RX bad pkt; len=%d %s%s%s%s\n", - NAME_UNIT, first_mbuf->m_pkthdr.len, - (last_desc->status & TLP_DSTS_RX_MII_ERR) ? " miierr" : "", - (last_desc->status & TLP_DSTS_RX_DRIBBLE) ? " dribble" : "", - (last_desc->status & TLP_DSTS_RX_DESC_ERR) ? " descerr" : "", - (last_desc->status & TLP_DSTS_RX_OVERRUN) ? " overrun" : ""); - if (last_desc->status & TLP_DSTS_RX_OVERRUN) - sc->status.cntrs.fifo_over++; - else - sc->status.cntrs.ierrors++; - m_freem(first_mbuf); - } - - return 1; /* did something */ - } - -/* Setup (prepare) to receive a packet. */ -/* Try to keep the RX descriptor ring full of empty buffers. */ -static int /* BSD version */ -rxintr_setup(softc_t *sc) - { - struct desc_ring *ring = &sc->rxring; - struct dma_desc *desc; - struct mbuf *m; - int desc_len; - int error; - - /* Ring is full if (wrap(write+1)==read) */ - if (((ring->write == ring->last) ? ring->first : ring->write+1) == ring->read) - return 0; /* ring is full; nothing to do */ - - /* Allocate a small mbuf and attach an mbuf cluster. */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - { - sc->status.cntrs.rxbuf++; - if (sc->config.debug) - printf("%s: rxintr_setup: MGETHDR() failed\n", NAME_UNIT); - return 0; - } - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT)==0) - { - m_freem(m); - sc->status.cntrs.rxbuf++; - if (sc->config.debug) - printf("%s: rxintr_setup: MCLGET() failed\n", NAME_UNIT); - return 0; - } - - /* Queue the mbuf for later processing by rxintr_cleanup. */ - mbuf_enqueue(ring, m); - - /* Write a DMA descriptor into the ring. */ - /* Hardware will not see it until the OWNER bit is set. */ - desc = ring->write; - /* Advance the ring write pointer. */ - if (ring->write++ == ring->last) ring->write = ring->first; - - desc_len = (MCLBYTES < MAX_DESC_LEN) ? MCLBYTES : MAX_DESC_LEN; - /* Map kernel virt addr to PCI bus addr. */ - if ((error = DMA_LOAD(desc->map, m->m_data, desc_len))) - printf("%s: bus_dmamap_load(rx): error %d\n", NAME_UNIT, error); - /* Invalidate the cache for this mbuf. */ - DMA_SYNC(desc->map, desc_len, BUS_DMASYNC_PREREAD); - - /* Set up the DMA descriptor. */ - desc->address1 = desc->map->dm_segs[0].ds_addr; - desc->length1 = desc_len>>1; - desc->address2 = desc->address1 + desc->length1; - desc->length2 = desc_len>>1; - - /* Before setting the OWNER bit, flush cache backing DMA descriptors. */ - DMA_SYNC(ring->map, ring->size_descs, BUS_DMASYNC_PREWRITE); - - /* Commit the DMA descriptor to the hardware. */ - desc->status = TLP_DSTS_OWNER; - - /* Notify the receiver that there is another buffer available. */ - WRITE_CSR(sc, TLP_RX_POLL, 1); - - return 1; /* did something */ - } - -/* Clean up after a packet has been transmitted. */ -/* Free the mbuf chain and update the DMA descriptor ring. */ -static int /* BSD version */ -txintr_cleanup(softc_t *sc) - { - struct desc_ring *ring = &sc->txring; - struct dma_desc *desc; - - while ((ring->read != ring->write) && /* while ring is not empty */ - !(ring->read->status & TLP_DSTS_OWNER)) - { - /* Read a DMA descriptor from the ring. */ - desc = ring->read; - /* Advance the ring read pointer. */ - if (ring->read++ == ring->last) ring->read = ring->first; - - /* This is a no-op on most architectures. */ - DMA_SYNC(desc->map, desc->length1 + desc->length2, BUS_DMASYNC_POSTWRITE); - /* Unmap kernel virtual address to PCI bus address. */ - bus_dmamap_unload(ring->tag, desc->map); - - /* If this descriptor is the last segment of a packet, */ - /* then dequeue and free the corresponding mbuf chain. */ - if (desc->control & TLP_DCTL_TX_LAST_SEG) - { - struct mbuf *m; - - if ((m = mbuf_dequeue(ring)) == NULL) - panic("%s: txintr_cleanup: expected an mbuf\n", NAME_UNIT); - - /* The only bad TX status is fifo underrun. */ - if (desc->status & TLP_DSTS_TX_UNDERRUN) - { - if (sc->config.debug) - printf("%s: txintr_cleanup: tx fifo underrun\n", NAME_UNIT); - sc->status.cntrs.fifo_under++; - sc->status.cntrs.oerrors++; - } - else - { - /* Include CRC and one flag byte in output byte count. */ - sc->status.cntrs.obytes += m->m_pkthdr.len + sc->config.crc_len +1; - sc->status.cntrs.opackets++; - } - - m_freem(m); - return 1; /* did something */ - } - } - - return 0; - } - -/* Build DMA descriptors for a transmit packet mbuf chain. */ -static int /* 0=success; 1=error */ /* BSD version */ -txintr_setup_mbuf(softc_t *sc, struct mbuf *m) - { - struct desc_ring *ring = &sc->txring; - struct dma_desc *desc; - unsigned int desc_len; - - /* build DMA descriptors for a chain of mbufs. */ - while (m) - { - char *data = m->m_data; - int length = m->m_len; /* zero length mbufs happen! */ - - /* Build DMA descriptors for one mbuf. */ - while (length > 0) - { - int error; - - /* Ring is full if (wrap(write+1)==read) */ - if (((ring->temp==ring->last) ? ring->first : ring->temp+1) == ring->read) - { /* Not enough DMA descriptors; try later. */ - for (; ring->temp!=ring->write; - ring->temp = (ring->temp==ring->first)? ring->last : ring->temp-1) - bus_dmamap_unload(ring->tag, ring->temp->map); - sc->status.cntrs.txdma++; /* IFF_OACTIVE? */ - return 1; - } - - /* Provisionally, write a descriptor into the ring. */ - /* But do not change the REAL ring write pointer. */ - /* Hardware will not see it until the OWNER bit is set. */ - desc = ring->temp; - /* Advance the temporary ring write pointer. */ - if (ring->temp++ == ring->last) ring->temp = ring->first; - - /* Clear all control bits except the END_RING bit. */ - desc->control &= TLP_DCTL_END_RING; - /* Do not pad short packets up to 64 bytes. */ - desc->control |= TLP_DCTL_TX_NO_PAD; - /* Use Tulip's CRC-32 generator, if appropriate. */ - if (sc->config.crc_len != CFG_CRC_32) - desc->control |= TLP_DCTL_TX_NO_CRC; - /* Set the OWNER bit, except in the first descriptor. */ - if (desc != ring->write) - desc->status = TLP_DSTS_OWNER; - - desc_len = (length > MAX_CHUNK_LEN) ? MAX_CHUNK_LEN : length; - /* Map kernel virt addr to PCI bus addr. */ - if ((error = DMA_LOAD(desc->map, data, desc_len))) - printf("%s: bus_dmamap_load(tx): error %d\n", NAME_UNIT, error); - /* Flush the cache and if bouncing, copy mbuf to bounce buf. */ - DMA_SYNC(desc->map, desc_len, BUS_DMASYNC_PREWRITE); - - /* Prevent wild fetches if mapping fails (nsegs==0). */ - desc->length1 = desc->length2 = 0; - desc->address1 = desc->address2 = 0; - { - bus_dma_segment_t *segs = desc->map->dm_segs; - int nsegs = desc->map->dm_nsegs; - if (nsegs >= 1) - { - desc->address1 = segs[0].ds_addr; - desc->length1 = segs[0].ds_len; - } - if (nsegs == 2) - { - desc->address2 = segs[1].ds_addr; - desc->length2 = segs[1].ds_len; - } - } - - data += desc_len; - length -= desc_len; - } /* while (length > 0) */ - - m = m->m_next; - } /* while (m) */ - - return 0; /* success */ - } - -/* Setup (prepare) to transmit a packet. */ -/* Select a packet, build DMA descriptors and give packet to hardware. */ -/* If DMA descriptors run out, abandon the attempt and return 0. */ -static int /* BSD version */ -txintr_setup(softc_t *sc) - { - struct desc_ring *ring = &sc->txring; - struct dma_desc *first_desc, *last_desc; - - /* Protect against half-up links: Do not transmit */ - /* if the receiver can not hear the far end. */ - if (sc->status.link_state != STATE_UP) return 0; - - /* Pick a packet to transmit. */ - if ((sc->tx_mbuf == NULL) && sc->stack) - sc->stack->output(sc); - if (sc->tx_mbuf == NULL) return 0; /* no pkt to transmit */ - - /* Build DMA descriptors for an outgoing mbuf chain. */ - ring->temp = ring->write; /* temporary ring write pointer */ - if (txintr_setup_mbuf(sc, sc->tx_mbuf)) return 0; - - /* Enqueue the mbuf; txintr_cleanup will free it. */ - mbuf_enqueue(ring, sc->tx_mbuf); - - /* Berkeley Packet Filter */ - bpf_mtap(sc->ifp, sc->tx_mbuf, BPF_D_OUT); - - /* The transmitter has room for another packet. */ - sc->tx_mbuf = NULL; - - /* Set first & last segment bits. */ - /* last_desc is the desc BEFORE the one pointed to by ring->temp. */ - first_desc = ring->write; - first_desc->control |= TLP_DCTL_TX_FIRST_SEG; - last_desc = (ring->temp==ring->first)? ring->last : ring->temp-1; - last_desc->control |= TLP_DCTL_TX_LAST_SEG; - /* Interrupt at end-of-transmission? Why bother the poor computer! */ -/* last_desc->control |= TLP_DCTL_TX_INTERRUPT; */ - - /* Make sure the OWNER bit is not set in the next descriptor. */ - /* The OWNER bit may have been set if a previous call aborted. */ - ring->temp->status = 0; - - /* Commit the DMA descriptors to the software. */ - ring->write = ring->temp; - - /* Before setting the OWNER bit, flush cache backing DMA descriptors. */ - DMA_SYNC(ring->map, ring->size_descs, BUS_DMASYNC_PREWRITE); - - /* Commit the DMA descriptors to the hardware. */ - first_desc->status = TLP_DSTS_OWNER; - - /* Notify the transmitter that there is another packet to send. */ - WRITE_CSR(sc, TLP_TX_POLL, 1); - - return 1; /* did something */ - } - -/* BSD kernels call this when a hardware interrupt happens. */ -static intr_return_t /* context: interrupt */ -bsd_interrupt(void *arg) - { - softc_t *sc = arg; - -# if DEVICE_POLLING - if (sc->ifp->if_capenable & IFCAP_POLLING) - return IRQ_NONE; -# endif - - /* Cut losses early if this is not our interrupt. */ - if ((READ_CSR(sc, TLP_STATUS) & TLP_INT_TXRX)==0) - return IRQ_NONE; - - /* Process tx and rx pkts. */ - lmc_interrupt(sc, sc->rxring.num_descs, 0); - - return IRQ_HANDLED; - } - -#endif /* BSD */ - -# if DEVICE_POLLING - -/* This procedure services the card without interrupts. */ -/* With rxintr_cleanup(), it implements input flow control. */ -static void /* context: softirq */ -bsd_poll(struct ifnet *ifp, enum poll_cmd cmd, int quota) - { - softc_t *sc = IFP2SC(ifp); - - /* Cut losses early if this is not our interrupt. */ - if ((READ_CSR(sc, TLP_STATUS) & TLP_INT_TXRX)==0) - return; - - /* Process all tx pkts and up to quota rx pkts. */ - lmc_interrupt(sc, quota, (cmd==POLL_AND_CHECK_STATUS)); - } - -# endif /* DEVICE_POLLING */ - - -/* Open a line protocol. */ -/* context: kernel (boot) or process (syscall) */ -static int -open_proto(softc_t *sc, struct config *config) - { - int error = 0; - - if (sc->stack) - error = sc->stack->open(sc, config); - else - error = BSD ? ENOSYS : -ENOSYS; - - return error; - } - -/* Attach a line protocol stack. */ -/* context: kernel (boot) or process (syscall) */ -static int -attach_stack(softc_t *sc, struct config *config) - { - int error = 0; - struct stack *stack = NULL; - - /* Done if stack is not changing. */ - if (sc->config.stack == config->stack) - return 0; - - /* Detach the current stack. */ - if (sc->stack && ((error = sc->stack->detach(sc)))) - return error; - - switch (config->stack) - { - case STACK_RAWIP: /* built-in */ - stack = &rawip_stack; - break; - -#if SPPP - case STACK_SPPP: - stack = &sppp_stack; - break; -#endif - -#if P2P - case STACK_P2P: - stack = &p2p_stack; - break; -#endif - -#if GEN_HDLC - case STACK_GEN_HDLC: - stack = &gen_hdlc_stack; - break; -#endif - -#if SYNC_PPP - case STACK_SYNC_PPP: - stack = &sync_ppp_stack; - break; -#endif - - - default: - stack = NULL; - break; - } - - if (stack) - error = stack->attach(sc, config); - else - error = BSD ? ENOSYS : -ENOSYS; - - return error; - } - - -/* - * This handles IOCTLs from lmcconfig(8). - * Must not run when card watchdogs run. - * Always called with top_lock held. - */ -static int /* context: process */ -lmc_ioctl(softc_t *sc, u_long cmd, void *data) - { - struct iohdr *iohdr = (struct iohdr *) data; - struct ioctl *ioctl = (struct ioctl *) data; - struct status *status = (struct status *) data; - struct config *config = (struct config *) data; - int error = 0; - - /* All structs start with a string and a cookie. */ - if (iohdr->cookie != NGM_LMC_COOKIE) - return EINVAL; - - switch (cmd) - { - case LMCIOCGSTAT: - { - *status = sc->status; - iohdr->cookie = NGM_LMC_COOKIE; - break; - } - case LMCIOCGCFG: - { - *config = sc->config; - iohdr->cookie = NGM_LMC_COOKIE; - break; - } - case LMCIOCSCFG: - { - if ((error = CHECK_CAP)) break; - if ((error = attach_stack(sc, config))); - else error = open_proto(sc, config); - tulip_loop(sc, config); - sc->card->attach(sc, config); - sc->config.debug = config->debug; - break; - } - case LMCIOCREAD: - { - if (ioctl->cmd == IOCTL_RW_PCI) - { - if (ioctl->address > 252) { error = EFAULT; break; } - ioctl->data = READ_PCI_CFG(sc, ioctl->address); - } - else if (ioctl->cmd == IOCTL_RW_CSR) - { - if (ioctl->address > 15) { error = EFAULT; break; } - ioctl->data = READ_CSR(sc, ioctl->address*TLP_CSR_STRIDE); - } - else if (ioctl->cmd == IOCTL_RW_SROM) - { - if (ioctl->address > 63) { error = EFAULT; break; } - ioctl->data = srom_read(sc, ioctl->address); - } - else if (ioctl->cmd == IOCTL_RW_BIOS) - ioctl->data = bios_read(sc, ioctl->address); - else if (ioctl->cmd == IOCTL_RW_MII) - ioctl->data = mii_read(sc, ioctl->address); - else if (ioctl->cmd == IOCTL_RW_FRAME) - ioctl->data = framer_read(sc, ioctl->address); - else - error = EINVAL; - break; - } - case LMCIOCWRITE: - { - if ((error = CHECK_CAP)) break; - if (ioctl->cmd == IOCTL_RW_PCI) - { - if (ioctl->address > 252) { error = EFAULT; break; } - WRITE_PCI_CFG(sc, ioctl->address, ioctl->data); - } - else if (ioctl->cmd == IOCTL_RW_CSR) - { - if (ioctl->address > 15) { error = EFAULT; break; } - WRITE_CSR(sc, ioctl->address*TLP_CSR_STRIDE, ioctl->data); - } - else if (ioctl->cmd == IOCTL_RW_SROM) - { - if (ioctl->address > 63) { error = EFAULT; break; } - srom_write(sc, ioctl->address, ioctl->data); /* can sleep */ - } - else if (ioctl->cmd == IOCTL_RW_BIOS) - { - if (ioctl->address == 0) bios_erase(sc); - bios_write(sc, ioctl->address, ioctl->data); /* can sleep */ - } - else if (ioctl->cmd == IOCTL_RW_MII) - mii_write(sc, ioctl->address, ioctl->data); - else if (ioctl->cmd == IOCTL_RW_FRAME) - framer_write(sc, ioctl->address, ioctl->data); - else if (ioctl->cmd == IOCTL_WO_SYNTH) - synth_write(sc, (struct synth *)&ioctl->data); - else if (ioctl->cmd == IOCTL_WO_DAC) - { - dac_write(sc, 0x9002); /* set Vref = 2.048 volts */ - dac_write(sc, ioctl->data & 0xFFF); - } - else - error = EINVAL; - break; - } - case LMCIOCTL: - { - if ((error = CHECK_CAP)) break; - if (ioctl->cmd == IOCTL_XILINX_RESET) - { - xilinx_reset(sc); - sc->card->attach(sc, &sc->config); - } - else if (ioctl->cmd == IOCTL_XILINX_ROM) - { - xilinx_load_from_rom(sc); - sc->card->attach(sc, &sc->config); - } - else if (ioctl->cmd == IOCTL_XILINX_FILE) - { - error = xilinx_load_from_file(sc, ioctl->ucode, ioctl->data); - if (error) xilinx_load_from_rom(sc); /* try the rom */ - sc->card->attach(sc, &sc->config); - } - else if (ioctl->cmd == IOCTL_RESET_CNTRS) - reset_cntrs(sc); - else - error = sc->card->ioctl(sc, ioctl); - break; - } - default: - error = EINVAL; - break; - } - - return error; - } - -/* This is the core watchdog procedure. - * ioctl syscalls and card watchdog routines must be interlocked. - * Called by ng_watchdog(), ifnet_watchdog() and netdev_watchdog(). - */ -static void /* context: softirq */ -lmc_watchdog(softc_t *sc) - { - /* Read and restart the Tulip timer. */ - u_int32_t tx_speed = READ_CSR(sc, TLP_TIMER); - WRITE_CSR(sc, TLP_TIMER, 0xFFFF); - - /* Measure MII clock using a timer in the Tulip chip. - * This timer counts transmitter bits divided by 4096. - * Since this is called once a second the math is easy. - * This is only correct when the link is NOT sending pkts. - * On a fully-loaded link, answer will be HALF actual rate. - * Clock rate during pkt is HALF clk rate between pkts. - * Measuring clock rate really measures link utilization! - */ - sc->status.tx_speed = (0xFFFF - (tx_speed & 0xFFFF)) << 12; - - /* Call the card-specific watchdog routine. */ - if (TOP_TRYLOCK(sc)) - { - /* Remember link_state before updating it. */ - sc->last_link_state = sc->status.link_state; - /* Update status.link_state. */ - sc->card->watchdog(sc); - - /* Increment a counter which tells user-land */ - /* observers that SNMP state has been updated. */ - sc->status.ticks++; - - TOP_UNLOCK(sc); - } - else - sc->status.cntrs.lck_watch++; - - /* Kernel date/time can take up to 5 seconds to start running. */ - if ((sc->status.ticks > 3) && /* h/w should be stable by now */ - (sc->status.cntrs.reset_time.tv_sec < 1000)) - { - microtime(&sc->status.cntrs.reset_time); - if (sc->status.cntrs.reset_time.tv_sec > 1000) - reset_cntrs(sc); - } - - /* Call the stack-specific watchdog routine. */ - if (sc->stack) - sc->stack->watchdog(sc); - - /* In case an interrupt gets lost, process tx and rx pkts */ - lmc_interrupt(sc, sc->rxring.num_descs, 1); - } - -/* Administrative status of the driver (UP or DOWN) has changed. - * A card-specific action is taken: - * HSSI: drop TA. - * (T3: send T3 idle ckt signal. ) - * SSI: drop RTS, DTR and DCD - * (T1: disable line interface tx; ) - */ -static void -set_ready(softc_t *sc, int status) - { - struct ioctl ioctl; - - ioctl.cmd = IOCTL_SET_STATUS; - ioctl.data = status; - - sc->card->ioctl(sc, &ioctl); - } - -static void -reset_cntrs(softc_t *sc) - { - memset(&sc->status.cntrs, 0, sizeof(struct cntrs)); - microtime(&sc->status.cntrs.reset_time); - } - -static void /* context: process, softirq, interrupt! */ -lmc_interrupt(void *arg, int quota, int check_status) - { - softc_t *sc = arg; - int activity; - - /* Do this FIRST! Otherwise UPs deadlock and MPs spin. */ - WRITE_CSR(sc, TLP_STATUS, READ_CSR(sc, TLP_STATUS)); - - /* If any CPU is inside this critical section, then */ - /* other CPUs should go away without doing anything. */ - if (BOTTOM_TRYLOCK(sc) == 0) - { - sc->status.cntrs.lck_intr++; - return; - } - - /* In Linux, pci_alloc_consistent() means DMA */ - /* descriptors do not need explicit syncing? */ -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - ring = &sc->rxring; - DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - } -#endif - - /* This is the main loop for interrupt processing. */ - sc->quota = quota; - do - { - activity = txintr_cleanup(sc); - activity += rxintr_cleanup(sc); - activity += rxintr_setup(sc); - } while (activity); - -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - ring = &sc->rxring; - DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - } -#endif - - /* As the interrupt is dismissed, check for four unusual events. */ - if (check_status) check_intr_status(sc); - - BOTTOM_UNLOCK(sc); - } - -/* Check for four unusual events: - * 1) fatal PCI bus errors - some are recoverable - * 2) transmitter FIFO underruns - increase fifo threshold - * 3) receiver FIFO overruns - clear potential hangup - * 4) no receive descs or bufs - count missed packets - */ -static void -check_intr_status(softc_t *sc) - { - u_int32_t status, cfcs, op_mode; - u_int32_t missed, overruns; - - /* 1) A fatal bus error causes a Tulip to stop initiating bus cycles. - * Module unload/load or boot are the only fixes for Parity Errors. - * Master and Target Aborts can be cleared and life may continue. - */ - status = READ_CSR(sc, TLP_STATUS); - if (status & TLP_STAT_FATAL_ERROR) - { - u_int32_t fatal = (status & TLP_STAT_FATAL_BITS)>>TLP_STAT_FATAL_SHIFT; - printf("%s: FATAL PCI BUS ERROR: %s%s%s%s\n", NAME_UNIT, - (fatal == 0) ? "PARITY ERROR" : "", - (fatal == 1) ? "MASTER ABORT" : "", - (fatal == 2) ? "TARGET ABORT" : "", - (fatal >= 3) ? "RESERVED (?)" : ""); - cfcs = READ_PCI_CFG(sc, TLP_CFCS); /* try to clear it */ - cfcs &= ~(TLP_CFCS_MSTR_ABORT | TLP_CFCS_TARG_ABORT); - WRITE_PCI_CFG(sc, TLP_CFCS, cfcs); - } - - /* 2) If the transmitter fifo underruns, increase the transmit fifo - * threshold: the number of bytes required to be in the fifo - * before starting the transmitter (cost: increased tx delay). - * The TX_FSM must be stopped to change this parameter. - */ - if (status & TLP_STAT_TX_UNDERRUN) - { - op_mode = READ_CSR(sc, TLP_OP_MODE); - /* enable store-and-forward mode if tx_threshold tops out? */ - if ((op_mode & TLP_OP_TX_THRESH) < TLP_OP_TX_THRESH) - { - op_mode += 0x4000; /* increment TX_THRESH field; can not overflow */ - WRITE_CSR(sc, TLP_OP_MODE, op_mode & ~TLP_OP_TX_RUN); - /* Wait for the TX FSM to stop; it might be processing a pkt. */ - while (READ_CSR(sc, TLP_STATUS) & TLP_STAT_TX_FSM); /* XXX HANG */ - WRITE_CSR(sc, TLP_OP_MODE, op_mode); /* restart tx */ - - if (sc->config.debug) - printf("%s: tx fifo underrun; threshold now %d bytes\n", - NAME_UNIT, 128<<((op_mode>>TLP_OP_TR_SHIFT)&3)); - sc->status.cntrs.underruns++; - } - } - - /* 3) Errata memo from Digital Equipment Corp warns that 21140A - * receivers through rev 2.2 can hang if the fifo overruns. - * Recommended fix: stop and start the RX FSM after an overrun. - */ - missed = READ_CSR(sc, TLP_MISSED); - if ((overruns = ((missed & TLP_MISS_OVERRUN)>>TLP_OVERRUN_SHIFT))) - { - if ((READ_PCI_CFG(sc, TLP_CFRV) & 0xFF) <= 0x22) - { - op_mode = READ_CSR(sc, TLP_OP_MODE); - WRITE_CSR(sc, TLP_OP_MODE, op_mode & ~TLP_OP_RX_RUN); - /* Wait for the RX FSM to stop; it might be processing a pkt. */ - while (READ_CSR(sc, TLP_STATUS) & TLP_STAT_RX_FSM); /* XXX HANG */ - WRITE_CSR(sc, TLP_OP_MODE, op_mode); /* restart rx */ - } - if (sc->config.debug) - printf("%s: rx fifo overruns=%d\n", NAME_UNIT, overruns); - sc->status.cntrs.overruns += overruns; - } - - /* 4) When the receiver is enabled and a packet arrives, but no DMA - * descriptor is available, the packet is counted as 'missed'. - * The receiver should never miss packets; warn if it happens. - */ - if ((missed = (missed & TLP_MISS_MISSED))) - { - if (sc->config.debug) - printf("%s: rx missed %d pkts\n", NAME_UNIT, missed); - sc->status.cntrs.missed += missed; - } - } - -/* Initialize the driver. */ -/* context: kernel (boot) or process (syscall) */ -static int -lmc_attach(softc_t *sc) - { - int error = 0; - struct config config; - - /* Attach the Tulip PCI bus interface. */ - if ((error = tulip_attach(sc))) return error; - - /* Reset the Xilinx Field Programmable Gate Array. */ - xilinx_reset(sc); /* side effect: turns on all four LEDs */ - - /* Attach card-specific stuff. */ - sc->card->attach(sc, NULL); /* changes sc->config */ - - /* Reset the FIFOs between Gate array and Tulip chip. */ - mii16_set_bits(sc, MII16_FIFO); - mii16_clr_bits(sc, MII16_FIFO); - -#if IFNET - /* Attach the ifnet kernel interface. */ - if ((error = ifnet_attach(sc))) return error; -#endif - -#if NETDEV - /* Attach the netdevice kernel interface. */ - if ((error = netdev_attach(sc))) return error; -#endif - - /* Attach a protocol stack and open a line protocol. */ - config = sc->config; - config.stack = STACK_RAWIP; - attach_stack(sc, &config); - config.proto = PROTO_IP_HDLC; - open_proto(sc, &config); - - /* Print obscure card information. */ - if (BOOT_VERBOSE) - { - u_int32_t cfrv = READ_PCI_CFG(sc, TLP_CFRV); - u_int16_t mii3 = mii_read(sc, 3); - u_int16_t srom[3]; - u_int8_t *ieee = (u_int8_t *)srom; - int i; - - printf("%s", NAME_UNIT); - printf(": PCI rev %d.%d", (cfrv>>4) & 0xF, cfrv & 0xF); - printf(", MII rev %d.%d", (mii3>>4) & 0xF, mii3 & 0xF); - for (i=0; i<3; i++) srom[i] = srom_read(sc, 10+i); - printf(", IEEE addr %02x:%02x:%02x:%02x:%02x:%02x", - ieee[0], ieee[1], ieee[2], ieee[3], ieee[4], ieee[5]); - sc->card->ident(sc); - } - -/* BSDs enable card interrupts and appear "ready" here. */ -/* Linux does this in netdev_open(). */ -#if BSD - set_ready(sc, 1); - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_TXRX); -#endif - - return 0; - } - -/* context: kernel (boot) or process (syscall) */ -static void -lmc_detach(softc_t *sc) - { - /* Disable card interrupts and appear "not ready". */ - set_ready(sc, 0); - WRITE_CSR(sc, TLP_INT_ENBL, TLP_INT_DISABLE); - - /* Detach the line protocol package. */ - if (sc->stack) - sc->stack->detach(sc); - -#if IFNET - /* Detach the ifnet kernel interface. */ - ifnet_detach(sc); -#endif - -#if NETDEV - /* Detach the netdevice kernel interface. */ - netdev_detach(sc); -#endif - - /* Detach framers, line interfaces, etc. on the card. */ - sc->card->detach(sc); - - /* Detach the Tulip PCI bus interface. */ - tulip_detach(sc); - } - -/* Loop back through the TULIP Ethernet chip; (no CRC). - * Data sheet says stop DMA before changing OPMODE register. - * But that's not as simple as it sounds; works anyway. - */ -static void -tulip_loop(softc_t *sc, struct config *config) - { - /* Check for enabling loopback thru Tulip chip. */ - if ((sc->config.loop_back != CFG_LOOP_TULIP) && - (config->loop_back == CFG_LOOP_TULIP)) - { - u_int32_t op_mode = READ_CSR(sc, TLP_OP_MODE); - op_mode |= TLP_OP_INT_LOOP; - WRITE_CSR(sc, TLP_OP_MODE, op_mode); - config->crc_len = CFG_CRC_0; - } - - /* Check for disabling loopback thru Tulip chip. */ - if ((sc->config.loop_back == CFG_LOOP_TULIP) && - (config->loop_back != CFG_LOOP_TULIP)) - { - u_int32_t op_mode = READ_CSR(sc, TLP_OP_MODE); - op_mode &= ~TLP_OP_LOOP_MODE; - WRITE_CSR(sc, TLP_OP_MODE, op_mode); - config->crc_len = CFG_CRC_16; - } - - sc->config.loop_back = config->loop_back; - } - -/* Attach the Tulip PCI bus interface. - * Allocate DMA descriptors and enable DMA. - * Returns 0 on success; error code on failure. - * context: kernel (boot) or process (syscall) - */ -static int -tulip_attach(softc_t *sc) - { - int num_rx_descs, error = 0; - u_int32_t bus_pbl, bus_cal, op_tr; - u_int32_t cfdd, cfcs, cflt, csid, cfit; - - /* Make sure the COMMAND bits are reasonable. */ - cfcs = READ_PCI_CFG(sc, TLP_CFCS); - cfcs &= ~TLP_CFCS_MWI_ENABLE; - cfcs |= TLP_CFCS_BUS_MASTER; - cfcs |= TLP_CFCS_MEM_ENABLE; - cfcs |= TLP_CFCS_IO_ENABLE; - cfcs |= TLP_CFCS_PAR_ERROR; - cfcs |= TLP_CFCS_SYS_ERROR; - WRITE_PCI_CFG(sc, TLP_CFCS, cfcs); - - /* Set the LATENCY TIMER to the recommended value, */ - /* and make sure the CACHE LINE SIZE is reasonable. */ - cfit = READ_PCI_CFG(sc, TLP_CFIT); - cflt = READ_PCI_CFG(sc, TLP_CFLT); - cflt &= ~TLP_CFLT_LATENCY; - cflt |= (cfit & TLP_CFIT_MAX_LAT)>>16; - /* "prgmbl burst length" and "cache alignment" used below. */ - switch(cflt & TLP_CFLT_CACHE) - { - case 8: /* 8 bytes per cache line */ - { bus_pbl = 32; bus_cal = 1; break; } - case 16: - { bus_pbl = 32; bus_cal = 2; break; } - case 32: - { bus_pbl = 32; bus_cal = 3; break; } - default: - { - bus_pbl = 32; bus_cal = 1; - cflt &= ~TLP_CFLT_CACHE; - cflt |= 8; - break; - } - } - WRITE_PCI_CFG(sc, TLP_CFLT, cflt); - - /* Make sure SNOOZE and SLEEP modes are disabled. */ - cfdd = READ_PCI_CFG(sc, TLP_CFDD); - cfdd &= ~TLP_CFDD_SLEEP; - cfdd &= ~TLP_CFDD_SNOOZE; - WRITE_PCI_CFG(sc, TLP_CFDD, cfdd); - DELAY(11*1000); /* Tulip wakes up in 10 ms max */ - - /* Software Reset the Tulip chip; stops DMA and Interrupts. */ - /* This does not change the PCI config regs just set above. */ - WRITE_CSR(sc, TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */ - DELAY(5); /* Tulip is dead for 50 PCI cycles after reset. */ - - /* Initialize the PCI busmode register. */ - /* The PCI bus cycle type "Memory Write and Invalidate" does NOT */ - /* work cleanly in any version of the 21140A, so do not enable it! */ - WRITE_CSR(sc, TLP_BUS_MODE, - (bus_cal ? TLP_BUS_READ_LINE : 0) | - (bus_cal ? TLP_BUS_READ_MULT : 0) | - (bus_pbl<<TLP_BUS_PBL_SHIFT) | - (bus_cal<<TLP_BUS_CAL_SHIFT) | - ((BYTE_ORDER == BIG_ENDIAN) ? TLP_BUS_DESC_BIGEND : 0) | - ((BYTE_ORDER == BIG_ENDIAN) ? TLP_BUS_DATA_BIGEND : 0) | - TLP_BUS_DSL_VAL | - TLP_BUS_ARB); - - /* Pick number of RX descriptors and TX fifo threshold. */ - /* tx_threshold in bytes: 0=128, 1=256, 2=512, 3=1024 */ - csid = READ_PCI_CFG(sc, TLP_CSID); - switch(csid) - { - case CSID_LMC_HSSI: /* 52 Mb/s */ - case CSID_LMC_HSSIc: /* 52 Mb/s */ - case CSID_LMC_T3: /* 45 Mb/s */ - { num_rx_descs = 48; op_tr = 2; break; } - case CSID_LMC_SSI: /* 10 Mb/s */ - { num_rx_descs = 32; op_tr = 1; break; } - case CSID_LMC_T1E1: /* 2 Mb/s */ - { num_rx_descs = 16; op_tr = 0; break; } - default: - { num_rx_descs = 16; op_tr = 0; break; } - } - - /* Create DMA descriptors and initialize list head registers. */ - if ((error = create_ring(sc, &sc->txring, NUM_TX_DESCS))) return error; - WRITE_CSR(sc, TLP_TX_LIST, sc->txring.dma_addr); - if ((error = create_ring(sc, &sc->rxring, num_rx_descs))) return error; - WRITE_CSR(sc, TLP_RX_LIST, sc->rxring.dma_addr); - - /* Initialize the operating mode register. */ - WRITE_CSR(sc, TLP_OP_MODE, TLP_OP_INIT | (op_tr<<TLP_OP_TR_SHIFT)); - - /* Read the missed frame register (result ignored) to zero it. */ - error = READ_CSR(sc, TLP_MISSED); /* error is used as a bit-dump */ - - /* Disable rx watchdog and tx jabber features. */ - WRITE_CSR(sc, TLP_WDOG, TLP_WDOG_INIT); - - return 0; - } - -/* Detach the Tulip PCI bus interface. */ -/* Disable DMA and free DMA descriptors. */ -/* context: kernel (boot) or process (syscall) */ -static void -tulip_detach(void *arg) - { - softc_t *sc = arg; - - /* Software reset the Tulip chip; stops DMA and Interrupts. */ - WRITE_CSR(sc, TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */ - DELAY(5); /* Tulip is dead for 50 PCI cycles after reset. */ - - /* Disconnect from the PCI bus except for config cycles. */ - /* Hmmm; Linux syslogs a warning that IO and MEM are disabled. */ - WRITE_PCI_CFG(sc, TLP_CFCS, TLP_CFCS_MEM_ENABLE | TLP_CFCS_IO_ENABLE); - - /* Free the DMA descriptor rings. */ - destroy_ring(sc, &sc->txring); - destroy_ring(sc, &sc->rxring); - } - -/* Called during config probing -- softc does not yet exist. */ -static void -print_driver_info(void) - { - /* Print driver information once only. */ - if (driver_announced++ == 0) - { - printf("LMC driver version %d/%d/%d; options", - VER_YEAR, VER_MONTH, VER_DAY); - if (ALTQ) printf(" ALTQ"); - if (1) printf(" BPF"); /* always defined */ - if (NAPI) printf(" NAPI"); - if (DEVICE_POLLING) printf(" POLL"); - if (P2P) printf(" P2P"); - if (SPPP) printf(" SPPP"); - if (GEN_HDLC) printf(" GEN_HDLC"); - if (SYNC_PPP) printf(" SYNC_PPP"); - if (NETGRAPH) printf(" NETGRAPH"); - printf(".\n"); - } - } - - - -/* This is the I/O configuration interface for NetBSD. */ - -/* Looking for a DEC 21140A chip on any Lan Media Corp card. */ -/* context: kernel (boot) or process (syscall) */ -static int -nbsd_match(device_t parent, cfdata_t match, void *aux) - { - struct pci_attach_args *pa = aux; - u_int32_t cfid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CFID); - u_int32_t csid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CSID); - - if (cfid != TLP_CFID_TULIP) return 0; - switch (csid) - { - case CSID_LMC_HSSI: - case CSID_LMC_HSSIc: - case CSID_LMC_T3: - case CSID_LMC_SSI: - case CSID_LMC_T1E1: - print_driver_info(); - return 100; - default: - return 0; - } - } - -/* NetBSD bottom-half initialization. */ -/* context: kernel (boot) or process (syscall) */ -static void -nbsd_attach(device_t parent, device_t self, void *aux) - { - softc_t *sc = device_private(self); - struct pci_attach_args *pa = aux; - const char *intrstr; - bus_addr_t csr_addr; - int error; - char intrbuf[PCI_INTRSTR_LEN]; - - /* for READ/WRITE_PCI_CFG() */ - sc->sc_dev = self; - sc->pa_pc = pa->pa_pc; - sc->pa_tag = pa->pa_tag; - sc->pa_dmat = pa->pa_dmat; - - /* What kind of card are we driving? */ - switch (READ_PCI_CFG(sc, TLP_CSID)) - { - case CSID_LMC_HSSI: - case CSID_LMC_HSSIc: - sc->dev_desc = HSSI_DESC; - sc->card = &hssi_card; - break; - case CSID_LMC_T3: - sc->dev_desc = T3_DESC; - sc->card = &t3_card; - break; - case CSID_LMC_SSI: - sc->dev_desc = SSI_DESC; - sc->card = &ssi_card; - break; - case CSID_LMC_T1E1: - sc->dev_desc = T1E1_DESC; - sc->card = &t1_card; - break; - default: - return; - } - - /* Allocate PCI resources to access the Tulip chip CSRs. */ -# if IOREF_CSR - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBIO) & -2; - sc->csr_tag = pa->pa_iot; /* bus_space tag for IO refs */ -# else - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBMA); - sc->csr_tag = pa->pa_memt; /* bus_space tag for MEM refs */ -# endif - if ((error = bus_space_map(sc->csr_tag, csr_addr, - TLP_CSR_SIZE, 0, &sc->csr_handle))) - { - aprint_error("%s: bus_space_map(): error %d\n", NAME_UNIT, error); - return; - } - - /* Allocate PCI interrupt resources. */ - if (pci_intr_map(pa, &sc->intr_handle)) - { - aprint_error("%s: pci_intr_map() failed\n", NAME_UNIT); - nbsd_detach(self, 0); - return; - } - if ((sc->irq_cookie = pci_intr_establish_xname(pa->pa_pc, sc->intr_handle, - IPL_NET, bsd_interrupt, sc, device_xname(self))) == NULL) - { - aprint_error("%s: couldn't map interrupt\n", NAME_UNIT); - nbsd_detach(self, 0); - return; - } - intrstr = pci_intr_string(pa->pa_pc, sc->intr_handle, intrbuf, sizeof(intrbuf)); - aprint_normal(" %s: %s\n", intrstr, sc->dev_desc); - aprint_naive(": %s\n", sc->dev_desc); - - /* Install a shutdown hook. */ - if ((sc->sdh_cookie = shutdownhook_establish(tulip_detach, sc)) == NULL) - { - aprint_error("%s: shutdown_hook_establish() failed\n", NAME_UNIT); - nbsd_detach(self, 0); - return; - } - - /* Initialize the top-half and bottom-half locks. */ - mutex_init(&sc->top_lock, MUTEX_DEFAULT, IPL_VM); - __cpu_simple_lock_init(&sc->bottom_lock); - - /* Initialize the driver. */ - if ((error = lmc_attach(sc))) nbsd_detach(self, 0); - } - -/* context: kernel (boot) or process (syscall) */ -static int -nbsd_detach(device_t self, int flags) - { - softc_t *sc = device_private(self); - - /* Detach from the bus and the kernel. */ - lmc_detach(sc); - - /* Release resources. */ - if (sc->sdh_cookie) - shutdownhook_disestablish(sc->sdh_cookie); - if (sc->irq_cookie) - pci_intr_disestablish(sc->pa_pc, sc->irq_cookie); - if (sc->csr_handle) - bus_space_unmap(sc->csr_tag, sc->csr_handle, TLP_CSR_SIZE); - - /* Destroy locks. */ - mutex_destroy(&sc->top_lock); - - return 0; - } - -CFATTACH_DECL_NEW(lmc, sizeof(softc_t), /* lmc_ca */ - nbsd_match, nbsd_attach, nbsd_detach, NULL); diff --git a/sys/dev/pci/if_lmc.h b/sys/dev/pci/if_lmc.h deleted file mode 100644 index f439bdf3e44..00000000000 --- a/sys/dev/pci/if_lmc.h +++ /dev/null @@ -1,1396 +0,0 @@ -/*- - * $NetBSD: if_lmc.h,v 1.26 2018/09/16 09:25:47 skrll Exp $ - * - * Copyright (c) 2002-2006 David Boggs. (boggs@boggs.palo-alto.ca.us) - * All rights reserved. - * - * BSD LICENSE: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * GNU GENERAL PUBLIC LICENSE: - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef IF_LMC_H -#define IF_LMC_H - -#include <sys/ioccom.h> - - -#define DEVICE_NAME "lmc" - -#define VER_YEAR 2006 -#define VER_MONTH 4 -#define VER_DAY 11 - -/* netgraph stuff */ -#define NG_LMC_NODE_TYPE "if_"DEVICE_NAME -#define NGM_LMC_COOKIE 1144752198 /* date -u +'%s' */ - -/* Tulip PCI configuration registers */ -#define TLP_CFID 0x00 /* 0: CFg ID register */ -#define TLP_CFCS 0x04 /* 1: CFg Command/Status */ -#define TLP_CFRV 0x08 /* 2: CFg ReVision */ -#define TLP_CFLT 0x0C /* 3: CFg Latency Timer */ -#define TLP_CBIO 0x10 /* 4: Cfg Base IO address */ -#define TLP_CBMA 0x14 /* 5: Cfg Base Mem Addr */ -#define TLP_CSID 0x2C /* 11: Cfg Subsys ID reg */ -#define TLP_CFIT 0x3C /* 15: CFg InTerrupt */ -#define TLP_CFDD 0x40 /* 16: CFg Driver Data */ - -#define TLP_CFID_TULIP 0x00091011 /* DEC 21140A Ethernet chip */ - -#define TLP_CFCS_MSTR_ABORT 0x20000000 -#define TLP_CFCS_TARG_ABORT 0x10000000 -#define TLP_CFCS_SYS_ERROR 0x00000100 -#define TLP_CFCS_PAR_ERROR 0x00000040 -#define TLP_CFCS_MWI_ENABLE 0x00000010 -#define TLP_CFCS_BUS_MASTER 0x00000004 -#define TLP_CFCS_MEM_ENABLE 0x00000002 -#define TLP_CFCS_IO_ENABLE 0x00000001 - -#define TLP_CFLT_LATENCY 0x0000FF00 -#define TLP_CFLT_CACHE 0x000000FF - -#define CSID_LMC_HSSI 0x00031376 /* LMC 5200 HSSI card */ -#define CSID_LMC_T3 0x00041376 /* LMC 5245 T3 card */ -#define CSID_LMC_SSI 0x00051376 /* LMC 1000 SSI card */ -#define CSID_LMC_T1E1 0x00061376 /* LMC 1200 T1E1 card */ -#define CSID_LMC_HSSIc 0x00071376 /* LMC 5200 HSSI cPCI */ -#define CSID_LMC_SDSL 0x00081376 /* LMC 1168 SDSL card */ - -#define TLP_CFIT_MAX_LAT 0xFF000000 - -#define TLP_CFDD_SLEEP 0x80000000 -#define TLP_CFDD_SNOOZE 0x40000000 - -/* Tulip Control and Status Registers */ -#define TLP_CSR_STRIDE 8 /* 64 bits */ -#define TLP_BUS_MODE 0 * TLP_CSR_STRIDE -#define TLP_TX_POLL 1 * TLP_CSR_STRIDE -#define TLP_RX_POLL 2 * TLP_CSR_STRIDE -#define TLP_RX_LIST 3 * TLP_CSR_STRIDE -#define TLP_TX_LIST 4 * TLP_CSR_STRIDE -#define TLP_STATUS 5 * TLP_CSR_STRIDE -#define TLP_OP_MODE 6 * TLP_CSR_STRIDE -#define TLP_INT_ENBL 7 * TLP_CSR_STRIDE -#define TLP_MISSED 8 * TLP_CSR_STRIDE -#define TLP_SROM_MII 9 * TLP_CSR_STRIDE -#define TLP_BIOS_ROM 10 * TLP_CSR_STRIDE -#define TLP_TIMER 11 * TLP_CSR_STRIDE -#define TLP_GPIO 12 * TLP_CSR_STRIDE -#define TLP_CSR13 13 * TLP_CSR_STRIDE -#define TLP_CSR14 14 * TLP_CSR_STRIDE -#define TLP_WDOG 15 * TLP_CSR_STRIDE -#define TLP_CSR_SIZE 128 /* IO bus space size */ - -/* CSR 0 - PCI Bus Mode Register */ -#define TLP_BUS_WRITE_INVAL 0x01000000 /* DONT USE! */ -#define TLP_BUS_READ_LINE 0x00800000 -#define TLP_BUS_READ_MULT 0x00200000 -#define TLP_BUS_DESC_BIGEND 0x00100000 -#define TLP_BUS_TAP 0x000E0000 -#define TLP_BUS_CAL 0x0000C000 -#define TLP_BUS_PBL 0x00003F00 -#define TLP_BUS_DATA_BIGEND 0x00000080 -#define TLP_BUS_DSL 0x0000007C -#define TLP_BUS_ARB 0x00000002 -#define TLP_BUS_RESET 0x00000001 -#define TLP_BUS_CAL_SHIFT 14 -#define TLP_BUS_PBL_SHIFT 8 - -/* CSR 5 - Status Register */ -#define TLP_STAT_FATAL_BITS 0x03800000 -#define TLP_STAT_TX_FSM 0x00700000 -#define TLP_STAT_RX_FSM 0x000E0000 -#define TLP_STAT_FATAL_ERROR 0x00002000 -#define TLP_STAT_TX_UNDERRUN 0x00000020 -#define TLP_STAT_FATAL_SHIFT 23 - -/* CSR 6 - Operating Mode Register */ -#define TLP_OP_RECEIVE_ALL 0x40000000 -#define TLP_OP_MUST_BE_ONE 0x02000000 -#define TLP_OP_NO_HEART_BEAT 0x00080000 -#define TLP_OP_PORT_SELECT 0x00040000 -#define TLP_OP_TX_THRESH 0x0000C000 -#define TLP_OP_TX_RUN 0x00002000 -#define TLP_OP_LOOP_MODE 0x00000C00 -#define TLP_OP_EXT_LOOP 0x00000800 -#define TLP_OP_INT_LOOP 0x00000400 -#define TLP_OP_FULL_DUPLEX 0x00000200 -#define TLP_OP_PROMISCUOUS 0x00000040 -#define TLP_OP_PASS_BAD_PKT 0x00000008 -#define TLP_OP_RX_RUN 0x00000002 -#define TLP_OP_TR_SHIFT 14 -#define TLP_OP_INIT (TLP_OP_PORT_SELECT | \ - TLP_OP_FULL_DUPLEX | \ - TLP_OP_MUST_BE_ONE | \ - TLP_OP_NO_HEART_BEAT | \ - TLP_OP_RECEIVE_ALL | \ - TLP_OP_PROMISCUOUS | \ - TLP_OP_PASS_BAD_PKT | \ - TLP_OP_RX_RUN | \ - TLP_OP_TX_RUN) - -/* CSR 7 - Interrupt Enable Register */ -#define TLP_INT_NORMAL_INTR 0x00010000 -#define TLP_INT_ABNRML_INTR 0x00008000 -#define TLP_INT_FATAL_ERROR 0x00002000 -#define TLP_INT_RX_NO_BUFS 0x00000080 -#define TLP_INT_RX_INTR 0x00000040 -#define TLP_INT_TX_UNDERRUN 0x00000020 -#define TLP_INT_TX_INTR 0x00000001 -#define TLP_INT_DISABLE 0 -#define TLP_INT_TX (TLP_INT_NORMAL_INTR | \ - TLP_INT_ABNRML_INTR | \ - TLP_INT_FATAL_ERROR | \ - TLP_INT_TX_UNDERRUN | \ - TLP_INT_TX_INTR) -#define TLP_INT_RX (TLP_INT_NORMAL_INTR | \ - TLP_INT_ABNRML_INTR | \ - TLP_INT_FATAL_ERROR | \ - TLP_INT_RX_NO_BUFS | \ - TLP_INT_RX_INTR) -#define TLP_INT_TXRX (TLP_INT_TX | TLP_INT_RX) - -/* CSR 8 - RX Missed Frames & Overrun Register */ -#define TLP_MISS_OCO 0x10000000 -#define TLP_MISS_OVERRUN 0x0FFE0000 -#define TLP_MISS_MFO 0x00010000 -#define TLP_MISS_MISSED 0x0000FFFF -#define TLP_OVERRUN_SHIFT 17 - -/* CSR 9 - SROM & MII & Boot ROM Register */ -#define TLP_MII_MDIN 0x00080000 -#define TLP_MII_MDOE 0x00040000 -#define TLP_MII_MDOUT 0x00020000 -#define TLP_MII_MDC 0x00010000 - -#define TLP_BIOS_RD 0x00004000 -#define TLP_BIOS_WR 0x00002000 -#define TLP_BIOS_SEL 0x00001000 - -#define TLP_SROM_RD 0x00004000 -#define TLP_SROM_SEL 0x00000800 -#define TLP_SROM_DOUT 0x00000008 -#define TLP_SROM_DIN 0x00000004 -#define TLP_SROM_CLK 0x00000002 -#define TLP_SROM_CS 0x00000001 - -/* CSR 12 - General Purpose IO register */ -#define TLP_GPIO_DIR 0x00000100 - -/* CSR 15 - Watchdog Timer Register */ -#define TLP_WDOG_RX_OFF 0x00000010 -#define TLP_WDOG_TX_OFF 0x00000001 -#define TLP_WDOG_INIT (TLP_WDOG_TX_OFF | \ - TLP_WDOG_RX_OFF) - -/* GPIO bits common to all cards */ -#define GPIO_INIT 0x01 /* from Xilinx */ -#define GPIO_RESET 0x02 /* to Xilinx */ -/* bits 2 and 3 vary with card type -- see below */ -#define GPIO_MODE 0x10 /* to Xilinx */ -#define GPIO_DP 0x20 /* to/from Xilinx */ -#define GPIO_DATA 0x40 /* serial data */ -#define GPIO_CLK 0x80 /* serial clock */ - -/* HSSI GPIO bits */ -#define GPIO_HSSI_ST 0x04 /* send timing sense (deprecated) */ -#define GPIO_HSSI_TXCLK 0x08 /* clock source */ - -/* HSSIc GPIO bits */ -#define GPIO_HSSI_SYNTH 0x04 /* Synth osc chip select */ -#define GPIO_HSSI_DCE 0x08 /* provide clock on TXCLOCK output */ - -/* T3 GPIO bits */ -#define GPIO_T3_DAC 0x04 /* DAC chip select */ -#define GPIO_T3_INTEN 0x08 /* Framer Interrupt enable */ - -/* SSI GPIO bits */ -#define GPIO_SSI_SYNTH 0x04 /* Synth osc chip select */ -#define GPIO_SSI_DCE 0x08 /* provide clock on TXCLOCK output */ - -/* T1E1 GPIO bits */ -#define GPIO_T1_INTEN 0x08 /* Framer Interrupt enable */ - -/* MII register 16 bits common to all cards */ -/* NB: LEDs for HSSI & SSI are in DIFFERENT bits than for T1E1 & T3; oops */ -/* NB: CRC32 for HSSI & SSI is in DIFFERENT bit than for T1E1 & T3; oops */ -#define MII16_LED_ALL 0x0780 /* RW: LED bit mask */ -#define MII16_FIFO 0x0800 /* RW: 1=reset, 0=not reset */ - -/* MII register 16 bits for HSSI */ -#define MII16_HSSI_TA 0x0001 /* RW: host ready; host->modem */ -#define MII16_HSSI_CA 0x0002 /* RO: modem ready; modem->host */ -#define MII16_HSSI_LA 0x0004 /* RW: loopback A; host->modem */ -#define MII16_HSSI_LB 0x0008 /* RW: loopback B; host->modem */ -#define MII16_HSSI_LC 0x0010 /* RO: loopback C; modem->host */ -#define MII16_HSSI_TM 0x0020 /* RO: test mode; modem->host */ -#define MII16_HSSI_CRC32 0x0040 /* RW: CRC length 16/32 */ -#define MII16_HSSI_LED_LL 0x0080 /* RW: lower left - green */ -#define MII16_HSSI_LED_LR 0x0100 /* RW: lower right - green */ -#define MII16_HSSI_LED_UL 0x0200 /* RW: upper left - green */ -#define MII16_HSSI_LED_UR 0x0400 /* RW: upper right - red */ -#define MII16_HSSI_FIFO 0x0800 /* RW: reset fifos */ -#define MII16_HSSI_FORCECA 0x1000 /* RW: [cPCI] force CA on */ -#define MII16_HSSI_CLKMUX 0x6000 /* RW: [cPCI] TX clock selection */ -#define MII16_HSSI_LOOP 0x8000 /* RW: [cPCI] LOOP TX into RX */ -#define MII16_HSSI_MODEM 0x003F /* TA+CA+LA+LB+LC+TM */ - -/* MII register 16 bits for DS3 */ -#define MII16_DS3_ZERO 0x0001 /* RW: short/long cables */ -#define MII16_DS3_TRLBK 0x0002 /* RW: loop towards host */ -#define MII16_DS3_LNLBK 0x0004 /* RW: loop towards net */ -#define MII16_DS3_RAIS 0x0008 /* RO: LIU receive AIS (depr) */ -#define MII16_DS3_TAIS 0x0010 /* RW: LIU transmit AIS (depr) */ -#define MII16_DS3_BIST 0x0020 /* RO: LIU QRSS patt match (depr) */ -#define MII16_DS3_DLOS 0x0040 /* RO: LIU Digital LOS (depr) */ -#define MII16_DS3_LED_BLU 0x0080 /* RW: lower right - blue */ -#define MII16_DS3_LED_YEL 0x0100 /* RW: lower left - yellow */ -#define MII16_DS3_LED_RED 0x0200 /* RW: upper right - red */ -#define MII16_DS3_LED_GRN 0x0400 /* RW: upper left - green */ -#define MII16_DS3_FIFO 0x0800 /* RW: reset fifos */ -#define MII16_DS3_CRC32 0x1000 /* RW: CRC length 16/32 */ -#define MII16_DS3_SCRAM 0x2000 /* RW: payload scrambler */ -#define MII16_DS3_POLY 0x4000 /* RW: 1=Larse, 0=DigLink|Kentrox */ -#define MII16_DS3_FRAME 0x8000 /* RW: 1=stop txframe pulses */ - -/* MII register 16 bits for SSI */ -#define MII16_SSI_DTR 0x0001 /* RW: DTR host->modem */ -#define MII16_SSI_DSR 0x0002 /* RO: DSR modem->host */ -#define MII16_SSI_RTS 0x0004 /* RW: RTS host->modem */ -#define MII16_SSI_CTS 0x0008 /* RO: CTS modem->host */ -#define MII16_SSI_DCD 0x0010 /* RW: DCD modem<->host */ -#define MII16_SSI_RI 0x0020 /* RO: RI modem->host */ -#define MII16_SSI_CRC32 0x0040 /* RW: CRC length 16/32 */ -#define MII16_SSI_LED_LL 0x0080 /* RW: lower left - green */ -#define MII16_SSI_LED_LR 0x0100 /* RW: lower right - green */ -#define MII16_SSI_LED_UL 0x0200 /* RW: upper left - green */ -#define MII16_SSI_LED_UR 0x0400 /* RW: upper right - red */ -#define MII16_SSI_FIFO 0x0800 /* RW: reset fifos */ -#define MII16_SSI_LL 0x1000 /* RW: LL: host->modem */ -#define MII16_SSI_RL 0x2000 /* RW: RL: host->modem */ -#define MII16_SSI_TM 0x4000 /* RO: TM: modem->host */ -#define MII16_SSI_LOOP 0x8000 /* RW: Loop at ext conn */ -#define MII16_SSI_MODEM 0x703F /* DTR+DSR+RTS+CTS+DCD+RI+LL+RL+TM */ - -/* Mii register 17 has the SSI cable bits */ -#define MII17_SSI_CABLE_SHIFT 3 /* shift to get cable type */ -#define MII17_SSI_CABLE_MASK 0x0038 /* RO: mask to get cable type */ -#define MII17_SSI_PRESCALE 0x0040 /* RW: divide by: 0=16; 1=512 */ -#define MII17_SSI_ITF 0x0100 /* RW: fill with: 0=flags; 1=ones */ -#define MII17_SSI_NRZI 0x0400 /* RW: coding: NRZ= 0; NRZI=1 */ - -/* MII register 16 bits for T1/E1 */ -#define MII16_T1_UNUSED1 0x0001 -#define MII16_T1_INVERT 0x0002 /* RW: invert data (for SF/AMI) */ -#define MII16_T1_XOE 0x0004 /* RW: TX Output Enable; 0=disable */ -#define MII16_T1_RST 0x0008 /* RW: Bt8370 chip reset */ -#define MII16_T1_Z 0x0010 /* RW: output impedance T1=1 E1=0 */ -#define MII16_T1_INTR 0x0020 /* RO: interrupt from Bt8370 */ -#define MII16_T1_ONESEC 0x0040 /* RO: one second square wave */ -#define MII16_T1_LED_BLU 0x0080 /* RW: lower right - blue */ -#define MII16_T1_LED_YEL 0x0100 /* RW: lower left - yellow */ -#define MII16_T1_LED_RED 0x0200 /* RW: upper right - red */ -#define MII16_T1_LED_GRN 0x0400 /* RW: upper left - green */ -#define MII16_T1_FIFO 0x0800 /* RW: reset fifos */ -#define MII16_T1_CRC32 0x1000 /* RW: CRC length 16/32 */ -#define MII16_T1_UNUSED2 0xE000 - -/* T3 framer: RW=Read/Write; RO=Read-Only; RC=Read/Clr; WO=Write-Only */ -#define T3CSR_STAT0 0x00 /* RO: real-time status */ -#define T3CSR_CTL1 0x01 /* RW: global control bits */ -#define T3CSR_FEBE 0x02 /* RC: Far End Block Error Counter */ -#define T3CSR_CERR 0x03 /* RC: C-bit Parity Error Counter */ -#define T3CSR_PERR 0x04 /* RC: P-bit Parity Error Counter */ -#define T3CSR_TX_FEAC 0x05 /* RW: Far End Alarm & Control */ -#define T3CSR_RX_FEAC 0x06 /* RO: Far End Alarm & Control */ -#define T3CSR_STAT7 0x07 /* RL: latched real-time status */ -#define T3CSR_CTL8 0x08 /* RW: extended global ctl bits */ -#define T3CSR_STAT9 0x09 /* RL: extended status bits */ -#define T3CSR_FERR 0x0A /* RC: F-bit Error Counter */ -#define T3CSR_MERR 0x0B /* RC: M-bit Error Counter */ -#define T3CSR_CTL12 0x0C /* RW: more extended ctl bits */ -#define T3CSR_DBL_FEAC 0x0D /* RW: TX double FEAC */ -#define T3CSR_CTL14 0x0E /* RW: even more extended ctl bits */ -#define T3CSR_FEAC_STK 0x0F /* RO: RX FEAC stack */ -#define T3CSR_STAT16 0x10 /* RL: extended latched status */ -#define T3CSR_INTEN 0x11 /* RW: interrupt enable */ -#define T3CSR_CVLO 0x12 /* RC: coding violation cntr LSB */ -#define T3CSR_CVHI 0x13 /* RC: coding violation cntr MSB */ -#define T3CSR_CTL20 0x14 /* RW: yet more extended ctl bits */ - -#define CTL1_XTX 0x01 /* Transmit X-bit value */ -#define CTL1_3LOOP 0x02 /* framer loop back */ -#define CTL1_SER 0x04 /* SERial interface selected */ -#define CTL1_M13MODE 0x08 /* M13 frame format */ -#define CTL1_TXIDL 0x10 /* Transmit Idle signal */ -#define CTL1_ENAIS 0x20 /* Enable AIS upon LOS */ -#define CTL1_TXAIS 0x40 /* Transmit Alarm Indication Sig */ -#define CTL1_NOFEBE 0x80 /* No Far End Block Errors */ - -#define CTL5_EMODE 0x80 /* rev B Extended features enabled */ -#define CTL5_START 0x40 /* transmit the FEAC msg now */ - -#define CTL8_FBEC 0x80 /* F-Bit Error Count control */ -#define CTL8_TBLU 0x20 /* Transmit Blue signal */ -#define CTL8_OUT_DIS 0x10 /* Output Disable */ - -#define STAT9_SEF 0x80 /* Severely Errored Frame */ -#define STAT9_RBLU 0x20 /* Receive Blue signal */ - -#define CTL12_RTPLLEN 0x80 /* Rx-to-Tx Payload Lpbk Lock ENbl */ -#define CTL12_RTPLOOP 0x40 /* Rx-to-Tx Payload Loopback */ -#define CTL12_DLCB1 0x08 /* Data Link C-Bits forced to 1 */ -#define CTL12_C21 0x04 /* C2 forced to 1 */ -#define CTL12_MCB1 0x02 /* Most C-Bits forced to 1 */ - -#define CTL13_DFEXEC 0x40 /* Execute Double FEAC */ - -#define CTL14_FEAC10 0x80 /* Transmit FEAC word 10 times */ -#define CTL14_RGCEN 0x20 /* Receive Gapped Clock Out Enbl */ -#define CTL14_TGCEN 0x10 /* Timing Gen Gapped Clk Out Enbl */ - -#define FEAC_STK_MORE 0x80 /* FEAC stack has more FEACs */ -#define FEAC_STK_VALID 0x40 /* FEAC stack is valid */ -#define FEAC_STK_FEAC 0x3F /* FEAC stack FEAC data */ - -#define STAT16_XERR 0x01 /* X-bit Error */ -#define STAT16_SEF 0x02 /* Severely Errored Frame */ -#define STAT16_RTLOC 0x04 /* Rx/Tx Loss Of Clock */ -#define STAT16_FEAC 0x08 /* new FEAC msg */ -#define STAT16_RIDL 0x10 /* channel IDLe signal */ -#define STAT16_RAIS 0x20 /* Alarm Indication Signal */ -#define STAT16_ROOF 0x40 /* Out Of Frame sync */ -#define STAT16_RLOS 0x80 /* Loss Of Signal */ - -#define CTL20_CVEN 0x01 /* Coding Violation Counter Enbl */ - -/* T1.107 Bit Oriented C-Bit Parity Far End Alarm Control and Status codes */ -#define T3BOP_OOF 0x00 /* Yellow alarm status */ -#define T3BOP_LINE_UP 0x07 /* line loopback activate */ -#define T3BOP_LINE_DOWN 0x1C /* line loopback deactivate */ -#define T3BOP_LOOP_DS3 0x1B /* loopback full DS3 */ -#define T3BOP_IDLE 0x1A /* IDLE alarm status */ -#define T3BOP_AIS 0x16 /* AIS alarm status */ -#define T3BOP_LOS 0x0E /* LOS alarm status */ - -/* T1E1 regs; RW=Read/Write; RO=Read-Only; RC=Read/Clr; WO=Write-Only */ -#define Bt8370_DID 0x000 /* RO: Device ID */ -#define Bt8370_CR0 0x001 /* RW; Primary Control Register */ -#define Bt8370_JAT_CR 0x002 /* RW: Jitter Attenuator CR */ -#define Bt8370_IRR 0x003 /* RO: Interrupt Request Reg */ -#define Bt8370_ISR7 0x004 /* RC: Alarm 1 Interrupt Status */ -#define Bt8370_ISR6 0x005 /* RC: Alarm 2 Interrupt Status */ -#define Bt8370_ISR5 0x006 /* RC: Error Interrupt Status */ -#define Bt8370_ISR4 0x007 /* RC; Cntr Ovfl Interrupt Status */ -#define Bt8370_ISR3 0x008 /* RC: Timer Interrupt Status */ -#define Bt8370_ISR2 0x009 /* RC: Data Link 1 Int Status */ -#define Bt8370_ISR1 0x00A /* RC: Data Link 2 Int Status */ -#define Bt8370_ISR0 0x00B /* RC: Pattrn Interrupt Status */ -#define Bt8370_IER7 0x00C /* RW: Alarm 1 Interrupt Enable */ -#define Bt8370_IER6 0x00D /* RW: Alarm 2 Interrupt Enable */ -#define Bt8370_IER5 0x00E /* RW: Error Interrupt Enable */ -#define Bt8370_IER4 0x00F /* RW: Cntr Ovfl Interrupt Enable */ - -#define Bt8370_IER3 0x010 /* RW: Timer Interrupt Enable */ -#define Bt8370_IER2 0x011 /* RW: Data Link 1 Int Enable */ -#define Bt8370_IER1 0x012 /* RW: Data Link 2 Int Enable */ -#define Bt8370_IER0 0x013 /* RW: Pattern Interrupt Enable */ -#define Bt8370_LOOP 0x014 /* RW: Loopback Config Reg */ -#define Bt8370_DL3_TS 0x015 /* RW: External Data Link Channel */ -#define Bt8370_DL3_BIT 0x016 /* RW: External Data Link Bit */ -#define Bt8370_FSTAT 0x017 /* RO: Offline Framer Status */ -#define Bt8370_PIO 0x018 /* RW: Programmable Input/Output */ -#define Bt8370_POE 0x019 /* RW: Programmable Output Enable */ -#define Bt8370_CMUX 0x01A /* RW: Clock Input Mux */ -#define Bt8370_TMUX 0x01B /* RW: Test Mux Config */ -#define Bt8370_TEST 0x01C /* RW: Test Config */ - -#define Bt8370_LIU_CR 0x020 /* RW: Line Intf Unit Config Reg */ -#define Bt8370_RSTAT 0x021 /* RO; Receive LIU Status */ -#define Bt8370_RLIU_CR 0x022 /* RW: Receive LIU Config */ -#define Bt8370_LPF 0x023 /* RW: RPLL Low Pass Filter */ -#define Bt8370_VGA_MAX 0x024 /* RW: Variable Gain Amplifier Max */ -#define Bt8370_EQ_DAT 0x025 /* RW: Equalizer Coeff Data Reg */ -#define Bt8370_EQ_PTR 0x026 /* RW: Equzlizer Coeff Table Ptr */ -#define Bt8370_DSLICE 0x027 /* RW: Data Slicer Threshold */ -#define Bt8370_EQ_OUT 0x028 /* RW: Equalizer Output Levels */ -#define Bt8370_VGA 0x029 /* RO: Variable Gain Ampl Status */ -#define Bt8370_PRE_EQ 0x02A /* RW: Pre-Equalizer */ - -#define Bt8370_COEFF0 0x030 /* RO: LMS Adj Eq Coeff Status */ -#define Bt8370_GAIN0 0x038 /* RW: Equalizer Gain Thresh */ -#define Bt8370_GAIN1 0x039 /* RW: Equalizer Gain Thresh */ -#define Bt8370_GAIN2 0x03A /* RW: Equalizer Gain Thresh */ -#define Bt8370_GAIN3 0x03B /* RW: Equalizer Gain Thresh */ -#define Bt8370_GAIN4 0x03C /* RW: Equalizer Gain Thresh */ - -#define Bt8370_RCR0 0x040 /* RW: Rx Configuration */ -#define Bt8370_RPATT 0x041 /* RW: Rx Test Pattern Config */ -#define Bt8370_RLB 0x042 /* RW: Rx Loopback Code Detr Conf */ -#define Bt8370_LBA 0x043 /* RW: Loopback Activate Code Patt */ -#define Bt8370_LBD 0x044 /* RW: Loopback Deact Code Patt */ -#define Bt8370_RALM 0x045 /* RW: Rx Alarm Signal Config */ -#define Bt8370_LATCH 0x046 /* RW: Alarm/Err/Cntr Latch Config */ -#define Bt8370_ALM1 0x047 /* RO: Alarm 1 Status */ -#define Bt8370_ALM2 0x048 /* RO: Alarm 2 Status */ -#define Bt8370_ALM3 0x049 /* RO: Alarm 3 Status */ - -#define Bt8370_FERR_LO 0x050 /* RC: Framing Bit Error Cntr LSB */ -#define Bt8370_FERR_HI 0x051 /* RC: Framing Bit Error Cntr MSB */ -#define Bt8370_CRC_LO 0x052 /* RC: CRC Error Counter LSB */ -#define Bt8370_CRC_HI 0x053 /* RC: CRC Error Counter MSB */ -#define Bt8370_LCV_LO 0x054 /* RC: Line Code Viol Counter LSB */ -#define Bt8370_LCV_HI 0x055 /* RC: Line Code Viol Counter MSB */ -#define Bt8370_FEBE_LO 0x056 /* RC: Far End Block Err Cntr LSB */ -#define Bt8370_FEBE_HI 0x057 /* RC: Far End Block Err Cntr MSB */ -#define Bt8370_BERR_LO 0x058 /* RC: PRBS Bit Error Counter LSB */ -#define Bt8370_BERR_HI 0x059 /* RC: PRBS Bit Error Counter MSB */ -#define Bt8370_AERR 0x05A /* RC: SEF/LOF/COFA counter */ -#define Bt8370_RSA4 0x05B /* RO: Rx Sa4 Byte Buffer */ -#define Bt8370_RSA5 0x05C /* RO: Rx Sa5 Byte Buffer */ -#define Bt8370_RSA6 0x05D /* RO: Rx Sa6 Byte Buffer */ -#define Bt8370_RSA7 0x05E /* RO: Rx Sa7 Byte Buffer */ -#define Bt8370_RSA8 0x05F /* RO: Rx Sa8 Byte Buffer */ - -#define Bt8370_SHAPE0 0x060 /* RW: Tx Pulse Shape Config */ -#define Bt8370_TLIU_CR 0x068 /* RW: Tx LIU Config Reg */ - -#define Bt8370_TCR0 0x070 /* RW: Tx Framer Config */ -#define Bt8370_TCR1 0x071 /* RW: Txter Configuration */ -#define Bt8370_TFRM 0x072 /* RW: Tx Frame Format */ -#define Bt8370_TERROR 0x073 /* RW: Tx Error Insert */ -#define Bt8370_TMAN 0x074 /* RW: Tx Manual Sa/FEBE Config */ -#define Bt8370_TALM 0x075 /* RW: Tx Alarm Signal Config */ -#define Bt8370_TPATT 0x076 /* RW: Tx Test Pattern Config */ -#define Bt8370_TLB 0x077 /* RW: Tx Inband Loopback Config */ -#define Bt8370_LBP 0x078 /* RW: Tx Inband Loopback Patt */ -#define Bt8370_TSA4 0x07B /* RW: Tx Sa4 Byte Buffer */ -#define Bt8370_TSA5 0x07C /* RW: Tx Sa5 Byte Buffer */ -#define Bt8370_TSA6 0x07D /* RW: Tx Sa6 Byte Buffer */ -#define Bt8370_TSA7 0x07E /* RW: Tx Sa7 Byte Buffer */ -#define Bt8370_TSA8 0x07F /* RW: Tx Sa8 Byte Buffer */ - -#define Bt8370_CLAD_CR 0x090 /* RW: Clock Rate Adapter Config */ -#define Bt8370_CSEL 0x091 /* RW: CLAD Frequency Select */ -#define Bt8370_CPHASE 0x092 /* RW: CLAD Phase Det Scale Factor */ -#define Bt8370_CTEST 0x093 /* RW: CLAD Test */ - -#define Bt8370_BOP 0x0A0 /* RW: Bit Oriented Protocol Xcvr */ -#define Bt8370_TBOP 0x0A1 /* RW: Tx BOP Codeword */ -#define Bt8370_RBOP 0x0A2 /* RO; Rx BOP Codeword */ -#define Bt8370_BOP_STAT 0x0A3 /* RO: BOP Status */ -#define Bt8370_DL1_TS 0x0A4 /* RW: DL1 Time Slot Enable */ -#define Bt8370_DL1_BIT 0x0A5 /* RW: DL1 Bit Enable */ -#define Bt8370_DL1_CTL 0x0A6 /* RW: DL1 Control */ -#define Bt8370_RDL1_FFC 0x0A7 /* RW: RDL1 FIFO Fill Control */ -#define Bt8370_RDL1 0x0A8 /* RO: RDL1 FIFO */ -#define Bt8370_RDL1_STAT 0x0A9 /* RO: RDL1 Status */ -#define Bt8370_PRM 0x0AA /* RW: Performance Report Message */ -#define Bt8370_TDL1_FEC 0x0AB /* RW: TDL1 FIFO Empty Control */ -#define Bt8370_TDL1_EOM 0x0AC /* WO: TDL1 End Of Message Control */ -#define Bt8370_TDL1 0x0AD /* RW: TDL1 FIFO */ -#define Bt8370_TDL1_STAT 0x0AE /* RO: TDL1 Status */ -#define Bt8370_DL2_TS 0x0AF /* RW: DL2 Time Slot Enable */ - -#define Bt8370_DL2_BIT 0x0B0 /* RW: DL2 Bit Enable */ -#define Bt8370_DL2_CTL 0x0B1 /* RW: DL2 Control */ -#define Bt8370_RDL2_FFC 0x0B2 /* RW: RDL2 FIFO Fill Control */ -#define Bt8370_RDL2 0x0B3 /* RO: RDL2 FIFO */ -#define Bt8370_RDL2_STAT 0x0B4 /* RO: RDL2 Status */ -#define Bt8370_TDL2_FEC 0x0B6 /* RW: TDL2 FIFO Empty Control */ -#define Bt8370_TDL2_EOM 0x0B7 /* WO; TDL2 End Of Message Control */ -#define Bt8370_TDL2 0x0B8 /* RW: TDL2 FIFO */ -#define Bt8370_TDL2_STAT 0x0B9 /* RO: TDL2 Status */ -#define Bt8370_DL_TEST1 0x0BA /* RW: DLINK Test Config */ -#define Bt8370_DL_TEST2 0x0BB /* RW: DLINK Test Status */ -#define Bt8370_DL_TEST3 0x0BC /* RW: DLINK Test Status */ -#define Bt8370_DL_TEST4 0x0BD /* RW: DLINK Test Control */ -#define Bt8370_DL_TEST5 0x0BE /* RW: DLINK Test Control */ - -#define Bt8370_SBI_CR 0x0D0 /* RW: System Bus Interface Config */ -#define Bt8370_RSB_CR 0x0D1 /* RW: Rx System Bus Config */ -#define Bt8370_RSYNC_BIT 0x0D2 /* RW: Rx System Bus Sync Bit Offs */ -#define Bt8370_RSYNC_TS 0x0D3 /* RW: Rx System Bus Sync TS Offs */ -#define Bt8370_TSB_CR 0x0D4 /* RW: Tx System Bus Config */ -#define Bt8370_TSYNC_BIT 0x0D5 /* RW: Tx System Bus Sync Bit OFfs */ -#define Bt8370_TSYNC_TS 0x0D6 /* RW: Tx System Bus Sync TS Offs */ -#define Bt8370_RSIG_CR 0x0D7 /* RW: Rx Siganalling Config */ -#define Bt8370_RSYNC_FRM 0x0D8 /* RW: Sig Reinsertion Frame Offs */ -#define Bt8370_SSTAT 0x0D9 /* RO: Slip Buffer Status */ -#define Bt8370_STACK 0x0DA /* RO: Rx Signalling Stack */ -#define Bt8370_RPHASE 0x0DB /* RO: RSLIP Phase Status */ -#define Bt8370_TPHASE 0x0DC /* RO: TSLIP Phase Status */ -#define Bt8370_PERR 0x0DD /* RO: RAM Parity Status */ - -#define Bt8370_SBCn 0x0E0 /* RW: System Bus Per-Channel Ctl */ -#define Bt8370_TPCn 0x100 /* RW: Tx Per-Channel Control */ -#define Bt8370_TSIGn 0x120 /* RW: Tx Signalling Buffer */ -#define Bt8370_TSLIP_LOn 0x140 /* RW: Tx PCM Slip Buffer Lo */ -#define Bt8370_TSLIP_HIn 0x160 /* RW: Tx PCM Slip Buffer Hi */ -#define Bt8370_RPCn 0x180 /* RW: Rx Per-Channel Control */ -#define Bt8370_RSIGn 0x1A0 /* RW: Rx Signalling Buffer */ -#define Bt8370_RSLIP_LOn 0x1C0 /* RW: Rx PCM Slip Buffer Lo */ -#define Bt8370_RSLIP_HIn 0x1E0 /* RW: Rx PCM Slip Buffer Hi */ - -/* Bt8370_LOOP (0x14) framer loopback control register bits */ -#define LOOP_ANALOG 0x01 /* inward loop thru LIU */ -#define LOOP_FRAMER 0x02 /* inward loop thru framer */ -#define LOOP_LINE 0x04 /* outward loop thru LIU */ -#define LOOP_PAYLOAD 0x08 /* outward loop of payload */ -#define LOOP_DUAL 0x06 /* inward framer + outward line */ - -/* Bt8370_ALM1 (0x47) receiver alarm status register bits */ -#define ALM1_SIGFRZ 0x01 /* Rx Signalling Freeze */ -#define ALM1_RLOF 0x02 /* Rx loss of frame alignment */ -#define ALM1_RLOS 0x04 /* Rx digital loss of signal */ -#define ALM1_RALOS 0x08 /* Rx analog loss of signal */ -#define ALM1_RAIS 0x10 /* Rx Alarm Indication Signal */ -#define ALM1_RYEL 0x40 /* Rx Yellow alarm indication */ -#define ALM1_RMYEL 0x80 /* Rx multiframe YELLOW alarm */ - -/* Bt8370_ALM3 (0x49) receive framer status register bits */ -#define ALM3_FRED 0x04 /* Rx Out Of T1/FAS alignment */ -#define ALM3_MRED 0x08 /* Rx Out Of MFAS alignment */ -#define ALM3_SRED 0x10 /* Rx Out Of CAS alignment */ -#define ALM3_SEF 0x20 /* Rx Severely Errored Frame */ -#define ALM3_RMAIS 0x40 /* Rx TS16 AIS (CAS) */ - -/* Bt8370_TALM (0x75) transmit alarm control register bits */ -#define TALM_TAIS 0x01 /* Tx Alarm Indication Signal */ -#define TALM_TYEL 0x02 /* Tx Yellow alarm */ -#define TALM_TMYEL 0x04 /* Tx Multiframe Yellow alarm */ -#define TALM_AUTO_AIS 0x08 /* auto send AIS on LOS */ -#define TALM_AUTO_YEL 0x10 /* auto send YEL on LOF */ -#define TALM_AUTO_MYEL 0x20 /* auto send E1-Y16 on loss-of-CAS */ - -/* 8370 BOP (Bit Oriented Protocol) command fragments */ -#define RBOP_OFF 0x00 /* BOP Rx disabled */ -#define RBOP_25 0xE0 /* BOP Rx requires 25 BOPs */ -#define TBOP_OFF 0x00 /* BOP Tx disabled */ -#define TBOP_25 0x0B /* BOP Tx sends 25 BOPs */ -#define TBOP_CONT 0x0F /* BOP Tx sends continuously */ - -/* T1.403 Bit-Oriented ESF Data-Link Message codes */ -#define T1BOP_OOF 0x00 /* Yellow alarm status */ -#define T1BOP_LINE_UP 0x07 /* line loopback activate */ -#define T1BOP_LINE_DOWN 0x1C /* line loopback deactivate */ -#define T1BOP_PAY_UP 0x0A /* payload loopback activate */ -#define T1BOP_PAY_DOWN 0x19 /* payload loopback deactivate */ -#define T1BOP_NET_UP 0x09 /* network loopback activate */ -#define T1BOP_NET_DOWN 0x12 /* network loopback deactivate */ - -/* Unix & Linux reserve 16 device-private IOCTLs */ -#if BSD -# define LMCIOCGSTAT _IOWR('i', 240, struct status) -# define LMCIOCGCFG _IOWR('i', 241, struct config) -# define LMCIOCSCFG _IOW('i', 242, struct config) -# define LMCIOCREAD _IOWR('i', 243, struct ioctl) -# define LMCIOCWRITE _IOW('i', 244, struct ioctl) -# define LMCIOCTL _IOWR('i', 245, struct ioctl) -#endif - -struct iohdr /* all LMCIOCs begin with this */ - { - char ifname[IFNAMSIZ]; /* interface name, e.g. "lmc0" */ - u_int32_t cookie; /* interface version number */ - u_int16_t direction; /* missing in Linux IOCTL */ - u_int16_t length; /* missing in Linux IOCTL */ - struct iohdr *iohdr; /* missing in Linux IOCTL */ - u_int32_t spare; /* pad this struct to **32 bytes** */ - }; - -#define DIR_IO 0 -#define DIR_IOW 1 /* copy data user->kernel */ -#define DIR_IOR 2 /* copy data kernel->user */ -#define DIR_IOWR 3 /* copy data kernel<->user */ - -struct hssi_snmp - { - u_int16_t sigs; /* MII16_HSSI & MII16_HSSI_MODEM */ - }; - -struct ssi_snmp - { - u_int16_t sigs; /* MII16_SSI & MII16_SSI_MODEM */ - }; - -struct t3_snmp - { - u_int16_t febe; /* 8 bits - Far End Block err cnt */ - u_int16_t lcv; /* 16 bits - BPV err cnt */ - u_int16_t pcv; /* 8 bits - P-bit err cnt */ - u_int16_t ccv; /* 8 bits - C-bit err cnt */ - u_int16_t line; /* line status bit vector */ - u_int16_t loop; /* loop status bit vector */ - }; - -struct t1_snmp - { - u_int16_t prm[4]; /* T1.403 Performance Report Msg */ - u_int16_t febe; /* 10 bits - E1 FAR CRC err cnt */ - u_int16_t lcv; /* 16 bits - BPV + EXZ err cnt */ - u_int16_t fe; /* 12 bits - Ft/Fs/FPS/FAS err cnt */ - u_int16_t crc; /* 10 bits - CRC6/CRC4 err cnt */ - u_int16_t line; /* line status bit vector */ - u_int16_t loop; /* loop status bit vector */ - }; - -/* SNMP trunk MIB Send codes */ -#define TSEND_NORMAL 1 /* Send data (normal or looped) */ -#define TSEND_LINE 2 /* Send 'line loopback activate' */ -#define TSEND_PAYLOAD 3 /* Send 'payload loop activate' */ -#define TSEND_RESET 4 /* Send 'loopback deactivate' */ -#define TSEND_QRS 5 /* Send Quasi Random Signal */ - -/* ANSI T1.403 Performance Report Msg -- once a second from the far end */ -#define T1PRM_FE 0x8000 /* Frame Sync Bit Error Event >= 1 */ -#define T1PRM_SE 0x4000 /* Severely Err Framing Event >= 1 */ -#define T1PRM_LB 0x2000 /* Payload Loopback Activated */ -#define T1PRM_G1 0x1000 /* CRC Error Event = 1 */ -#define T1PRM_R 0x0800 /* Reserved */ -#define T1PRM_G2 0x0400 /* 1 < CRC Error Event <= 5 */ -#define T1PRM_SEQ 0x0300 /* modulo 4 counter */ -#define T1PRM_G3 0x0080 /* 5 < CRC Error Event <= 10 */ -#define T1PRM_LV 0x0040 /* Line Code Violation Event >= 1 */ -#define T1PRM_G4 0x0020 /* 10 < CRC Error Event <= 100 */ -#define T1PRM_U 0x0018 /* Under study for synchronization */ -#define T1PRM_G5 0x0004 /* 100 < CRC Error Event <= 319 */ -#define T1PRM_SL 0x0002 /* Slip Event >= 1 */ -#define T1PRM_G6 0x0001 /* CRC Error Event >= 320 */ - -/* SNMP Line Status */ -#define TLINE_NORM 0x0001 /* no alarm present */ -#define TLINE_RX_RAI 0x0002 /* receiving RAI = Yellow alarm */ -#define TLINE_TX_RAI 0x0004 /* sending RAI = Yellow alarm */ -#define TLINE_RX_AIS 0x0008 /* receiving AIS = blue alarm */ -#define TLINE_TX_AIS 0x0010 /* sending AIS = blue alarm */ -#define TLINE_LOF 0x0020 /* near end LOF = red alarm */ -#define TLINE_LOS 0x0040 /* near end loss of Signal */ -#define TLINE_LOOP 0x0080 /* near end is looped */ -#define T1LINE_RX_TS16_AIS 0x0100 /* near end receiving TS16 AIS */ -#define T1LINE_RX_TS16_LOMF 0x0200 /* near end sending TS16 LOMF */ -#define T1LINE_TX_TS16_LOMF 0x0400 /* near end receiving TS16 LOMF */ -#define T1LINE_RX_TEST 0x0800 /* near end receiving QRS Signal */ -#define T1LINE_SEF 0x1000 /* near end severely errored frame */ -#define T3LINE_RX_IDLE 0x0100 /* near end receiving IDLE signal */ -#define T3LINE_SEF 0x0200 /* near end severely errored frame */ - -/* SNMP Loopback Status */ -#define TLOOP_NONE 0x01 /* no loopback */ -#define TLOOP_NEAR_PAYLOAD 0x02 /* near end payload loopback */ -#define TLOOP_NEAR_LINE 0x04 /* near end line loopback */ -#define TLOOP_NEAR_OTHER 0x08 /* near end looped somehow */ -#define TLOOP_NEAR_INWARD 0x10 /* near end looped inward */ -#define TLOOP_FAR_PAYLOAD 0x20 /* far end payload loopback */ -#define TLOOP_FAR_LINE 0x40 /* far end line loopback */ - -/* event counters record interesting statistics */ -struct cntrs - { - struct timeval reset_time; /* time when cntrs were reset */ - u_int64_t ibytes; /* Rx bytes with good status */ - u_int64_t obytes; /* Tx bytes */ - u_int64_t ipackets; /* Rx packets with good status */ - u_int64_t opackets; /* Tx packets */ - u_int32_t ierrors; /* Rx packets with bad status */ - u_int32_t oerrors; /* Tx packets with bad status */ - u_int32_t idrops; /* Rx packets dropped by SW */ - u_int32_t missed; /* Rx pkts missed: no DMA descs */ - u_int32_t odrops; /* Tx packets dropped by SW */ - u_int32_t fifo_over; /* Rx fifo overruns from DMA desc */ - u_int32_t overruns; /* Rx fifo overruns from CSR */ - u_int32_t fifo_under; /* Tx fifo underruns from DMA desc */ - u_int32_t underruns; /* Rx fifo underruns from CSR */ - u_int32_t fdl_pkts; /* Rx T1 Facility Data Link pkts */ - u_int32_t crc_errs; /* Rx T1 frame CRC errors */ - u_int32_t lcv_errs; /* Rx T1 T3 Line Coding Violation */ - u_int32_t frm_errs; /* Rx T1 T3 Frame bit errors */ - u_int32_t febe_errs; /* Rx T1 T3 Far End Bit Errors */ - u_int32_t par_errs; /* Rx T3 P-bit parity errors */ - u_int32_t cpar_errs; /* Rx T3 C-bit parity errors */ - u_int32_t mfrm_errs; /* Rx T3 Multi-frame bit errors */ - u_int32_t rxbuf; /* Rx out of packet buffers */ - u_int32_t txdma; /* Tx out of DMA desciptors */ - u_int32_t lck_watch; /* lock conflict in watchdog */ - u_int32_t lck_intr; /* lock conflict in interrupt */ - u_int32_t spare1; /* debugging temp */ - u_int32_t spare2; /* debugging temp */ - u_int32_t spare3; /* debugging temp */ - u_int32_t spare4; /* debugging temp */ - }; - -/* sc->status is the READ ONLY status of the card. */ -/* Accessed using socket IO control calls or netgraph control messages. */ -struct status - { - struct iohdr iohdr; /* common ioctl header */ - u_int32_t card_type; /* PCI device number */ - u_int16_t link_state; /* actual state: up, down, test */ - u_int32_t tx_speed; /* measured TX bits/sec */ - u_int32_t cable_type; /* SSI only: cable type */ - u_int32_t time_slots; /* T1E1 only: actual TSs in use */ - u_int32_t stack; /* actual line stack in use */ - u_int32_t proto; /* actual line proto in use */ - u_int32_t keep_alive; /* actual keep-alive status */ - u_int32_t ticks; /* incremented by watchdog @ 1 Hz */ - struct cntrs cntrs; /* event counters */ - union - { - struct hssi_snmp hssi; /* data for RFC-???? HSSI MIB */ - struct t3_snmp t3; /* data for RFC-2496 T3 MIB */ - struct ssi_snmp ssi; /* data for RFC-1659 RS232 MIB */ - struct t1_snmp t1; /* data for RFC-2495 T1 MIB */ - } snmp; - }; - -/* protocol stack codes */ -#define STACK_NONE 0 /* not set fnobl */ -#define STACK_RAWIP 1 /* driver yyyyy */ -#define STACK_SPPP 2 /* fbsd, nbsd, obsd yyynn */ -#define STACK_P2P 3 /* bsd/os nnnyn */ -#define STACK_GEN_HDLC 4 /* linux nnnny */ -#define STACK_SYNC_PPP 5 /* linux nnnny */ -#define STACK_NETGRAPH 6 /* fbsd ynnnn */ - -/* line protocol codes */ -#define PROTO_NONE 0 /* not set fnobl */ -#define PROTO_IP_HDLC 1 /* raw IP4/6 pkts in HDLC yyyyy */ -#define PROTO_PPP 2 /* Point-to-Point Protocol yyyyy */ -#define PROTO_C_HDLC 3 /* Cisco HDLC Protocol yyyyy */ -#define PROTO_FRM_RLY 4 /* Frame Relay Protocol ynnyy */ -#define PROTO_ETH_HDLC 5 /* raw Ether pkts in HDLC nnnny */ -#define PROTO_X25 6 /* X.25/LAPB Protocol nnnny */ - -/* oper_status codes (same as SNMP status codes) */ -#define STATE_UP 1 /* may/will tx/rx pkts */ -#define STATE_DOWN 2 /* can't/won't tx/rx pkts */ -#define STATE_TEST 3 /* currently not used */ - -struct synth /* programmable oscillator params */ - { - unsigned n:7; /* numerator (3..127) */ - unsigned m:7; /* denominator (3..127) */ - unsigned v:1; /* mul by 1|8 */ - unsigned x:2; /* div by 1|2|4|8 */ - unsigned r:2; /* div by 1|2|4|8 */ - unsigned prescale:13; /* log(final divisor): 2, 4 or 9 */ - } __packed; - -#define SYNTH_FREF 20e6 /* reference xtal = 20 MHz */ -#define SYNTH_FMIN 50e6 /* internal VCO min 50 MHz */ -#define SYNTH_FMAX 250e6 /* internal VCO max 250 MHz */ - -/* sc->config is the READ/WRITE configuration of the card. */ -/* Accessed using socket IO control calls or netgraph control messages. */ -struct config - { - struct iohdr iohdr; /* common ioctl header */ - u_int32_t crc_len; /* ALL: CRC-16 or CRC-32 or none */ - u_int32_t loop_back; /* ALL: many kinds of loopbacks */ - u_int32_t tx_clk_src; /* T1, HSSI: ST, RT, int, ext */ - u_int32_t format; /* T3, T1: ckt framing format */ - u_int32_t time_slots; /* T1: 64Kb time slot config */ - u_int32_t cable_len; /* T3, T1: cable length in meters */ - u_int32_t scrambler; /* T3: payload scrambler config */ - u_int32_t dte_dce; /* SSI, HSSIc: drive TXCLK */ - struct synth synth; /* SSI, HSSIc: synth oscil params */ - u_int32_t rx_gain_max; /* T1: receiver gain limit 0-50 dB */ - u_int32_t tx_pulse; /* T1: transmitter pulse shape */ - u_int32_t tx_lbo; /* T1: transmitter atten 0-22.5 dB */ - u_int32_t debug; /* ALL: extra printout */ - u_int32_t stack; /* ALL: use this line stack */ - u_int32_t proto; /* ALL: use this line proto */ - u_int32_t keep_alive; /* SPPP: use keep-alive packets */ - }; - -#define CFG_CRC_0 0 /* no CRC */ -#define CFG_CRC_16 2 /* X^16+X^12+X^5+1 (default) */ -#define CFG_CRC_32 4 /* X^32+X^26+X^23+X^22+X^16+X^12+ */ - /* X^11+X^10+X^8+X^7+X^5+X^4+X^2+X+1 */ -#define CFG_LOOP_NONE 1 /* SNMP don't loop back anything */ -#define CFG_LOOP_PAYLOAD 2 /* SNMP loop outward thru framer */ -#define CFG_LOOP_LINE 3 /* SNMP loop outward thru LIU */ -#define CFG_LOOP_OTHER 4 /* SNMP loop inward thru LIU */ -#define CFG_LOOP_INWARD 5 /* SNMP loop inward thru framer */ -#define CFG_LOOP_DUAL 6 /* SNMP loop inward & outward */ -#define CFG_LOOP_TULIP 16 /* ALL: loop inward thru Tulip */ -#define CFG_LOOP_PINS 17 /* HSSIc, SSI: loop inward-pins */ -#define CFG_LOOP_LL 18 /* HSSI, SSI: assert LA/LL mdm pin */ -#define CFG_LOOP_RL 19 /* HSSI, SSI: assert LB/RL mdm pin */ - -#define CFG_CLKMUX_ST 1 /* TX clk <- Send timing */ -#define CFG_CLKMUX_INT 2 /* TX clk <- internal source */ -#define CFG_CLKMUX_RT 3 /* TX clk <- Receive (loop) timing */ -#define CFG_CLKMUX_EXT 4 /* TX clk <- ext connector */ - -/* values 0-31 are Bt8370 CR0 register values (LSB is zero if E1). */ -/* values 32-99 are reserved for other T1E1 formats, (even number if E1) */ -/* values 100 and up are used for T3 frame formats. */ -#define CFG_FORMAT_T1SF 9 /* T1-SF AMI */ -#define CFG_FORMAT_T1ESF 27 /* T1-ESF+CRC B8ZS X^6+X+1 */ -#define CFG_FORMAT_E1FAS 0 /* E1-FAS HDB3 TS0 */ -#define CFG_FORMAT_E1FASCRC 8 /* E1-FAS+CRC HDB3 TS0 X^4+X+1 */ -#define CFG_FORMAT_E1FASCAS 16 /* E1-FAS +CAS HDB3 TS0 & TS16 */ -#define CFG_FORMAT_E1FASCRCCAS 24 /* E1-FAS+CRC+CAS HDB3 TS0 & TS16 */ -#define CFG_FORMAT_E1NONE 32 /* E1-NO framing HDB3 */ -#define CFG_FORMAT_T3CPAR 100 /* T3-C-Bit par B3ZS */ -#define CFG_FORMAT_T3M13 101 /* T3-M13 format B3ZS */ - -/* format aliases that improve code readability */ -#define FORMAT_T1ANY ((sc->config.format & 1)==1) -#define FORMAT_E1ANY ((sc->config.format & 1)==0) -#define FORMAT_E1CAS ((sc->config.format & 0x11)==0x10) -#define FORMAT_E1CRC ((sc->config.format & 0x09)==0x08) -#define FORMAT_E1NONE (sc->config.format == CFG_FORMAT_E1NONE) -#define FORMAT_T1ESF (sc->config.format == CFG_FORMAT_T1ESF) -#define FORMAT_T1SF (sc->config.format == CFG_FORMAT_T1SF) -#define FORMAT_T3CPAR (sc->config.format == CFG_FORMAT_T3CPAR) - -#define CFG_SCRAM_OFF 1 /* DS3 payload scrambler off */ -#define CFG_SCRAM_DL_KEN 2 /* DS3 DigitalLink/Kentrox X^43+1 */ -#define CFG_SCRAM_LARS 3 /* DS3 Larscom X^20+X^17+1 w/28ZS */ - -#define CFG_DTE 1 /* HSSIc, SSI: rcv TXCLK; rcv DCD */ -#define CFG_DCE 2 /* HSSIc, SSI: drv TXCLK; drv DCD */ - -#define CFG_GAIN_SHORT 0x24 /* 0-20 dB of equalized gain */ -#define CFG_GAIN_MEDIUM 0x2C /* 0-30 dB of equalized gain */ -#define CFG_GAIN_LONG 0x34 /* 0-40 dB of equalized gain */ -#define CFG_GAIN_EXTEND 0x3F /* 0-64 dB of equalized gain */ -#define CFG_GAIN_AUTO 0xFF /* auto-set based on cable length */ - -#define CFG_PULSE_T1DSX0 0 /* T1 DSX 0- 40 meters */ -#define CFG_PULSE_T1DSX1 2 /* T1 DSX 40- 80 meters */ -#define CFG_PULSE_T1DSX2 4 /* T1 DSX 80-120 meters */ -#define CFG_PULSE_T1DSX3 6 /* T1 DSX 120-160 meters */ -#define CFG_PULSE_T1DSX4 8 /* T1 DSX 160-200 meters */ -#define CFG_PULSE_E1COAX 10 /* E1 75 ohm coax pair */ -#define CFG_PULSE_E1TWIST 12 /* E1 120 ohm twisted pairs */ -#define CFG_PULSE_T1CSU 14 /* T1 CSU 200-2000 meters; set LBO */ -#define CFG_PULSE_AUTO 0xFF /* auto-set based on cable length */ - -#define CFG_LBO_0DB 0 /* T1CSU LBO = 0.0 dB; FCC opt A */ -#define CFG_LBO_7DB 16 /* T1CSU LBO = 7.5 dB; FCC opt B */ -#define CFG_LBO_15DB 32 /* T1CSU LBO = 15.0 dB; FCC opt C */ -#define CFG_LBO_22DB 48 /* T1CSU LBO = 22.5 dB; final span */ -#define CFG_LBO_AUTO 0xFF /* auto-set based on cable length */ - -struct ioctl - { - struct iohdr iohdr; /* common ioctl header */ - u_int32_t cmd; /* command */ - u_int32_t address; /* command address */ - u_int32_t data; /* command data */ - char *ucode; /* user-land address of ucode */ - }; - -#define IOCTL_RW_PCI 1 /* RW: Tulip PCI config registers */ -#define IOCTL_RW_CSR 2 /* RW: Tulip Control & Status Regs */ -#define IOCTL_RW_SROM 3 /* RW: Tulip Serial Rom */ -#define IOCTL_RW_BIOS 4 /* RW: Tulip Boot rom */ -#define IOCTL_RW_MII 5 /* RW: MII registers */ -#define IOCTL_RW_FRAME 6 /* RW: Framer registers */ -#define IOCTL_WO_SYNTH 7 /* WO: Synthesized oscillator */ -#define IOCTL_WO_DAC 8 /* WO: Digital/Analog Converter */ - -#define IOCTL_XILINX_RESET 16 /* reset Xilinx: all FFs set to 0 */ -#define IOCTL_XILINX_ROM 17 /* load Xilinx program from ROM */ -#define IOCTL_XILINX_FILE 18 /* load Xilinx program from file */ - -#define IOCTL_SET_STATUS 50 /* set mdm ctrl bits (internal) */ -#define IOCTL_SNMP_SEND 51 /* trunk MIB send code */ -#define IOCTL_SNMP_LOOP 52 /* trunk MIB loop configuration */ -#define IOCTL_SNMP_SIGS 53 /* RS232-like modem control sigs */ -#define IOCTL_RESET_CNTRS 54 /* reset event counters */ - -/* storage for these strings is allocated here! */ -const char *ssi_cables[] = - { - "V.10/EIA423", - "V.11/EIA530A", - "RESERVED", - "X.21", - "V.35", - "V.36/EIA449", - "V.28/EIA232", - "NO CABLE", - NULL, - }; - -/***************************************************************************/ -/* Declarations above here are shared with the user lmcconfig program. */ -/* Declarations below here are private to the kernel device driver. */ -/***************************************************************************/ - -#if KERNEL || _KERNEL || __KERNEL__ - -/* Hide the minor differences between Operating Systems */ - -typedef int intr_return_t; -# define READ_PCI_CFG(sc, addr) pci_conf_read ((sc)->pa_pc, (sc)->pa_tag, addr) -# define WRITE_PCI_CFG(sc, addr, data) pci_conf_write((sc)->pa_pc, (sc)->pa_tag, addr, data) -# define READ_CSR(sc, csr) bus_space_read_4 ((sc)->csr_tag, (sc)->csr_handle, csr) -# define WRITE_CSR(sc, csr, val) bus_space_write_4((sc)->csr_tag, (sc)->csr_handle, csr, val) -# define NAME_UNIT device_xname(sc->sc_dev) -# define BOOT_VERBOSE (boothowto & AB_VERBOSE) -# define TOP_LOCK(sc) (mutex_spin_enter(&(sc)->top_lock), 0) -# define TOP_TRYLOCK(sc) mutex_tryenter(&(sc)->top_lock) -# define TOP_UNLOCK(sc) mutex_spin_exit(&(sc)->top_lock) -# define BOTTOM_TRYLOCK(sc) __cpu_simple_lock_try(&(sc)->bottom_lock) -# define BOTTOM_UNLOCK(sc) __cpu_simple_unlock (&(sc)->bottom_lock) -# define CHECK_CAP kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE, KAUTH_REQ_NETWORK_INTERFACE_FIRMWARE, sc->ifp, NULL, NULL) -# define DISABLE_INTR int spl = splnet() -# define ENABLE_INTR splx(spl) -# define IRQ_NONE 0 -# define IRQ_HANDLED 1 -# define IFP2SC(ifp) (ifp)->if_softc -# define COPY_BREAK MHLEN -# define SLEEP(usecs) tsleep(sc, PZERO, DEVICE_NAME, 1+(usecs/tick)) -# define DMA_SYNC(map, size, flags) bus_dmamap_sync(ring->tag, map, 0, size, flags) -# define DMA_LOAD(map, addr, size) bus_dmamap_load(ring->tag, map, addr, size, 0, BUS_DMA_NOWAIT) -# define LMC_BPF_ATTACH(sc, dlt, len) \ - do { \ - bpf_attach((sc)->ifp, dlt, len); \ - bpf_mtap_softint_init((sc)->ifp); \ - } while (0) -# define LMC_BPF_DETACH(sc) bpf_detach((sc)->ifp) - -static int driver_announced = 0; /* print driver info once only */ - -#define SNDQ_MAXLEN 32 /* packets awaiting transmission */ -#define DESCS_PER_PKT 4 /* DMA descriptors per TX pkt */ -#define NUM_TX_DESCS (DESCS_PER_PKT * SNDQ_MAXLEN) -/* Increase DESCS_PER_PKT if status.cntrs.txdma increments. */ - -/* A Tulip DMA descriptor can point to two chunks of memory. - * Each chunk has a max length of 2047 bytes (ask the VMS guys). - * 2047 isn't a multiple of a cache line size (32 bytes typically). - * So back off to 2048-32 = 2016 bytes per chunk (2 chunks per descr). - */ -#define MAX_CHUNK_LEN (2048-32) -#define MAX_DESC_LEN (2 * MAX_CHUNK_LEN) - -/* Tulip DMA descriptor; THIS STRUCT MUST MATCH THE HARDWARE */ -struct dma_desc - { - u_int32_t status; /* hardware->to->software */ -#if BYTE_ORDER == LITTLE_ENDIAN /* left-to-right packing */ - unsigned length1:11; /* buffer1 length */ - unsigned length2:11; /* buffer2 length */ - unsigned control:10; /* software->to->hardware */ -#else /* right-to-left packing */ - unsigned control:10; /* software->to->hardware */ - unsigned length2:11; /* buffer2 length */ - unsigned length1:11; /* buffer1 length */ -#endif - u_int32_t address1; /* buffer1 bus address */ - u_int32_t address2; /* buffer2 bus address */ - bus_dmamap_t map; /* bus dmamap for this descriptor */ -# define TLP_BUS_DSL_VAL (sizeof(bus_dmamap_t) & TLP_BUS_DSL) - } __packed; - -/* Tulip DMA descriptor status bits */ -#define TLP_DSTS_OWNER 0x80000000 -#define TLP_DSTS_RX_DESC_ERR 0x00004000 -#define TLP_DSTS_RX_FIRST_DESC 0x00000200 -#define TLP_DSTS_RX_LAST_DESC 0x00000100 -#define TLP_DSTS_RX_MII_ERR 0x00000008 -#define TLP_DSTS_RX_DRIBBLE 0x00000004 -#define TLP_DSTS_TX_UNDERRUN 0x00000002 -#define TLP_DSTS_RX_OVERRUN 0x00000001 /* not documented in rev AF */ -#define TLP_DSTS_RX_BAD (TLP_DSTS_RX_MII_ERR | \ - TLP_DSTS_RX_DRIBBLE | \ - TLP_DSTS_RX_DESC_ERR | \ - TLP_DSTS_RX_OVERRUN) - -/* Tulip DMA descriptor control bits */ -#define TLP_DCTL_TX_INTERRUPT 0x0200 -#define TLP_DCTL_TX_LAST_SEG 0x0100 -#define TLP_DCTL_TX_FIRST_SEG 0x0080 -#define TLP_DCTL_TX_NO_CRC 0x0010 -#define TLP_DCTL_END_RING 0x0008 -#define TLP_DCTL_TX_NO_PAD 0x0002 - -/* DMA descriptors are kept in a ring. - * Ring is empty when (read == write). - * Ring is full when (read == wrap(write+1)), - * The ring also contains a tailq of data buffers. - */ -struct desc_ring - { - struct dma_desc *read; /* next descriptor to be read */ - struct dma_desc *write; /* next descriptor to be written */ - struct dma_desc *first; /* first descriptor in ring */ - struct dma_desc *last; /* last descriptor in ring */ - struct dma_desc *temp; /* temporary write pointer for tx */ - u_int32_t dma_addr; /* bus addr for desc array XXX */ - int size_descs; /* bus_dmamap_sync needs this */ - int num_descs; /* used to set rx quota */ -#if IFNET || NETGRAPH - struct mbuf *head; /* tail-queue of mbufs */ - struct mbuf *tail; -#elif NETDEV - struct sk_buff *head; /* tail-queue of skbuffs */ - struct sk_buff *tail; -#endif - bus_dma_tag_t tag; /* bus_dma_tag for desc array */ - bus_dmamap_t map; /* bus_dmamap for desc array */ - bus_dma_segment_t segs[2]; /* bus_dmamap_load() or bus_dmamem_alloc() */ - int nsegs; /* bus_dmamap_load() or bus_dmamem_alloc() */ - }; - -/* break circular definition */ -typedef struct softc softc_t; - -struct card /* an object */ - { - void (*ident) (softc_t *); - void (*watchdog) (softc_t *); - int (*ioctl) (softc_t *, struct ioctl *); - void (*attach) (softc_t *, struct config *); - void (*detach) (softc_t *); - }; - -struct stack /* an object */ - { -#if IFNET || NETGRAPH - int (*ioctl) (softc_t *, u_long, void *); - void (*input) (softc_t *, struct mbuf *); - void (*output) (softc_t *); -#elif NETDEV - int (*ioctl) (softc_t *, struct ifreq *, int); - int (*type) (softc_t *, struct sk_buff *); - int (*mtu) (softc_t *, int); -#endif - void (*watchdog) (softc_t *); - int (*open) (softc_t *, struct config *); - int (*attach) (softc_t *, struct config *); - int (*detach) (softc_t *); - }; - -/* This is the instance data, or "software context" for the device driver. */ -struct softc - { - - device_t sc_dev; - pcitag_t pa_tag; - pci_chipset_tag_t pa_pc; - bus_dma_tag_t pa_dmat; - bus_space_tag_t csr_tag; - bus_space_handle_t csr_handle; - pci_intr_handle_t intr_handle; - void *irq_cookie; - void *sdh_cookie; - struct mbuf *tx_mbuf; /* hang mbuf here while building dma descs */ - kmutex_t top_lock; /* lock card->watchdog vs ioctls */ - __cpu_simple_lock_t bottom_lock; /* lock buf queues & descriptor rings */ - - /* State for kernel-resident Line Protocols */ -#if IFNET -# if SPPP - struct sppp spppcom; - struct sppp *sppp; -# elif P2P - struct p2pcom p2pcom; - struct p2pcom *p2p; -# else - struct ifnet ifnet; -# endif - struct ifnet *ifp; - struct ifmedia ifm; -#endif /* IFNET */ - -#if NETDEV -# if GEN_HDLC - hdlc_device *hdlcdev; /* contains struct net_device_stats */ -# else - struct net_device_stats netdev_stats; -# endif -# if SYNC_PPP - struct ppp_device *ppd; - struct ppp_device ppp_dev; /* contains a struct sppp */ - struct sppp *sppp; -# endif - struct net_device *netdev; -#endif /* NETDEV */ - - - - - /* State used by all card types; lock with top_lock. */ - struct status status; /* lmcconfig can read */ - struct config config; /* lmcconfig can read/write */ - const char *dev_desc; /* string describing card */ - struct card *card; /* card methods */ - struct stack *stack; /* line methods */ - u_int32_t gpio_dir; /* s/w copy of GPIO direction reg */ - u_int16_t led_state; /* last value written to mii16 */ - int quota; /* used for packet flow control */ - - /* State used by card-specific watchdogs; lock with top_lock. */ - u_int32_t last_mii16; /* SSI, HSSI: MII reg 16 one sec ago */ - u_int32_t last_stat16; /* T3: framer reg 16 one sec ago */ - u_int32_t last_alm1; /* T1E1: framer reg 47 one sec ago */ - u_int32_t last_link_state; /* ALL: status.link_state 1 ec ago */ - u_int32_t last_FEAC; /* T3: last FEAC msg code received */ - u_int32_t loop_timer; /* T1E1, T3: secs until loop ends */ - - /* State used by the interrupt code; lock with bottom_lock. */ - struct desc_ring txring; /* tx descriptor ring state */ - struct desc_ring rxring; /* rx descriptor ring state */ - }; /* end of softc */ - - -#define HSSI_DESC "LMC5200 HSSI Card" -#define T3_DESC "LMC5245 T3 Card" -#define SSI_DESC "LMC1000 SSI Card" -#define T1E1_DESC "LMC1200 T1E1 Card" - -/* procedure prototypes */ - -static void srom_shift_bits(softc_t *, u_int32_t, u_int32_t); -static u_int16_t srom_read(softc_t *, u_int8_t); -static void srom_write(softc_t *, u_int8_t, u_int16_t); - -static u_int8_t bios_read(softc_t *, u_int32_t); -static void bios_write_phys(softc_t *, u_int32_t, u_int8_t); -static void bios_write(softc_t *, u_int32_t, u_int8_t); -static void bios_erase(softc_t *); - -static void mii_shift_bits(softc_t *, u_int32_t, u_int32_t); -static u_int16_t mii_read(softc_t *, u_int8_t); -static void mii_write(softc_t *, u_int8_t, u_int16_t); - -static void mii16_set_bits(softc_t *, u_int16_t); -static void mii16_clr_bits(softc_t *, u_int16_t); -static void mii17_set_bits(softc_t *, u_int16_t); -static void mii17_clr_bits(softc_t *, u_int16_t); - -static void led_off(softc_t *, u_int16_t); -static void led_on(softc_t *, u_int16_t); -static void led_inv(softc_t *, u_int16_t); - -static void framer_write(softc_t *, u_int16_t, u_int8_t); -static u_int8_t framer_read(softc_t *, u_int16_t); - -static void gpio_make_input(softc_t *, u_int32_t); -static void gpio_make_output(softc_t *, u_int32_t); -static u_int32_t gpio_read(softc_t *); -static void gpio_set_bits(softc_t *, u_int32_t); -static void gpio_clr_bits(softc_t *, u_int32_t); - -static void xilinx_reset(softc_t *); -static void xilinx_load_from_rom(softc_t *); -static int xilinx_load_from_file(softc_t *, char *, u_int32_t); - -static void synth_shift_bits(softc_t *, u_int32_t, u_int32_t); -static void synth_write(softc_t *, struct synth *); - -static void dac_write(softc_t *, u_int16_t); - -static void hssi_ident(softc_t *); -static void hssi_watchdog(softc_t *); -static int hssi_ioctl(softc_t *, struct ioctl *); -static void hssi_attach(softc_t *, struct config *); -static void hssi_detach(softc_t *); - -static void t3_ident(softc_t *); -static void t3_watchdog(softc_t *); -static int t3_ioctl(softc_t *, struct ioctl *); -static void t3_send_dbl_feac(softc_t *, int, int); -static void t3_attach(softc_t *, struct config *); -static void t3_detach(softc_t *); - -static void ssi_ident(softc_t *); -static void ssi_watchdog(softc_t *); -static int ssi_ioctl(softc_t *, struct ioctl *); -static void ssi_attach(softc_t *, struct config *); -static void ssi_detach(softc_t *); - -static void t1_ident(softc_t *); -static void t1_watchdog(softc_t *); -static int t1_ioctl(softc_t *, struct ioctl *); -static void t1_send_bop(softc_t *, int); -static void t1_attach(softc_t *, struct config *); -static void t1_detach(softc_t *); - - -#if SYNC_PPP -static int sync_ppp_ioctl(softc_t *, struct ifreq *, int); -static int sync_ppp_type(softc_t *, struct sk_buff *); -static int sync_ppp_mtu(softc_t *, int); -static void sync_ppp_watchdog(softc_t *); -static int sync_ppp_open(softc_t *, struct config *); -static int sync_ppp_attach(softc_t *, struct config *); -static int sync_ppp_detach(softc_t *); -#endif /* SYNC_PPP */ - -#if GEN_HDLC -static int gen_hdlc_ioctl(softc_t *, struct ifreq *, int); -static int gen_hdlc_type(softc_t *, struct sk_buff *); -static int gen_hdlc_mtu(softc_t *, int); -static void gen_hdlc_watchdog(softc_t *); -static int gen_hdlc_open(softc_t *, struct config *); -static int gen_hdlc_attach(softc_t *, struct config *); -static int gen_hdlc_detach(softc_t *); -static int gen_hdlc_card_params(struct net_device *, unsigned short, - unsigned short); -#endif /* GEN_HDLC */ - -#if P2P -static int p2p_stack_ioctl(softc_t *, u_long, void *); -static void p2p_stack_input(softc_t *, struct mbuf *); -static void p2p_stack_output(softc_t *); -static void p2p_stack_watchdog(softc_t *); -static int p2p_stack_open(softc_t *, struct config *); -static int p2p_stack_attach(softc_t *, struct config *); -static int p2p_stack_detach(softc_t *); -static int p2p_getmdm(struct p2pcom *, void *); -static int p2p_mdmctl(struct p2pcom *, int); -#endif /* P2P */ - -#if SPPP -static int sppp_stack_ioctl(softc_t *, u_long, void *); -static void sppp_stack_input(softc_t *, struct mbuf *); -static void sppp_stack_output(softc_t *); -static void sppp_stack_watchdog(softc_t *); -static int sppp_stack_open(softc_t *, struct config *); -static int sppp_stack_attach(softc_t *, struct config *); -static int sppp_stack_detach(softc_t *); -static void sppp_tls(struct sppp *); -static void sppp_tlf(struct sppp *); -#endif /* SPPP */ - -#if IFNET -static int rawip_ioctl(softc_t *, u_long, void *); -static void rawip_input(softc_t *, struct mbuf *); -static void rawip_output(softc_t *); -#elif NETDEV -static int rawip_ioctl(softc_t *, struct ifreq *, int); -static int rawip_type(softc_t *, struct sk_buff *); -static int rawip_mtu(softc_t *, int); -#endif -static void rawip_watchdog(softc_t *); -static int rawip_open(softc_t *, struct config *); -static int rawip_attach(softc_t *, struct config *); -static int rawip_detach(softc_t *); - -#if IFNET -static void ifnet_input(struct ifnet *, struct mbuf *); -static int ifnet_output(struct ifnet *, struct mbuf *, - const struct sockaddr *, const struct rtentry *); -static int ifnet_ioctl(struct ifnet *, u_long, void *); -static void ifnet_start(struct ifnet *); -static void ifnet_watchdog(struct ifnet *); - -static void ifnet_setup(struct ifnet *); -static int ifnet_attach(softc_t *); -static void ifnet_detach(softc_t *); - -static void ifmedia_setup(softc_t *); -static int lmc_ifmedia_change(struct ifnet *); -static void ifmedia_status(struct ifnet *, struct ifmediareq *); -#endif /* IFNET */ - -#if NETDEV -static int netdev_open(struct net_device *); -static int netdev_stop(struct net_device *); -static int netdev_start(struct sk_buff *, struct net_device *); -# if NAPI -static int netdev_poll(struct net_device *, int *); -# endif -static int netdev_ioctl(struct net_device *, struct ifreq *, int); -static int netdev_mtu(struct net_device *, int); -static void netdev_timeout(struct net_device *); -static struct net_device_stats *netdev_stats(struct net_device *); -static void netdev_watchdog(unsigned long); - -static void netdev_setup(struct net_device *); -static int netdev_attach(softc_t *); -static void netdev_detach(softc_t *); -#endif /* NETDEV */ - - -#if BSD -static int create_ring(softc_t *, struct desc_ring *, int); -static void destroy_ring(softc_t *, struct desc_ring *); - -static void mbuf_enqueue(struct desc_ring *, struct mbuf *); -static struct mbuf *mbuf_dequeue(struct desc_ring *); - -static int rxintr_cleanup(softc_t *); -static int rxintr_setup(softc_t *); -static int txintr_cleanup(softc_t *); -static int txintr_setup_mbuf(softc_t *, struct mbuf *); -static int txintr_setup(softc_t *); - -static intr_return_t bsd_interrupt(void *); -# if DEVICE_POLLING -static void bsd_poll(struct ifnet *, enum poll_cmd, int); -# endif -#endif /* BSD */ - -static int open_proto(softc_t *, struct config *); -static int attach_stack(softc_t *, struct config *); - -static int lmc_ioctl(softc_t *, u_long, void *); -static void lmc_watchdog(softc_t *); - -static void set_ready(softc_t *, int); -static void reset_cntrs(softc_t *); - -static void lmc_interrupt(void *, int, int); -static void check_intr_status(softc_t *); - -static int lmc_attach(softc_t *); -static void lmc_detach(softc_t *); - -static void tulip_loop(softc_t *, struct config *); -static int tulip_attach(softc_t *); -static void tulip_detach(void *); - -static void print_driver_info(void); - -static int nbsd_match(device_t, cfdata_t, void *); -static void nbsd_attach(device_t, device_t, void *); -static int nbsd_detach(device_t, int); - -#endif /* KERNEL */ - -#endif /* IF_LMC_H */ |
