summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2001-04-08 02:16:53 +0000
committerJason Wright <jason@cvs.openbsd.org>2001-04-08 02:16:53 +0000
commite031e8b2df5d3a7023255224246a4b6126e121df (patch)
tree0682f06a675a5b279858805b20bf149b1da5446b /sys/dev/pci
parentaa5fcc9a50bd4bb3dc3b888616ea2e09b24eb8de (diff)
Skeleton driver for 3c990 (mainly so aaron/theo/myself can coordinate)
- the firmware image is still under a restrictive license, so it will not be in the tree yet - driver only knows how to (correctly) upload firmware - register definitions and such are incomplete
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/if_txp.c593
-rw-r--r--sys/dev/pci/if_txpreg.h315
3 files changed, 914 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 7a7255143c9..9646dfd5542 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.100 2001/03/29 14:20:46 aaron Exp $
+# $OpenBSD: files.pci,v 1.101 2001/04/08 02:16:52 jason Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -229,6 +229,11 @@ device tl: ether, ifnet, mii, ifmedia
attach tl at pci
file dev/pci/if_tl.c tl
+# 3Com 3c990
+device txp: ether, ifnet, mii, ifmedia
+attach txp at pci
+file dev/pci/if_txp.c txp
+
# S3 SonicVibes (S3 617)
device sv: audio, auconv, mulaw
attach sv at pci
diff --git a/sys/dev/pci/if_txp.c b/sys/dev/pci/if_txp.c
new file mode 100644
index 00000000000..55a1b5b90fd
--- /dev/null
+++ b/sys/dev/pci/if_txp.c
@@ -0,0 +1,593 @@
+/* $OpenBSD: if_txp.c,v 1.1 2001/04/08 02:16:52 jason Exp $ */
+
+/*
+ * Copyright (c) 2001
+ * Jason L. Wright <jason@thought.net> and
+ * Aaron Campbell <aaron@monkey.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ */
+
+/*
+ * Driver for 3c990 (Typhoon) Ethernet ASIC
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net/if_media.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <machine/bus.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/if_txpreg.h>
+#include <dev/pci/typhoon_image.h>
+
+/* XXX not here */
+struct txp_softc {
+ struct device sc_dev;
+ void * sc_ih;
+ bus_space_handle_t sc_bh;
+ bus_space_tag_t sc_bt;
+ bus_dma_tag_t sc_dmat;
+ struct arpcom sc_arpcom;
+ struct timeout sc_tick_tmo;
+};
+
+struct txp_fw_file_header {
+ u_int8_t magicid[8];
+ u_int32_t version;
+ u_int32_t nsections;
+ u_int32_t addr;
+};
+
+struct txp_fw_section_header {
+ u_int32_t nbytes;
+ u_int16_t cksum;
+ u_int16_t reserved;
+ u_int32_t addr;
+};
+
+#define TXP_PCI_LOMEM 0x14
+#define WRITE_REG(sc,reg,val) \
+ bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, reg, val)
+#define READ_REG(sc,reg) \
+ bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, reg)
+/* end XXX not here */
+
+int txp_probe __P((struct device *, void *, void *));
+void txp_attach __P((struct device *, struct device *, void *));
+int txp_intr __P((void *));
+void txp_tick __P((void *));
+void txp_shutdown __P((void *));
+int txp_ioctl __P((struct ifnet *, u_long, caddr_t));
+void txp_start __P((struct ifnet *));
+void txp_stop __P((struct txp_softc *));
+void txp_init __P((struct txp_softc *));
+void txp_watchdog __P((struct ifnet *));
+
+int txp_chip_init __P((struct txp_softc *));
+int txp_reset_adapter __P((struct txp_softc *));
+int txp_download_fw __P((struct txp_softc *));
+int txp_download_fw_wait __P((struct txp_softc *));
+int txp_download_fw_section __P((struct txp_softc *,
+ struct txp_fw_section_header *, int));
+
+int
+txp_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3COM)
+ return (0);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_3COM_3CR990TX95:
+ case PCI_PRODUCT_3COM_3CR990TX97:
+ case PCI_PRODUCT_3COM_3CR990SVR95:
+ case PCI_PRODUCT_3COM_3CR990SVR97:
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+txp_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct txp_softc *sc = (struct txp_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ bus_size_t iosize;
+ u_int32_t command;
+
+ command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+
+ if (!(command & PCI_COMMAND_MASTER_ENABLE)) {
+ printf(": failed to enable bus mastering\n");
+ return;
+ }
+
+ if (!(command & PCI_COMMAND_MEM_ENABLE)) {
+ printf(": failed to enable memory mapping\n");
+ return;
+ }
+ if (pci_mapreg_map(pa, TXP_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_bt, &sc->sc_bh, NULL, &iosize)) {
+ printf(": can't map mem space %d\n", 0);
+ return;
+ }
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf(": couldn't map interrupt\n");
+ return;
+ }
+
+ intrstr = pci_intr_string(pc, ih);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, txp_intr, sc,
+ self->dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf(": %s", intrstr);
+
+ if (txp_chip_init(sc))
+ return;
+
+ if (txp_download_fw(sc))
+ return;
+
+ printf("\n");
+
+ ifp->if_softc = sc;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = txp_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = txp_start;
+ ifp->if_watchdog = txp_watchdog;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+
+ /*
+ * Attach us everywhere
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ shutdownhook_establish(txp_shutdown, sc);
+}
+
+int
+txp_chip_init(sc)
+ struct txp_softc *sc;
+{
+ /* disable interrupts */
+ WRITE_REG(sc, TXP_INT_ENABLE_REGISTER, 0);
+ WRITE_REG(sc, TXP_INT_MASK_REGISTER, 0x0000ffff);
+
+ /* ack all interrupts */
+ WRITE_REG(sc, TXP_INT_STATUS_REGISTER, 0xffffffff);
+
+ if (txp_reset_adapter(sc))
+ return (-1);
+
+ /* disable interrupts */
+ WRITE_REG(sc, TXP_INT_ENABLE_REGISTER, 0);
+ WRITE_REG(sc, TXP_INT_MASK_REGISTER, 0x0000ffff);
+
+ /* ack all interrupts */
+ WRITE_REG(sc, TXP_INT_STATUS_REGISTER, 0xffffffff);
+
+ return (0);
+}
+
+int
+txp_reset_adapter(sc)
+ struct txp_softc *sc;
+{
+ u_int32_t r;
+ int i;
+
+ WRITE_REG(sc, TXP_SOFT_RESET_REGISTER, 0x7f);
+ DELAY(1000);
+ WRITE_REG(sc, TXP_SOFT_RESET_REGISTER, 0);
+
+ /* Should wait max 6 seconds */
+ for (i = 0; i < 6000; i++) {
+ r = READ_REG(sc, TXP_ARM2HOST_COMM_0_REGISTER);
+ if (r == TYPHOON_WAITING_FOR_HOST_REQUEST)
+ break;
+ DELAY(1000);
+ }
+
+ if (r != TYPHOON_WAITING_FOR_HOST_REQUEST) {
+ printf(": reset hung\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+txp_download_fw(sc)
+ struct txp_softc *sc;
+{
+ struct txp_fw_file_header *fileheader;
+ struct txp_fw_section_header *secthead;
+ int sect;
+ u_int32_t r, i, ier, imr;
+
+ ier = READ_REG(sc, TXP_INT_ENABLE_REGISTER);
+ WRITE_REG(sc, TXP_INT_ENABLE_REGISTER,
+ ier | TYPHOON_INT_ARM2HOST_COMM_0);
+
+ imr = READ_REG(sc, TXP_INT_MASK_REGISTER);
+ WRITE_REG(sc, TXP_INT_MASK_REGISTER,
+ imr | TYPHOON_INT_ARM2HOST_COMM_0);
+
+ for (i = 0; i < 10000; i++) {
+ r = READ_REG(sc, TXP_ARM2HOST_COMM_0_REGISTER);
+ if (r == TYPHOON_WAITING_FOR_HOST_REQUEST)
+ break;
+ DELAY(50);
+ }
+ if (r != TYPHOON_WAITING_FOR_HOST_REQUEST) {
+ printf(": not waiting for host request\n");
+ return (-1);
+ }
+
+ /* Ack the status */
+ WRITE_REG(sc, TXP_INT_STATUS_REGISTER, TYPHOON_INT_ARM2HOST_COMM_0);
+
+ /* Tell boot firmware to get ready for image */
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_1_REGISTER, fileheader->addr);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_0_REGISTER, TYPHOON_BOOTCOMMAND_RUNTIME_IMAGE);
+
+ fileheader = (struct txp_fw_file_header *)TyphoonImage;
+ if (strncmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) {
+ printf(": fw invalid magic\n");
+ return (-1);
+ }
+
+ secthead = (struct txp_fw_section_header *)(TyphoonImage +
+ sizeof(struct txp_fw_file_header));
+
+ if (txp_download_fw_wait(sc)) {
+ printf(": fw wait failed, initial\n", sect);
+ return (-1);
+ }
+
+ for (sect = 0; sect < fileheader->nsections; sect++) {
+ if (txp_download_fw_section(sc, secthead, sect))
+ return (-1);
+ secthead = (struct txp_fw_section_header *)
+ (((u_int8_t *)secthead) + secthead->nbytes + sizeof(*secthead));
+ }
+
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_0_REGISTER,
+ TYPHOON_BOOTCOMMAND_DOWNLOAD_COMPLETE);
+
+ for (i = 0; i < 10000; i++) {
+ r = READ_REG(sc, TXP_ARM2HOST_COMM_0_REGISTER);
+ if (r == TYPHOON_WAITING_FOR_BOOT)
+ break;
+ DELAY(50);
+ }
+ if (r != TYPHOON_WAITING_FOR_BOOT) {
+ printf(": not waiting for boot\n");
+ return (-1);
+ }
+
+ WRITE_REG(sc, TXP_INT_ENABLE_REGISTER, ier);
+ WRITE_REG(sc, TXP_INT_MASK_REGISTER, imr);
+
+ return (0);
+}
+
+int
+txp_download_fw_wait(sc)
+ struct txp_softc *sc;
+{
+ u_int32_t i, r;
+
+ for (i = 0; i < 10000; i++) {
+ r = READ_REG(sc, TXP_INT_STATUS_REGISTER);
+ if (r & TYPHOON_INT_ARM2HOST_COMM_0)
+ break;
+ DELAY(50);
+ }
+
+ if (!(r & TYPHOON_INT_ARM2HOST_COMM_0)) {
+ printf(": fw wait failed comm0\n", sc->sc_dev.dv_xname);
+ return (-1);
+ }
+
+ WRITE_REG(sc, TXP_INT_STATUS_REGISTER, TYPHOON_INT_ARM2HOST_COMM_0);
+
+ r = READ_REG(sc, TXP_ARM2HOST_COMM_0_REGISTER);
+ if (r != TYPHOON_WAITING_FOR_SEGMENT) {
+ printf(": fw not waiting for segment\n", sc->sc_dev.dv_xname);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+txp_download_fw_section(sc, sect, sectnum)
+ struct txp_softc *sc;
+ struct txp_fw_section_header *sect;
+ int sectnum;
+{
+ u_int64_t pa;
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ bus_dma_segment_t seg;
+ bus_dmamap_t dmamap;
+ int rseg, err = 0;
+ caddr_t kva;
+
+ /* Skip zero length sections */
+ if (sect->nbytes == 0)
+ return (0);
+
+ /* map a buffer, copy segment to it, get physaddr */
+ if (bus_dmamem_alloc(dmat, sect->nbytes, PAGE_SIZE, 0, &seg, 1, &rseg,
+ BUS_DMA_NOWAIT)) {
+ printf(": fw dmamam alloc fail\n");
+ return (-1);
+ }
+ if (bus_dmamem_map(dmat, &seg, rseg, sect->nbytes, &kva,
+ BUS_DMA_NOWAIT)) {
+ printf(": fw dmamem map fail\n");
+ err = -1;
+ goto bail_free;
+ }
+ if (bus_dmamap_create(dmat, sect->nbytes, 1, sect->nbytes, 0,
+ BUS_DMA_NOWAIT, &dmamap)) {
+ printf(": fw dmamap create fail\n");
+ err = -1;
+ goto bail_unmap;
+ }
+ if (bus_dmamap_load(dmat, dmamap, kva, sect->nbytes, NULL,
+ BUS_DMA_NOWAIT)) {
+ printf(": fw dmamap load fail\n");
+ err = -1;
+ goto bail_destroy;
+ }
+ bcopy(((u_int8_t *)sect) + sizeof(*sect), kva, sect->nbytes);
+ bus_dmamap_sync(dmat, dmamap,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ pa = dmamap->dm_segs[0].ds_addr;
+
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_1_REGISTER, sect->nbytes);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_2_REGISTER, sect->cksum);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_3_REGISTER, sect->addr);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_4_REGISTER, pa >> 32);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_5_REGISTER, pa & 0xffffffff);
+ WRITE_REG(sc, TXP_HOST2ARM_COMM_0_REGISTER,
+ TYPHOON_BOOTCOMMAND_SEGMENT_AVAILABLE);
+
+ if (txp_download_fw_wait(sc)) {
+ printf(": fw wait failed, section %d\n", sectnum);
+ err = -1;
+ goto bail;
+ }
+
+ bus_dmamap_sync(dmat, dmamap,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+bail:
+ bus_dmamap_unload(dmat, dmamap);
+bail_destroy:
+ bus_dmamap_destroy(dmat, dmamap);
+bail_unmap:
+ bus_dmamem_unmap(dmat, kva, sect->nbytes);
+bail_free:
+ bus_dmamem_free(dmat, &seg, rseg);
+
+ return (err);
+}
+
+int
+txp_intr(vsc)
+ void *vsc;
+{
+ int claimed = 0;
+
+ return (claimed);
+}
+
+
+void
+txp_shutdown(vsc)
+ void *vsc;
+{
+ struct txp_softc *sc = (struct txp_softc *)vsc;
+
+ txp_stop(sc);
+}
+
+void
+txp_tick(vsc)
+ void *vsc;
+{
+ struct txp_softc *sc = vsc;
+
+ timeout_add(&sc->sc_tick_tmo, hz);
+}
+
+int
+txp_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct txp_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ if ((error = ether_ioctl(ifp, &sc->sc_arpcom, command, data)) > 0) {
+ splx(s);
+ return error;
+ }
+
+ switch(command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ txp_init(sc);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif /* INET */
+ default:
+ txp_init(sc);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ txp_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ txp_stop(sc);
+ }
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom) :
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly.
+ */
+ /* XXX TODO: set multicast list */
+ error = 0;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void)splx(s);
+
+ return(error);
+}
+
+void
+txp_init(sc)
+ struct txp_softc *sc;
+{
+}
+
+void
+txp_start(ifp)
+ struct ifnet *ifp;
+{
+}
+
+void
+txp_stop(sc)
+ struct txp_softc *sc;
+{
+}
+
+void
+txp_watchdog(ifp)
+ struct ifnet *ifp;
+{
+}
+
+struct cfattach txp_ca = {
+ sizeof(struct txp_softc), txp_probe, txp_attach,
+};
+
+struct cfdriver txp_cd = {
+ 0, "txp", DV_IFNET
+};
diff --git a/sys/dev/pci/if_txpreg.h b/sys/dev/pci/if_txpreg.h
new file mode 100644
index 00000000000..9e5573b773c
--- /dev/null
+++ b/sys/dev/pci/if_txpreg.h
@@ -0,0 +1,315 @@
+/* $OpenBSD: if_txpreg.h,v 1.1 2001/04/08 02:16:52 jason Exp $ */
+
+/*
+ * Copyright (c) 2001 Aaron Campbell <aaron@monkey.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Aaron Campbell.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 HIS RELATIVES 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 MIND, 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.
+ */
+
+#define TXP_INTR TXP_INT_STATUS_REGISTER
+
+/*
+ * Typhoon registers.
+ */
+#define TXP_SOFT_RESET_REGISTER 0x00
+#define TXP_INT_STATUS_REGISTER 0x04
+#define TXP_INT_ENABLE_REGISTER 0x08
+#define TXP_INT_MASK_REGISTER 0x0C
+#define TXP_SELF_INT_REGISTER 0x10
+#define TXP_HOST2ARM_COMM_7_REGISTER 0x14
+#define TXP_HOST2ARM_COMM_6_REGISTER 0x18
+#define TXP_HOST2ARM_COMM_5_REGISTER 0x1C
+#define TXP_HOST2ARM_COMM_4_REGISTER 0x20
+#define TXP_HOST2ARM_COMM_3_REGISTER 0x24
+#define TXP_HOST2ARM_COMM_2_REGISTER 0x28
+#define TXP_HOST2ARM_COMM_1_REGISTER 0x2C
+#define TXP_HOST2ARM_COMM_0_REGISTER 0x30
+#define TXP_ARM2HOST_COMM_3_REGISTER 0x34
+#define TXP_ARM2HOST_COMM_2_REGISTER 0x38
+#define TXP_ARM2HOST_COMM_1_REGISTER 0x3C
+#define TXP_ARM2HOST_COMM_0_REGISTER 0x40
+
+/*
+ * Typhoon commands.
+ */
+#define TXP_CMD_GLOBAL_RESET 0x00
+#define TXP_CMD_TX_ENABLE 0x01
+#define TXP_CMD_TX_DISABLE 0x02
+#define TXP_CMD_RX_ENABLE 0x03
+#define TXP_CMD_RX_DISABLE 0x04
+#define TXP_CMD_RX_FILTER_WRITE 0x05
+#define TXP_CMD_RX_FILTER_READ 0x06
+#define TXP_CMD_READ_STATISTICS 0x07
+#define TXP_CMD_CYCLE_STATISTICS 0x08
+#define TXP_CMD_ERROR_READ 0x09
+#define TXP_CMD_MEMORY_READ 0x0a
+#define TXP_CMD_MEMORY_WRITE_SINGLE 0x0b
+#define TXP_CMD_VARIABLE_SECTION_READ 0x0c
+#define TXP_CMD_VARIABLE_SECTION_WRITE 0x0d
+#define TXP_CMD_STATIC_SECTION_READ 0x0e
+#define TXP_CMD_STATIC_SECTION_WRITE 0x0f
+#define TXP_CMD_IMAGE_SECTION_PROGRAM 0x10
+#define TXP_CMD_NVRAM_PAGE_READ 0x11
+#define TXP_CMD_NVRAM_PAGE_WRITE 0x12
+#define TXP_CMD_XCVR_SELECT 0x13
+#define TXP_CMD_TEST_MUX 0x14
+#define TXP_CMD_PHYLOOPBACK_ENABLE 0x15
+#define TXP_CMD_PHYLOOPBACK_DISABLE 0x16
+#define TXP_CMD_MAC_CONTROL_READ 0x17
+#define TXP_CMD_MAC_CONTROL_WRITE 0x18
+#define TXP_CMD_MAX_PKT_SIZE_READ 0x19
+#define TXP_CMD_MAX_PKT_SIZE_WRITE 0x1a
+#define TXP_CMD_MEDIA_STATUS_READ 0x1b
+#define TXP_CMD_MEDIA_STATUS_WRITE 0x1c
+#define TXP_CMD_NETWORK_DIAGS_READ 0x1d
+#define TXP_CMD_NETWORK_DIAGS_WRITE 0x1e
+#define TXP_CMD_POWER_MGMT_EVENT_READ 0x1f
+#define TXP_CMD_POWER_MGMT_EVENT_WRITE 0x20
+#define TXP_CMD_VARIABLE_PARAMETER_READ 0x21
+#define TXP_CMD_VARIABLE_PARAMETER_WRITE 0x22
+#define TXP_CMD_GOTO_SLEEP 0x23
+#define TXP_CMD_FIREWALL_CONTROL 0x24
+#define TXP_CMD_MCAST_HASH_MASK_WRITE 0x25
+#define TXP_CMD_STATION_ADDRESS_WRITE 0x26
+#define TXP_CMD_STATION_ADDRESS_READ 0x27
+#define TXP_CMD_STATION_MASK_WRITE 0x28
+#define TXP_CMD_STATION_MASK_READ 0x29
+#define TXP_CMD_VLAN_ETHER_TYPE_READ 0x2a
+#define TXP_CMD_VLAN_ETHER_TYPE_WRITE 0x2b
+#define TXP_CMD_VLAN_MASK_READ 0x2c
+#define TXP_CMD_VLAN_MASK_WRITE 0x2d
+#define TXP_CMD_BCAST_THROTTLE_WRITE 0x2e
+#define TXP_CMD_BCAST_THROTTLE_READ 0x2f
+#define TXP_CMD_DHCP_PREVENT_WRITE 0x30
+#define TXP_CMD_DHCP_PREVENT_READ 0x31
+#define TXP_CMD_RECV_BUFFER_CONTROL 0x32
+#define TXP_CMD_SOFTWARE_RESET 0x33
+#define TXP_CMD_CREATE_SA 0x34
+#define TXP_CMD_DELETE_SA 0x35
+#define TXP_CMD_ENABLE_RX_IP_OPTION 0x36
+#define TXP_CMD_RANDOM_NUMBER_CONTROL 0x37
+#define TXP_CMD_RANDOM_NUMBER_READ 0x38
+#define TXP_CMD_MATRIX_TABLE_MODE_WRITE 0x39
+#define TXP_CMD_MATRIX_DETAIL_READ 0x3a
+#define TXP_CMD_FILTER_ARRAY_READ 0x3b
+#define TXP_CMD_FILTER_DETAIL_READ 0x3c
+#define TXP_CMD_FILTER_TABLE_MODE_WRITE 0x3d
+#define TXP_CMD_FILTER_TCL_WRITE 0x3e
+#define TXP_CMD_FILTER_TBL_READ 0x3f
+#define TXP_CMD_FILTER_DEFINE 0x45
+#define TXP_CMD_ADD_WAKEUP_PKT 0x46
+#define TXP_CMD_ADD_SLEEP_PKT 0x47
+#define TXP_CMD_ENABLE_SLEEP_EVENTS 0x48
+#define TXP_CMD_ENABLE_WAKEUP_EVENTS 0x49
+#define TXP_CMD_GET_IP_ADDRESS 0x4a
+#define TXP_CMD_READ_PCI_REG 0x4c
+#define TXP_CMD_WRITE_PCI_REG 0x4d
+#define TXP_CMD_OFFLOAD_WRITE 0x4f
+#define TXP_CMD_HELLO_RESPONSE 0x57
+#define TXP_CMD_ENABLE_RX_FILTER 0x58
+#define TXP_CMD_RX_FILTER_CAPABILITY 0x59
+#define TXP_CMD_HALT 0x5d
+#define TXP_CMD_INVALID 0xffff
+
+#define TXP_FRAGMENT 0x0000
+#define TXP_TXFRAME 0x0001
+#define TXP_COMMAND 0x0002
+#define TXP_OPTION 0x0003
+#define TXP_RECEIVE 0x0004
+#define TXP_RESPONSE 0x0005
+
+#define TXP_TYPE_IPSEC 0x0000
+#define TXP_TYPE_TCPSEGMENT 0x0001
+
+#define TXP_PFLAG_NOCRC 0x0000
+#define TXP_PFLAG_IPCKSUM 0x0001
+#define TXP_PFLAG_TCPCKSUM 0x0002
+#define TXP_PFLAG_TCPSEGMENT 0x0004
+#define TXP_PFLAG_INSERTVLAN 0x0008
+#define TXP_PFLAG_IPSEC 0x0010
+#define TXP_PFLAG_PRIORITY 0x0020
+#define TXP_PFLAG_UDPCKSUM 0x0040
+#define TXP_PFLAG_PADFRAME 0x0080
+
+#define TXP_MISC_FIRSTDESC 0x0000
+#define TXP_MISC_LASTDESC 0x0001
+
+#define TXP_ERR_INTERNAL 0x0000
+#define TXP_ERR_FIFOUNDERRUN 0x0001
+#define TXP_ERR_BADSSD 0x0002
+#define TXP_ERR_RUNT 0x0003
+#define TXP_ERR_CRC 0x0004
+#define TXP_ERR_OVERSIZE 0x0005
+#define TXP_ERR_ALIGNMENT 0x0006
+#define TXP_ERR_DRIBBLEBIT 0x0007
+
+#define TXP_PROTO_UNKNOWN 0x0000
+#define TXP_PROTO_IP 0x0001
+#define TXP_PROTO_IPX 0x0002
+#define TXP_PROTO_RESERVED 0x0003
+
+#define TXP_STAT_PROTO 0x0001
+#define TXP_STAT_VLAN 0x0002
+#define TXP_STAT_IPFRAGMENT 0x0004
+#define TXP_STAT_IPSEC 0x0008
+#define TXP_STAT_IPCKSUMBAD 0x0010
+#define TXP_STAT_TCPCKSUMBAD 0x0020
+#define TXP_STAT_UDPCKSUMBAD 0x0040
+#define TXP_STAT_IPCKSUMGOOD 0x0080
+#define TXP_STAT_TCPCKSUMGOOD 0x0100
+#define TXP_STAT_UDPCKSUMGOOD 0x0200
+
+struct txp_tx_desc {
+ u_int8_t tx_desctype:3,
+ tx_rsvd:5;
+
+ u_int8_t tx_num;
+ u_int16_t tx_rsvd1;
+ u_int32_t tx_addrlo;
+ u_int32_t tx_addrhi;
+
+ u_int32_t tx_proc_flags:9,
+ tx_proc_rsvd1:3,
+ tx_proc_vlanpri:16,
+ tx_proc_rsvd2:4;
+};
+
+struct txp_rx_desc {
+ u_int8_t rx_desctype:3,
+ rx_rcvtype:2,
+ rx_rsvdA:1,
+ rx_error:1,
+ rx_rsvdB:1;
+
+ u_int8_t rx_num;
+ u_int16_t rx_len;
+ u_int32_t rx_addrlo;
+ u_int32_t rx_addrhi;
+ u_int32_t rx_stat;
+ u_int16_t rx_filter;
+ u_int16_t rx_ipsechash;
+ u_int32_t rx_vlan;
+};
+
+struct txp_cmd_desc {
+ u_int8_t cmd_desctype:3,
+ cmd_rsvd:3,
+ cmd_respond:1,
+ cmd_rsvd1:1;
+
+ u_int8_t cmd_num;
+ u_int16_t cmd_id;
+ u_int16_t cmd_seq;
+ u_int16_t cmd_par1;
+ u_int32_t cmd_par2;
+ u_int32_t cmd_par3;
+};
+
+struct txp_frag_desc {
+ u_int8_t frag_desctype:3,
+ frag_rsvd:5;
+
+ u_int8_t frag_rsvd1;
+ u_int16_t frag_num;
+ u_int32_t frag_addrlo;
+ u_int32_t frag_addrhi;
+ u_int32_t frag_rsvd2;
+};
+
+struct txp_opt_desc {
+ u_int8_t opt_desctype:3,
+ opt_rsvd:1,
+ opt_type:4;
+
+ u_int8_t opt_num;
+ u_int16_t opt_dep1;
+ u_int32_t opt_dep2;
+ u_int32_t opt_dep3;
+ u_int32_t opt_dep4;
+};
+
+struct txp_ipsec_desc {
+ u_int8_t ipsec_desctpe:3,
+ ipsec_rsvd:1,
+ ipsec_type:4;
+
+ u_int8_t ipsec_num;
+ u_int16_t ipsec_flags;
+ u_int16_t ipsec_ah1;
+ u_int16_t ipsec_esp1;
+ u_int16_t ipsec_ah2;
+ u_int16_t ipsec_esp2;
+ u_int32_t ipsec_rsvd1;
+};
+
+struct txp_tcpseg_desc {
+ u_int8_t tcpseg_desctype:3,
+ tcpseg_rsvd:1,
+ tcpseg_type:4;
+
+ u_int8_t tcpseg_num;
+
+ u_int16_t tcpseg_mss:12,
+ tcpseg_misc:4;
+
+ u_int32_t tcpseg_respaddr;
+ u_int32_t tcpseg_txbytes;
+ u_int32_t tcpseg_lss;
+};
+
+struct txp_resp_desc {
+ u_int8_t resp_desctype:3,
+ resp_rsvd1:3,
+ resp_error:1,
+ resp_resv2:1;
+
+ u_int8_t resp_num;
+ u_int16_t resp_cmd;
+ u_int16_t resp_seq;
+ u_int16_t resp_par1;
+ u_int32_t resp_par2;
+ u_int32_t resp_par3;
+};
+
+
+/*
+ * TYPHOON status register state
+ */
+#define TYPHOON_WAITING_FOR_BOOT 0x00000007
+#define TYPHOON_RUNNING 0x00000009
+#define TYPHOON_WAITING_FOR_HOST_REQUEST 0x0000000D
+#define TYPHOON_WAITING_FOR_SEGMENT 0x00000010
+#define TYPHOON_SLEEPING 0x00000011
+#define TYPHOON_HALTED 0x00000014
+
+
+/* Random stuff... */
+#define TYPHOON_INT_ARM2HOST_COMM_0 0x00000002
+#define TYPHOON_BOOTCOMMAND_RUNTIME_IMAGE 0xFD
+#define TYPHOON_BOOTCOMMAND_DOWNLOAD_COMPLETE 0xFB
+#define TYPHOON_BOOTCOMMAND_SEGMENT_AVAILABLE 0xFC