summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/agp.c801
-rw-r--r--sys/pci/agp_ali.c266
-rw-r--r--sys/pci/agp_amd.c419
-rw-r--r--sys/pci/agp_i810.c478
-rw-r--r--sys/pci/agp_if.m134
-rw-r--r--sys/pci/agp_intel.c361
-rw-r--r--sys/pci/agp_sis.c258
-rw-r--r--sys/pci/agp_via.c257
-rw-r--r--sys/pci/agppriv.h105
-rw-r--r--sys/pci/agpreg.h164
-rw-r--r--sys/pci/agpvar.h126
-rw-r--r--sys/pci/alpm.c641
-rw-r--r--sys/pci/amd.c2453
-rw-r--r--sys/pci/amd.h580
-rw-r--r--sys/pci/amdpm.c640
-rw-r--r--sys/pci/cy_pci.c205
-rw-r--r--sys/pci/dc21040reg.h583
-rw-r--r--sys/pci/if_dc.c3619
-rw-r--r--sys/pci/if_dcreg.h1147
-rw-r--r--sys/pci/if_de.c5271
-rw-r--r--sys/pci/if_devar.h924
-rw-r--r--sys/pci/if_en_pci.c485
-rw-r--r--sys/pci/if_mn.c1470
-rw-r--r--sys/pci/if_pcn.c1434
-rw-r--r--sys/pci/if_pcnreg.h519
-rw-r--r--sys/pci/if_rl.c1904
-rw-r--r--sys/pci/if_rlreg.h511
-rw-r--r--sys/pci/if_sf.c1537
-rw-r--r--sys/pci/if_sfreg.h1060
-rw-r--r--sys/pci/if_sis.c2085
-rw-r--r--sys/pci/if_sisreg.h488
-rw-r--r--sys/pci/if_sk.c2218
-rw-r--r--sys/pci/if_skreg.h1223
-rw-r--r--sys/pci/if_ste.c1583
-rw-r--r--sys/pci/if_stereg.h545
-rw-r--r--sys/pci/if_ti.c3628
-rw-r--r--sys/pci/if_tireg.h1067
-rw-r--r--sys/pci/if_tl.c2335
-rw-r--r--sys/pci/if_tlreg.h596
-rw-r--r--sys/pci/if_vr.c1650
-rw-r--r--sys/pci/if_vrreg.h523
-rw-r--r--sys/pci/if_wb.c1880
-rw-r--r--sys/pci/if_wbreg.h468
-rw-r--r--sys/pci/if_xl.c3082
-rw-r--r--sys/pci/if_xlreg.h720
-rw-r--r--sys/pci/intpm.c752
-rw-r--r--sys/pci/intpmreg.h77
-rwxr-xr-xsys/pci/locate.pl45
-rw-r--r--sys/pci/meteor.c2131
-rw-r--r--sys/pci/meteor_reg.h246
-rw-r--r--sys/pci/ncr.c7163
-rw-r--r--sys/pci/ncrreg.h573
-rw-r--r--sys/pci/ohci_pci.c322
-rw-r--r--sys/pci/simos.c350
-rw-r--r--sys/pci/simos.h74
-rw-r--r--sys/pci/ti_fw.h4593
-rw-r--r--sys/pci/ti_fw2.h5232
-rw-r--r--sys/pci/uhci_pci.c407
-rw-r--r--sys/pci/viapm.c924
-rw-r--r--sys/pci/xmaciireg.h403
-rw-r--r--sys/pci/xrpu.c271
61 files changed, 76006 insertions, 0 deletions
diff --git a/sys/pci/agp.c b/sys/pci/agp.c
new file mode 100644
index 0000000..b16d1ee
--- /dev/null
+++ b/sys/pci/agp.c
@@ -0,0 +1,801 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <sys/agpio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpvar.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+MODULE_VERSION(agp, 1);
+
+MALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
+
+#define CDEV_MAJOR 148
+ /* agp_drv.c */
+static d_open_t agp_open;
+static d_close_t agp_close;
+static d_ioctl_t agp_ioctl;
+static d_mmap_t agp_mmap;
+
+static struct cdevsw agp_cdevsw = {
+ /* open */ agp_open,
+ /* close */ agp_close,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ agp_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ agp_mmap,
+ /* strategy */ nostrategy,
+ /* name */ "agp",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ D_TTY,
+};
+
+static devclass_t agp_devclass;
+#define KDEV2DEV(kdev) devclass_get_device(agp_devclass, minor(kdev))
+
+/* Helper functions for implementing chipset mini drivers. */
+
+void
+agp_flush_cache()
+{
+#ifdef __i386__
+ wbinvd();
+#endif
+}
+
+u_int8_t
+agp_find_caps(device_t dev)
+{
+ u_int32_t status;
+ u_int8_t ptr, next;
+
+ /*
+ * Check the CAP_LIST bit of the PCI status register first.
+ */
+ status = pci_read_config(dev, PCIR_STATUS, 2);
+ if (!(status & 0x10))
+ return 0;
+
+ /*
+ * Traverse the capabilities list.
+ */
+ for (ptr = pci_read_config(dev, AGP_CAPPTR, 1);
+ ptr != 0;
+ ptr = next) {
+ u_int32_t capid = pci_read_config(dev, ptr, 4);
+ next = AGP_CAPID_GET_NEXT_PTR(capid);
+
+ /*
+ * If this capability entry ID is 2, then we are done.
+ */
+ if (AGP_CAPID_GET_CAP_ID(capid) == 2)
+ return ptr;
+ }
+
+ return 0;
+}
+
+/*
+ * Find an AGP display device (if any).
+ */
+static device_t
+agp_find_display(void)
+{
+ devclass_t pci = devclass_find("pci");
+ device_t bus, dev = 0;
+ device_t *kids;
+ int busnum, numkids, i;
+
+ for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
+ bus = devclass_get_device(pci, busnum);
+ if (!bus)
+ continue;
+ device_get_children(bus, &kids, &numkids);
+ for (i = 0; i < numkids; i++) {
+ dev = kids[i];
+ if (pci_get_class(dev) == PCIC_DISPLAY
+ && pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
+ if (agp_find_caps(dev)) {
+ free(kids, M_TEMP);
+ return dev;
+ }
+
+ }
+ free(kids, M_TEMP);
+ }
+
+ return 0;
+}
+
+struct agp_gatt *
+agp_alloc_gatt(device_t dev)
+{
+ u_int32_t apsize = AGP_GET_APERTURE(dev);
+ u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
+ struct agp_gatt *gatt;
+
+ if (bootverbose)
+ device_printf(dev,
+ "allocating GATT for aperture of size %dM\n",
+ apsize / (1024*1024));
+
+ gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
+ if (!gatt)
+ return 0;
+
+ gatt->ag_entries = entries;
+ gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
+ 0, ~0, PAGE_SIZE, 0);
+ if (!gatt->ag_virtual) {
+ if (bootverbose)
+ device_printf(dev, "contiguous allocation failed\n");
+ free(gatt, M_AGP);
+ return 0;
+ }
+ bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
+ gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
+ agp_flush_cache();
+
+ return gatt;
+}
+
+void
+agp_free_gatt(struct agp_gatt *gatt)
+{
+ contigfree(gatt->ag_virtual,
+ gatt->ag_entries * sizeof(u_int32_t), M_AGP);
+ free(gatt, M_AGP);
+}
+
+static int agp_max[][2] = {
+ {0, 0},
+ {32, 4},
+ {64, 28},
+ {128, 96},
+ {256, 204},
+ {512, 440},
+ {1024, 942},
+ {2048, 1920},
+ {4096, 3932}
+};
+#define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0]))
+
+int
+agp_generic_attach(device_t dev)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ int rid, memsize, i;
+
+ /*
+ * Find and map the aperture.
+ */
+ rid = AGP_APBASE;
+ sc->as_aperture = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->as_aperture)
+ return ENOMEM;
+
+ /*
+ * Work out an upper bound for agp memory allocation. This
+ * uses a heurisitc table from the Linux driver.
+ */
+ memsize = ptoa(Maxmem) >> 20;
+ for (i = 0; i < agp_max_size; i++) {
+ if (memsize <= agp_max[i][0])
+ break;
+ }
+ if (i == agp_max_size) i = agp_max_size - 1;
+ sc->as_maxmem = agp_max[i][1] << 20U;
+
+ /*
+ * The lock is used to prevent re-entry to
+ * agp_generic_bind_memory() since that function can sleep.
+ */
+ lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0);
+
+ /*
+ * Initialise stuff for the userland device.
+ */
+ agp_devclass = devclass_find("agp");
+ TAILQ_INIT(&sc->as_memory);
+ sc->as_nextid = 1;
+
+ sc->as_devnode = make_dev(&agp_cdevsw,
+ device_get_unit(dev),
+ UID_ROOT,
+ GID_WHEEL,
+ 0600,
+ "agpgart");
+
+ return 0;
+}
+
+int
+agp_generic_detach(device_t dev)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ bus_release_resource(dev, SYS_RES_MEMORY, AGP_APBASE, sc->as_aperture);
+ lockmgr(&sc->as_lock, LK_DRAIN, 0, curthread);
+ lockdestroy(&sc->as_lock);
+ destroy_dev(sc->as_devnode);
+ agp_flush_cache();
+ return 0;
+}
+
+int
+agp_generic_enable(device_t dev, u_int32_t mode)
+{
+ device_t mdev = agp_find_display();
+ u_int32_t tstatus, mstatus;
+ u_int32_t command;
+ int rq, sba, fw, rate;;
+
+ if (!mdev) {
+ AGP_DPF("can't find display\n");
+ return ENXIO;
+ }
+
+ tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+ mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
+
+ /* Set RQ to the min of mode, tstatus and mstatus */
+ rq = AGP_MODE_GET_RQ(mode);
+ if (AGP_MODE_GET_RQ(tstatus) < rq)
+ rq = AGP_MODE_GET_RQ(tstatus);
+ if (AGP_MODE_GET_RQ(mstatus) < rq)
+ rq = AGP_MODE_GET_RQ(mstatus);
+
+ /* Set SBA if all three can deal with SBA */
+ sba = (AGP_MODE_GET_SBA(tstatus)
+ & AGP_MODE_GET_SBA(mstatus)
+ & AGP_MODE_GET_SBA(mode));
+
+ /* Similar for FW */
+ fw = (AGP_MODE_GET_FW(tstatus)
+ & AGP_MODE_GET_FW(mstatus)
+ & AGP_MODE_GET_FW(mode));
+
+ /* Figure out the max rate */
+ rate = (AGP_MODE_GET_RATE(tstatus)
+ & AGP_MODE_GET_RATE(mstatus)
+ & AGP_MODE_GET_RATE(mode));
+ if (rate & AGP_MODE_RATE_4x)
+ rate = AGP_MODE_RATE_4x;
+ else if (rate & AGP_MODE_RATE_2x)
+ rate = AGP_MODE_RATE_2x;
+ else
+ rate = AGP_MODE_RATE_1x;
+
+ /* Construct the new mode word and tell the hardware */
+ command = AGP_MODE_SET_RQ(0, rq);
+ command = AGP_MODE_SET_SBA(command, sba);
+ command = AGP_MODE_SET_FW(command, fw);
+ command = AGP_MODE_SET_RATE(command, rate);
+ command = AGP_MODE_SET_AGP(command, 1);
+ pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
+ pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
+
+ return 0;
+}
+
+struct agp_memory *
+agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ struct agp_memory *mem;
+
+ if ((size & (AGP_PAGE_SIZE - 1)) != 0)
+ return 0;
+
+ if (sc->as_allocated + size > sc->as_maxmem)
+ return 0;
+
+ if (type != 0) {
+ printf("agp_generic_alloc_memory: unsupported type %d\n",
+ type);
+ return 0;
+ }
+
+ mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
+ mem->am_id = sc->as_nextid++;
+ mem->am_size = size;
+ mem->am_type = 0;
+ mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
+ mem->am_physical = 0;
+ mem->am_offset = 0;
+ mem->am_is_bound = 0;
+ TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
+ sc->as_allocated += size;
+
+ return mem;
+}
+
+int
+agp_generic_free_memory(device_t dev, struct agp_memory *mem)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+
+ if (mem->am_is_bound)
+ return EBUSY;
+
+ sc->as_allocated -= mem->am_size;
+ TAILQ_REMOVE(&sc->as_memory, mem, am_link);
+ vm_object_deallocate(mem->am_obj);
+ free(mem, M_AGP);
+ return 0;
+}
+
+int
+agp_generic_bind_memory(device_t dev, struct agp_memory *mem,
+ vm_offset_t offset)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ vm_offset_t i, j, k;
+ vm_page_t m;
+ int error;
+
+ lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread);
+
+ if (mem->am_is_bound) {
+ device_printf(dev, "memory already bound\n");
+ return EINVAL;
+ }
+
+ if (offset < 0
+ || (offset & (AGP_PAGE_SIZE - 1)) != 0
+ || offset + mem->am_size > AGP_GET_APERTURE(dev)) {
+ device_printf(dev, "binding memory at bad offset %#x\n",
+ (int) offset);
+ return EINVAL;
+ }
+
+ /*
+ * Bind the individual pages and flush the chipset's
+ * TLB.
+ *
+ * XXX Presumably, this needs to be the pci address on alpha
+ * (i.e. use alpha_XXX_dmamap()). I don't have access to any
+ * alpha AGP hardware to check.
+ */
+ for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
+ /*
+ * Find a page from the object and wire it
+ * down. This page will be mapped using one or more
+ * entries in the GATT (assuming that PAGE_SIZE >=
+ * AGP_PAGE_SIZE. If this is the first call to bind,
+ * the pages will be allocated and zeroed.
+ */
+ m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
+ VM_ALLOC_ZERO | VM_ALLOC_RETRY);
+ AGP_DPF("found page pa=%#x\n", VM_PAGE_TO_PHYS(m));
+ vm_page_wire(m);
+
+ /*
+ * Install entries in the GATT, making sure that if
+ * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
+ * aligned to PAGE_SIZE, we don't modify too many GATT
+ * entries.
+ */
+ for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
+ j += AGP_PAGE_SIZE) {
+ vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
+ AGP_DPF("binding offset %#x to pa %#x\n",
+ offset + i + j, pa);
+ error = AGP_BIND_PAGE(dev, offset + i + j, pa);
+ if (error) {
+ /*
+ * Bail out. Reverse all the mappings
+ * and unwire the pages.
+ */
+ vm_page_wakeup(m);
+ for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
+ AGP_UNBIND_PAGE(dev, offset + k);
+ for (k = 0; k <= i; k += PAGE_SIZE) {
+ m = vm_page_lookup(mem->am_obj,
+ OFF_TO_IDX(k));
+ vm_page_unwire(m, 0);
+ }
+ lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
+ return error;
+ }
+ }
+ vm_page_wakeup(m);
+ }
+
+ /*
+ * Flush the cpu cache since we are providing a new mapping
+ * for these pages.
+ */
+ agp_flush_cache();
+
+ /*
+ * Make sure the chipset gets the new mappings.
+ */
+ AGP_FLUSH_TLB(dev);
+
+ mem->am_offset = offset;
+ mem->am_is_bound = 1;
+
+ lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
+
+ return 0;
+}
+
+int
+agp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ vm_page_t m;
+ int i;
+
+ lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread);
+
+ if (!mem->am_is_bound) {
+ device_printf(dev, "memory is not bound\n");
+ return EINVAL;
+ }
+
+
+ /*
+ * Unbind the individual pages and flush the chipset's
+ * TLB. Unwire the pages so they can be swapped.
+ */
+ for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
+ AGP_UNBIND_PAGE(dev, mem->am_offset + i);
+ for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
+ m = vm_page_lookup(mem->am_obj, atop(i));
+ vm_page_unwire(m, 0);
+ }
+
+ agp_flush_cache();
+ AGP_FLUSH_TLB(dev);
+
+ mem->am_offset = 0;
+ mem->am_is_bound = 0;
+
+ lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
+
+ return 0;
+}
+
+/* Helper functions for implementing user/kernel api */
+
+static int
+agp_acquire_helper(device_t dev, enum agp_acquire_state state)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+
+ if (sc->as_state != AGP_ACQUIRE_FREE)
+ return EBUSY;
+ sc->as_state = state;
+
+ return 0;
+}
+
+static int
+agp_release_helper(device_t dev, enum agp_acquire_state state)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+
+ if (sc->as_state == AGP_ACQUIRE_FREE)
+ return 0;
+
+ if (sc->as_state != state)
+ return EBUSY;
+
+ sc->as_state = AGP_ACQUIRE_FREE;
+ return 0;
+}
+
+static struct agp_memory *
+agp_find_memory(device_t dev, int id)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ struct agp_memory *mem;
+
+ AGP_DPF("searching for memory block %d\n", id);
+ TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
+ AGP_DPF("considering memory block %d\n", mem->am_id);
+ if (mem->am_id == id)
+ return mem;
+ }
+ return 0;
+}
+
+/* Implementation of the userland ioctl api */
+
+static int
+agp_info_user(device_t dev, agp_info *info)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+
+ bzero(info, sizeof *info);
+ info->bridge_id = pci_get_devid(dev);
+ info->agp_mode =
+ pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+ info->aper_base = rman_get_start(sc->as_aperture);
+ info->aper_size = AGP_GET_APERTURE(dev) >> 20;
+ info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
+ info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
+
+ return 0;
+}
+
+static int
+agp_setup_user(device_t dev, agp_setup *setup)
+{
+ return AGP_ENABLE(dev, setup->agp_mode);
+}
+
+static int
+agp_allocate_user(device_t dev, agp_allocate *alloc)
+{
+ struct agp_memory *mem;
+
+ mem = AGP_ALLOC_MEMORY(dev,
+ alloc->type,
+ alloc->pg_count << AGP_PAGE_SHIFT);
+ if (mem) {
+ alloc->key = mem->am_id;
+ alloc->physical = mem->am_physical;
+ return 0;
+ } else {
+ return ENOMEM;
+ }
+}
+
+static int
+agp_deallocate_user(device_t dev, int id)
+{
+ struct agp_memory *mem = agp_find_memory(dev, id);;
+
+ if (mem) {
+ AGP_FREE_MEMORY(dev, mem);
+ return 0;
+ } else {
+ return ENOENT;
+ }
+}
+
+static int
+agp_bind_user(device_t dev, agp_bind *bind)
+{
+ struct agp_memory *mem = agp_find_memory(dev, bind->key);
+
+ if (!mem)
+ return ENOENT;
+
+ return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
+}
+
+static int
+agp_unbind_user(device_t dev, agp_unbind *unbind)
+{
+ struct agp_memory *mem = agp_find_memory(dev, unbind->key);
+
+ if (!mem)
+ return ENOENT;
+
+ return AGP_UNBIND_MEMORY(dev, mem);
+}
+
+static int
+agp_open(dev_t kdev, int oflags, int devtype, struct thread *td)
+{
+ device_t dev = KDEV2DEV(kdev);
+ struct agp_softc *sc = device_get_softc(dev);
+
+ if (!sc->as_isopen) {
+ sc->as_isopen = 1;
+ device_busy(dev);
+ }
+
+ return 0;
+}
+
+static int
+agp_close(dev_t kdev, int fflag, int devtype, struct thread *td)
+{
+ device_t dev = KDEV2DEV(kdev);
+ struct agp_softc *sc = device_get_softc(dev);
+ struct agp_memory *mem;
+
+ /*
+ * Clear the GATT and force release on last close
+ */
+ while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
+ if (mem->am_is_bound)
+ AGP_UNBIND_MEMORY(dev, mem);
+ AGP_FREE_MEMORY(dev, mem);
+ }
+ if (sc->as_state == AGP_ACQUIRE_USER)
+ agp_release_helper(dev, AGP_ACQUIRE_USER);
+ sc->as_isopen = 0;
+ device_unbusy(dev);
+
+ return 0;
+}
+
+static int
+agp_ioctl(dev_t kdev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ device_t dev = KDEV2DEV(kdev);
+
+ switch (cmd) {
+ case AGPIOC_INFO:
+ return agp_info_user(dev, (agp_info *) data);
+
+ case AGPIOC_ACQUIRE:
+ return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
+
+ case AGPIOC_RELEASE:
+ return agp_release_helper(dev, AGP_ACQUIRE_USER);
+
+ case AGPIOC_SETUP:
+ return agp_setup_user(dev, (agp_setup *)data);
+
+ case AGPIOC_ALLOCATE:
+ return agp_allocate_user(dev, (agp_allocate *)data);
+
+ case AGPIOC_DEALLOCATE:
+ return agp_deallocate_user(dev, *(int *) data);
+
+ case AGPIOC_BIND:
+ return agp_bind_user(dev, (agp_bind *)data);
+
+ case AGPIOC_UNBIND:
+ return agp_unbind_user(dev, (agp_unbind *)data);
+
+ }
+
+ return EINVAL;
+}
+
+static int
+agp_mmap(dev_t kdev, vm_offset_t offset, int prot)
+{
+ device_t dev = KDEV2DEV(kdev);
+ struct agp_softc *sc = device_get_softc(dev);
+
+ if (offset > AGP_GET_APERTURE(dev))
+ return -1;
+ return atop(rman_get_start(sc->as_aperture) + offset);
+}
+
+/* Implementation of the kernel api */
+
+device_t
+agp_find_device()
+{
+ if (!agp_devclass)
+ return 0;
+ return devclass_get_device(agp_devclass, 0);
+}
+
+enum agp_acquire_state
+agp_state(device_t dev)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+ return sc->as_state;
+}
+
+void
+agp_get_info(device_t dev, struct agp_info *info)
+{
+ struct agp_softc *sc = device_get_softc(dev);
+
+ info->ai_mode =
+ pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+ info->ai_aperture_base = rman_get_start(sc->as_aperture);
+ info->ai_aperture_size = rman_get_size(sc->as_aperture);
+ info->ai_aperture_va = (vm_offset_t) rman_get_virtual(sc->as_aperture);
+ info->ai_memory_allowed = sc->as_maxmem;
+ info->ai_memory_used = sc->as_allocated;
+}
+
+int
+agp_acquire(device_t dev)
+{
+ return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
+}
+
+int
+agp_release(device_t dev)
+{
+ return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
+}
+
+int
+agp_enable(device_t dev, u_int32_t mode)
+{
+ return AGP_ENABLE(dev, mode);
+}
+
+void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
+{
+ return (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
+}
+
+void agp_free_memory(device_t dev, void *handle)
+{
+ struct agp_memory *mem = (struct agp_memory *) handle;
+ AGP_FREE_MEMORY(dev, mem);
+}
+
+int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
+{
+ struct agp_memory *mem = (struct agp_memory *) handle;
+ return AGP_BIND_MEMORY(dev, mem, offset);
+}
+
+int agp_unbind_memory(device_t dev, void *handle)
+{
+ struct agp_memory *mem = (struct agp_memory *) handle;
+ return AGP_UNBIND_MEMORY(dev, mem);
+}
+
+void agp_memory_info(device_t dev, void *handle, struct
+ agp_memory_info *mi)
+{
+ struct agp_memory *mem = (struct agp_memory *) handle;
+
+ mi->ami_size = mem->am_size;
+ mi->ami_physical = mem->am_physical;
+ mi->ami_offset = mem->am_offset;
+ mi->ami_is_bound = mem->am_is_bound;
+}
diff --git a/sys/pci/agp_ali.c b/sys/pci/agp_ali.c
new file mode 100644
index 0000000..ac281e8
--- /dev/null
+++ b/sys/pci/agp_ali.c
@@ -0,0 +1,266 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+
+struct agp_ali_softc {
+ struct agp_softc agp;
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_gatt *gatt;
+};
+
+static const char*
+agp_ali_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_BRIDGE
+ || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ if (agp_find_caps(dev) == 0)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ case 0x154110b9:
+ return ("Ali M1541 host to AGP bridge");
+ };
+
+ if (pci_get_vendor(dev) == 0x10b9)
+ return ("Ali Generic host to PCI bridge");
+
+ return NULL;
+}
+
+static int
+agp_ali_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_ali_match(dev);
+ if (desc) {
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_ali_attach(device_t dev)
+{
+ struct agp_ali_softc *sc = device_get_softc(dev);
+ struct agp_gatt *gatt;
+ int error;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ for (;;) {
+ gatt = agp_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ }
+ sc->gatt = gatt;
+
+ /* Install the gatt. */
+ pci_write_config(dev, AGP_ALI_ATTBASE,
+ (gatt->ag_physical
+ | (pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff)),
+ 4);
+
+ /* Enable the TLB. */
+ pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
+
+ return 0;
+}
+
+static int
+agp_ali_detach(device_t dev)
+{
+ struct agp_ali_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ /* Disable the TLB.. */
+ pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
+
+ /* Put the aperture back the way it started. */
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+ pci_write_config(dev, AGP_ALI_ATTBASE,
+ pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff,
+ 4);
+
+ agp_free_gatt(sc->gatt);
+ return 0;
+}
+
+#define M 1024*1024
+
+static u_int32_t agp_ali_table[] = {
+ 0, /* 0 - invalid */
+ 1, /* 1 - invalid */
+ 2, /* 2 - invalid */
+ 4*M, /* 3 - invalid */
+ 8*M, /* 4 - invalid */
+ 0, /* 5 - invalid */
+ 16*M, /* 6 - invalid */
+ 32*M, /* 7 - invalid */
+ 64*M, /* 8 - invalid */
+ 128*M, /* 9 - invalid */
+ 256*M, /* 10 - invalid */
+};
+#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
+
+static u_int32_t
+agp_ali_get_aperture(device_t dev)
+{
+ /*
+ * The aperture size is derived from the low bits of attbase.
+ * I'm not sure this is correct..
+ */
+ int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff;
+ if (i >= agp_ali_table_size)
+ return 0;
+ return agp_ali_table[i];
+}
+
+static int
+agp_ali_set_aperture(device_t dev, u_int32_t aperture)
+{
+ int i;
+
+ for (i = 0; i < agp_ali_table_size; i++)
+ if (agp_ali_table[i] == aperture)
+ break;
+ if (i == agp_ali_table_size)
+ return EINVAL;
+
+ pci_write_config(dev, AGP_ALI_ATTBASE,
+ ((pci_read_config(dev, AGP_ALI_ATTBASE, 4) & ~0xff)
+ | i), 4);
+ return 0;
+}
+
+static int
+agp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_ali_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
+ return 0;
+}
+
+static int
+agp_ali_unbind_page(device_t dev, int offset)
+{
+ struct agp_ali_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+ return 0;
+}
+
+static void
+agp_ali_flush_tlb(device_t dev)
+{
+ pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
+ pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
+}
+
+static device_method_t agp_ali_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_ali_probe),
+ DEVMETHOD(device_attach, agp_ali_attach),
+ DEVMETHOD(device_detach, agp_ali_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_ali_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_ali_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_ali_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_ali_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_ali_flush_tlb),
+ DEVMETHOD(agp_enable, agp_generic_enable),
+ DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_generic_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_ali_driver = {
+ "agp",
+ agp_ali_methods,
+ sizeof(struct agp_ali_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_ali, pci, agp_ali_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agp_amd.c b/sys/pci/agp_amd.c
new file mode 100644
index 0000000..527765d
--- /dev/null
+++ b/sys/pci/agp_amd.c
@@ -0,0 +1,419 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+MALLOC_DECLARE(M_AGP);
+
+#define READ2(off) bus_space_read_2(sc->bst, sc->bsh, off)
+#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
+#define WRITE2(off,v) bus_space_write_2(sc->bst, sc->bsh, off, v)
+#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
+
+struct agp_amd_gatt {
+ u_int32_t ag_entries;
+ u_int32_t *ag_virtual; /* virtual address of gatt */
+ vm_offset_t ag_physical;
+ u_int32_t *ag_vdir; /* virtual address of page dir */
+ vm_offset_t ag_pdir; /* physical address of page dir */
+};
+
+struct agp_amd_softc {
+ struct agp_softc agp;
+ struct resource *regs; /* memory mapped control registers */
+ bus_space_tag_t bst; /* bus_space tag */
+ bus_space_handle_t bsh; /* bus_space handle */
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_amd_gatt *gatt;
+};
+
+static struct agp_amd_gatt *
+agp_amd_alloc_gatt(device_t dev)
+{
+ u_int32_t apsize = AGP_GET_APERTURE(dev);
+ u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
+ struct agp_amd_gatt *gatt;
+ int i, npages, pdir_offset;
+
+ if (bootverbose)
+ device_printf(dev,
+ "allocating GATT for aperture of size %dM\n",
+ apsize / (1024*1024));
+
+ gatt = malloc(sizeof(struct agp_amd_gatt), M_AGP, M_NOWAIT);
+ if (!gatt)
+ return 0;
+
+ /*
+ * The AMD751 uses a page directory to map a non-contiguous
+ * gatt so we don't need to use contigmalloc.
+ * Malloc individual gatt pages and map them into the page
+ * directory.
+ */
+ gatt->ag_entries = entries;
+ gatt->ag_virtual = malloc(entries * sizeof(u_int32_t),
+ M_AGP, M_NOWAIT);
+ if (!gatt->ag_virtual) {
+ if (bootverbose)
+ device_printf(dev, "allocation failed\n");
+ free(gatt, M_AGP);
+ return 0;
+ }
+ bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
+
+ /*
+ * Allocate the page directory.
+ */
+ gatt->ag_vdir = malloc(AGP_PAGE_SIZE, M_AGP, M_NOWAIT);
+ if (!gatt->ag_vdir) {
+ if (bootverbose)
+ device_printf(dev,
+ "failed to allocate page directory\n");
+ free(gatt->ag_virtual, M_AGP);
+ free(gatt, M_AGP);
+ return 0;
+ }
+ bzero(gatt->ag_vdir, AGP_PAGE_SIZE);
+
+ gatt->ag_pdir = vtophys((vm_offset_t) gatt->ag_vdir);
+ if(bootverbose)
+ device_printf(dev, "gatt -> ag_pdir %8x\n",
+ (vm_offset_t)gatt->ag_pdir);
+ /*
+ * Allocate the gatt pages
+ */
+ gatt->ag_entries = entries;
+ if(bootverbose)
+ device_printf(dev, "allocating GATT for %d AGP page entries\n",
+ gatt->ag_entries);
+
+ gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
+
+ /*
+ * Map the pages of the GATT into the page directory.
+ *
+ * The GATT page addresses are mapped into the directory offset by
+ * an amount dependent on the base address of the aperture. This
+ * is and offset into the page directory, not an offset added to
+ * the addresses of the gatt pages.
+ */
+
+ pdir_offset = pci_read_config(dev, AGP_AMD751_APBASE, 4) >> 22;
+
+ npages = ((entries * sizeof(u_int32_t) + AGP_PAGE_SIZE - 1)
+ >> AGP_PAGE_SHIFT);
+
+ for (i = 0; i < npages; i++) {
+ vm_offset_t va;
+ vm_offset_t pa;
+
+ va = ((vm_offset_t) gatt->ag_virtual) + i * AGP_PAGE_SIZE;
+ pa = vtophys(va);
+ gatt->ag_vdir[i + pdir_offset] = pa | 1;
+ }
+
+ /*
+ * Make sure the chipset can see everything.
+ */
+ agp_flush_cache();
+
+ return gatt;
+}
+
+static void
+agp_amd_free_gatt(struct agp_amd_gatt *gatt)
+{
+ free(gatt->ag_virtual, M_AGP);
+ free(gatt->ag_vdir, M_AGP);
+ free(gatt, M_AGP);
+}
+
+static const char*
+agp_amd_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_BRIDGE
+ || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ if (agp_find_caps(dev) == 0)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+
+ case 0x700e1022:
+ return ("AMD 761 host to AGP bridge");
+
+ case 0x70061022:
+ return ("AMD 751 host to AGP bridge");
+
+ case 0x700c1022:
+ return ("AMD 762 host to AGP bridge");
+
+ };
+
+ return NULL;
+}
+
+static int
+agp_amd_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_amd_match(dev);
+ if (desc) {
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_amd_attach(device_t dev)
+{
+ struct agp_amd_softc *sc = device_get_softc(dev);
+ struct agp_amd_gatt *gatt;
+ int error, rid;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ rid = AGP_AMD751_REGISTERS;
+ sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->regs) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+
+ sc->bst = rman_get_bustag(sc->regs);
+ sc->bsh = rman_get_bushandle(sc->regs);
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ for (;;) {
+ gatt = agp_amd_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
+ return ENOMEM;
+ }
+ sc->gatt = gatt;
+
+ /* Install the gatt. */
+ WRITE4(AGP_AMD751_ATTBASE, gatt->ag_pdir);
+
+ /* Enable synchronisation between host and agp. */
+ pci_write_config(dev,
+ AGP_AMD751_MODECTRL,
+ AGP_AMD751_MODECTRL_SYNEN, 1);
+
+ /* Set indexing mode for two-level and enable page dir cache */
+ pci_write_config(dev,
+ AGP_AMD751_MODECTRL2,
+ AGP_AMD751_MODECTRL2_GPDCE, 1);
+
+ /* Enable the TLB and flush */
+ WRITE2(AGP_AMD751_STATUS,
+ READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE);
+ AGP_FLUSH_TLB(dev);
+
+ return 0;
+}
+
+static int
+agp_amd_detach(device_t dev)
+{
+ struct agp_amd_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ /* Disable the TLB.. */
+ WRITE2(AGP_AMD751_STATUS,
+ READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE);
+
+ /* Disable host-agp sync */
+ pci_write_config(dev, AGP_AMD751_MODECTRL, 0x00, 1);
+
+ /* Clear the GATT base */
+ WRITE4(AGP_AMD751_ATTBASE, 0);
+
+ /* Put the aperture back the way it started. */
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+
+ agp_amd_free_gatt(sc->gatt);
+
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ AGP_AMD751_REGISTERS, sc->regs);
+
+ return 0;
+}
+
+static u_int32_t
+agp_amd_get_aperture(device_t dev)
+{
+ int vas;
+
+ /*
+ * The aperture size is equal to 32M<<vas.
+ */
+ vas = (pci_read_config(dev, AGP_AMD751_APCTRL, 1) & 0x06) >> 1;
+ return (32*1024*1024) << vas;
+}
+
+static int
+agp_amd_set_aperture(device_t dev, u_int32_t aperture)
+{
+ int vas;
+
+ /*
+ * Check for a power of two and make sure its within the
+ * programmable range.
+ */
+ if (aperture & (aperture - 1)
+ || aperture < 32*1024*1024
+ || aperture > 2U*1024*1024*1024)
+ return EINVAL;
+
+ vas = ffs(aperture / 32*1024*1024) - 1;
+
+ /*
+ * While the size register is bits 1-3 of APCTRL, bit 0 must be
+ * set for the size value to be 'valid'
+ */
+ pci_write_config(dev, AGP_AMD751_APCTRL,
+ (((pci_read_config(dev, AGP_AMD751_APCTRL, 1) & ~0x06)
+ | ((vas << 1) | 1))), 1);
+
+ return 0;
+}
+
+static int
+agp_amd_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_amd_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
+
+ /* invalidate the cache */
+ AGP_FLUSH_TLB(dev);
+ return 0;
+}
+
+static int
+agp_amd_unbind_page(device_t dev, int offset)
+{
+ struct agp_amd_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+ return 0;
+}
+
+static void
+agp_amd_flush_tlb(device_t dev)
+{
+ struct agp_amd_softc *sc = device_get_softc(dev);
+
+ /* Set the cache invalidate bit and wait for the chipset to clear */
+ WRITE4(AGP_AMD751_TLBCTRL, 1);
+ do {
+ DELAY(1);
+ } while (READ4(AGP_AMD751_TLBCTRL));
+}
+
+static device_method_t agp_amd_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_amd_probe),
+ DEVMETHOD(device_attach, agp_amd_attach),
+ DEVMETHOD(device_detach, agp_amd_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_amd_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_amd_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_amd_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_amd_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_amd_flush_tlb),
+ DEVMETHOD(agp_enable, agp_generic_enable),
+ DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_generic_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_amd_driver = {
+ "agp",
+ agp_amd_methods,
+ sizeof(struct agp_amd_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_amd, pci, agp_amd_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agp_i810.c b/sys/pci/agp_i810.c
new file mode 100644
index 0000000..ed5f6d2
--- /dev/null
+++ b/sys/pci/agp_i810.c
@@ -0,0 +1,478 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * Copyright (c) 2000 Ruslan Ermilov
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+MALLOC_DECLARE(M_AGP);
+
+#define READ1(off) bus_space_read_1(sc->bst, sc->bsh, off)
+#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
+
+struct agp_i810_softc {
+ struct agp_softc agp;
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_gatt *gatt;
+ u_int32_t dcache_size;
+ device_t bdev; /* bridge device */
+ struct resource *regs; /* memory mapped GC registers */
+ bus_space_tag_t bst; /* bus_space tag */
+ bus_space_handle_t bsh; /* bus_space handle */
+};
+
+static const char*
+agp_i810_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_DISPLAY
+ || pci_get_subclass(dev) != PCIS_DISPLAY_VGA)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ case 0x71218086:
+ return ("Intel 82810 (i810 GMCH) SVGA controller");
+
+ case 0x71238086:
+ return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller");
+
+ case 0x71258086:
+ return ("Intel 82810E (i810E GMCH) SVGA controller");
+
+ case 0x11328086:
+ return ("Intel 82815 (i815 GMCH) SVGA controller");
+ };
+
+ return NULL;
+}
+
+/*
+ * Find bridge device.
+ */
+static device_t
+agp_i810_find_bridge(device_t dev)
+{
+ device_t *children, child;
+ int nchildren, i;
+ u_int32_t devid;
+
+ /*
+ * Calculate bridge device's ID.
+ */
+ devid = pci_get_devid(dev);
+ switch (devid) {
+ case 0x71218086:
+ case 0x71238086:
+ case 0x71258086:
+ devid -= 0x10000;
+ break;
+
+ case 0x11328086:
+ devid = 0x11308086;
+ break;
+ };
+ if (device_get_children(device_get_parent(dev), &children, &nchildren))
+ return 0;
+
+ for (i = 0; i < nchildren; i++) {
+ child = children[i];
+
+ if (pci_get_devid(child) == devid) {
+ free(children, M_TEMP);
+ return child;
+ }
+ }
+ free(children, M_TEMP);
+ return 0;
+}
+
+static int
+agp_i810_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_i810_match(dev);
+ if (desc) {
+ device_t bdev;
+ u_int8_t smram;
+
+ bdev = agp_i810_find_bridge(dev);
+ if (!bdev) {
+ if (bootverbose)
+ printf("I810: can't find bridge device\n");
+ return ENXIO;
+ }
+
+ smram = pci_read_config(bdev, AGP_I810_SMRAM, 1);
+ if ((smram & AGP_I810_SMRAM_GMS)
+ == AGP_I810_SMRAM_GMS_DISABLED) {
+ if (bootverbose)
+ printf("I810: disabled, not probing\n");
+ return ENXIO;
+ }
+
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_i810_attach(device_t dev)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ struct agp_gatt *gatt;
+ int error, rid;
+
+ sc->bdev = agp_i810_find_bridge(dev);
+ if (!sc->bdev)
+ return ENOENT;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ rid = AGP_I810_MMADR;
+ sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->regs) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ sc->bst = rman_get_bustag(sc->regs);
+ sc->bsh = rman_get_bushandle(sc->regs);
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED)
+ sc->dcache_size = 4 * 1024 * 1024;
+ else
+ sc->dcache_size = 0;
+
+ for (;;) {
+ gatt = agp_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ }
+ sc->gatt = gatt;
+
+ /* Install the GATT. */
+ WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1);
+
+ /*
+ * Make sure the chipset can see everything.
+ */
+ agp_flush_cache();
+
+ return 0;
+}
+
+static int
+agp_i810_detach(device_t dev)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ /* Clear the GATT base. */
+ WRITE4(AGP_I810_PGTBL_CTL, 0);
+
+ /* Put the aperture back the way it started. */
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+
+ agp_free_gatt(sc->gatt);
+
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ AGP_I810_MMADR, sc->regs);
+
+ return 0;
+}
+
+static u_int32_t
+agp_i810_get_aperture(device_t dev)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ u_int16_t miscc;
+
+ miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
+ if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32)
+ return 32 * 1024 * 1024;
+ else
+ return 64 * 1024 * 1024;
+}
+
+static int
+agp_i810_set_aperture(device_t dev, u_int32_t aperture)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ u_int16_t miscc;
+
+ /*
+ * Double check for sanity.
+ */
+ if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) {
+ device_printf(dev, "bad aperture size %d\n", aperture);
+ return EINVAL;
+ }
+
+ miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2);
+ miscc &= ~AGP_I810_MISCC_WINSIZE;
+ if (aperture == 32 * 1024 * 1024)
+ miscc |= AGP_I810_MISCC_WINSIZE_32;
+ else
+ miscc |= AGP_I810_MISCC_WINSIZE_64;
+
+ pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2);
+
+ return 0;
+}
+
+static int
+agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1);
+ return 0;
+}
+
+static int
+agp_i810_unbind_page(device_t dev, int offset)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0);
+ return 0;
+}
+
+/*
+ * Writing via memory mapped registers already flushes all TLBs.
+ */
+static void
+agp_i810_flush_tlb(device_t dev)
+{
+}
+
+static int
+agp_i810_enable(device_t dev, u_int32_t mode)
+{
+
+ return 0;
+}
+
+static struct agp_memory *
+agp_i810_alloc_memory(device_t dev, int type, vm_size_t size)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ struct agp_memory *mem;
+
+ if ((size & (AGP_PAGE_SIZE - 1)) != 0)
+ return 0;
+
+ if (sc->agp.as_allocated + size > sc->agp.as_maxmem)
+ return 0;
+
+ if (type == 1) {
+ /*
+ * Mapping local DRAM into GATT.
+ */
+ if (size != sc->dcache_size)
+ return 0;
+ } else if (type == 2) {
+ /*
+ * Bogus mapping of a single page for the hardware cursor.
+ */
+ if (size != AGP_PAGE_SIZE)
+ return 0;
+ }
+
+ mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
+ mem->am_id = sc->agp.as_nextid++;
+ mem->am_size = size;
+ mem->am_type = type;
+ if (type != 1)
+ mem->am_obj = vm_object_allocate(OBJT_DEFAULT,
+ atop(round_page(size)));
+ else
+ mem->am_obj = 0;
+
+ if (type == 2) {
+ /*
+ * Allocate and wire down the page now so that we can
+ * get its physical address.
+ */
+ vm_page_t m;
+ m = vm_page_grab(mem->am_obj, 0, VM_ALLOC_ZERO|VM_ALLOC_RETRY);
+ vm_page_wire(m);
+ mem->am_physical = VM_PAGE_TO_PHYS(m);
+ vm_page_wakeup(m);
+ } else {
+ mem->am_physical = 0;
+ }
+
+ mem->am_offset = 0;
+ mem->am_is_bound = 0;
+ TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link);
+ sc->agp.as_allocated += size;
+
+ return mem;
+}
+
+static int
+agp_i810_free_memory(device_t dev, struct agp_memory *mem)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+
+ if (mem->am_is_bound)
+ return EBUSY;
+
+ if (mem->am_type == 2) {
+ /*
+ * Unwire the page which we wired in alloc_memory.
+ */
+ vm_page_t m = vm_page_lookup(mem->am_obj, 0);
+ vm_page_unwire(m, 0);
+ }
+
+ sc->agp.as_allocated -= mem->am_size;
+ TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link);
+ if (mem->am_obj)
+ vm_object_deallocate(mem->am_obj);
+ free(mem, M_AGP);
+ return 0;
+}
+
+static int
+agp_i810_bind_memory(device_t dev, struct agp_memory *mem,
+ vm_offset_t offset)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ vm_offset_t i;
+
+ if (mem->am_type != 1)
+ return agp_generic_bind_memory(dev, mem, offset);
+
+ for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) {
+ WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4,
+ i | 3);
+ }
+
+ return 0;
+}
+
+static int
+agp_i810_unbind_memory(device_t dev, struct agp_memory *mem)
+{
+ struct agp_i810_softc *sc = device_get_softc(dev);
+ vm_offset_t i;
+
+ if (mem->am_type != 1)
+ return agp_generic_unbind_memory(dev, mem);
+
+ for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
+ WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0);
+
+ return 0;
+}
+
+static device_method_t agp_i810_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_i810_probe),
+ DEVMETHOD(device_attach, agp_i810_attach),
+ DEVMETHOD(device_detach, agp_i810_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_i810_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_i810_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_i810_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_i810_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_i810_flush_tlb),
+ DEVMETHOD(agp_enable, agp_i810_enable),
+ DEVMETHOD(agp_alloc_memory, agp_i810_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_i810_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_i810_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_i810_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_i810_driver = {
+ "agp",
+ agp_i810_methods,
+ sizeof(struct agp_i810_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agp_if.m b/sys/pci/agp_if.m
new file mode 100644
index 0000000..06f64d3
--- /dev/null
+++ b/sys/pci/agp_if.m
@@ -0,0 +1,134 @@
+#
+# Copyright (c) 2000 Doug Rabson
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+#
+# The AGP interface is used internally to the agp driver to isolate the
+# differences between various AGP chipsets into chipset mini drivers. It
+# should not be used outside the AGP driver. The kernel api for accessing
+# AGP functionality is described in <pci/agpvar,h>
+#
+INTERFACE agp;
+
+#
+# Return the current aperture size.
+#
+METHOD u_int32_t get_aperture {
+ device_t dev;
+};
+
+#
+# Set the size of the aperture. Return EINVAL on error or 0 on success.
+#
+METHOD int set_aperture {
+ device_t dev;
+ u_int32_t aperture;
+};
+
+#
+# Bind a single page in the AGP aperture to a given physical address.
+# The offset is a byte offset within the aperture which must be
+# aligned to an AGP page boundary.
+#
+METHOD int bind_page {
+ device_t dev;
+ vm_offset_t offset;
+ vm_offset_t physical;
+};
+
+#
+# Unbind a single page in the AGP aperture.
+#
+METHOD int unbind_page {
+ device_t dev;
+ vm_offset_t offset;
+};
+
+#
+# Flush the GATT TLB. This is used after a call to bind_page to
+# ensure that any mappings cached in the chipset are discarded.
+#
+METHOD void flush_tlb {
+ device_t dev;
+};
+
+#
+# Enable the agp hardware with the relavent mode. The mode bits are
+# defined in <pci/agpreg.h>
+#
+METHOD int enable {
+ device_t dev;
+ u_int32_t mode;
+};
+
+#
+# Allocate memory of a given type. The type is a chipset-specific
+# code which is used by certain integrated agp graphics chips
+# (basically just the i810 for now) to access special features of
+# the chipset. An opaque handle representing the memory region is
+# returned and can be used as an argument to free_memory, bind_memory
+# and unbind_memory.
+#
+# The size is specified in bytes but must be a multiple of the AGP
+# page size.
+#
+METHOD struct agp_memory * alloc_memory {
+ device_t dev;
+ int type;
+ vm_size_t size;
+};
+
+#
+# Free a memory region previously allocated with alloc_memory. Return
+# EBUSY if the memory is bound.
+#
+METHOD int free_memory {
+ device_t dev;
+ struct agp_memory *mem;
+};
+
+#
+# Bind a memory region to a specific byte offset within the chipset's
+# AGP aperture. This effectively defines a range of contiguous
+# physical address which alias the (possibly uncontiguous) pages in
+# the memory region.
+#
+METHOD int bind_memory {
+ device_t dev;
+ struct agp_memory *mem;
+ vm_offset_t offset;
+};
+
+#
+# Unbind a memory region bound with bind_memory.
+#
+METHOD int unbind_memory {
+ device_t dev;
+ struct agp_memory *handle;
+};
diff --git a/sys/pci/agp_intel.c b/sys/pci/agp_intel.c
new file mode 100644
index 0000000..165409d
--- /dev/null
+++ b/sys/pci/agp_intel.c
@@ -0,0 +1,361 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+
+struct agp_intel_softc {
+ struct agp_softc agp;
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_gatt *gatt;
+};
+
+static const char*
+agp_intel_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_BRIDGE
+ || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ if (agp_find_caps(dev) == 0)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ /* Intel -- vendor 0x8086 */
+ case 0x71808086:
+ return ("Intel 82443LX (440 LX) host to PCI bridge");
+
+ case 0x71908086:
+ return ("Intel 82443BX (440 BX) host to PCI bridge");
+
+ case 0x71a08086:
+ return ("Intel 82443GX host to PCI bridge");
+
+ case 0x71a18086:
+ return ("Intel 82443GX host to AGP bridge");
+
+ case 0x11308086:
+ return ("Intel 82815 (i815 GMCH) host to PCI bridge");
+
+ case 0x25008086:
+ return ("Intel 82820 host to AGP bridge");
+
+ case 0x35758086:
+ return ("Intel 82830 host to AGP bridge");
+
+ case 0x1a218086:
+ return ("Intel 82840 host to AGP bridge");
+
+ case 0x1a308086:
+ return ("Intel 82845 host to AGP bridge");
+
+ case 0x25308086:
+ return ("Intel 82850 host to AGP bridge");
+
+ case 0x25318086:
+ return ("Intel 82860 host to AGP bridge");
+ };
+
+ if (pci_get_vendor(dev) == 0x8086)
+ return ("Intel Generic host to PCI bridge");
+
+ return NULL;
+}
+
+static int
+agp_intel_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_intel_match(dev);
+ if (desc) {
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_intel_attach(device_t dev)
+{
+ struct agp_intel_softc *sc = device_get_softc(dev);
+ struct agp_gatt *gatt;
+ u_int32_t type = pci_get_devid(dev);
+ int error;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ for (;;) {
+ gatt = agp_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ }
+ sc->gatt = gatt;
+
+ /* Install the gatt. */
+ pci_write_config(dev, AGP_INTEL_ATTBASE, gatt->ag_physical, 4);
+
+ /* Enable things, clear errors etc. */
+ switch (type) {
+ case 0x1a218086: /* i840 */
+ case 0x25308086: /* i850 */
+ case 0x25318086: /* i860 */
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x0000, 4);
+ pci_write_config(dev, AGP_INTEL_MCHCFG,
+ (pci_read_config(dev, AGP_INTEL_MCHCFG, 2)
+ | (1 << 9)), 2);
+ break;
+
+ case 0x25008086: /* i820 */
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x0000, 4);
+ pci_write_config(dev, AGP_INTEL_I820_RDCR,
+ (pci_read_config(dev, AGP_INTEL_I820_RDCR, 1)
+ | (1 << 1)), 1);
+ break;
+
+ case 0x1a308086: /* i845 */
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x0000, 4);
+ pci_write_config(dev, AGP_INTEL_I845_MCHCFG,
+ (pci_read_config(dev, AGP_INTEL_I845_MCHCFG, 1)
+ | (1 << 1)), 1);
+ break;
+
+ default: /* Intel Generic (maybe) */
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
+ pci_write_config(dev, AGP_INTEL_NBXCFG,
+ (pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
+ & ~(1 << 10)) | (1 << 9), 4);
+ }
+
+ switch (type) {
+ case 0x1a218086: /* i840 */
+ pci_write_config(dev, AGP_INTEL_I8XX_ERRSTS, 0xc000, 2);
+ break;
+
+ case 0x25008086: /* i820 */
+ case 0x1a308086: /* i845 */
+ case 0x25308086: /* i850 */
+ case 0x25318086: /* i860 */
+ pci_write_config(dev, AGP_INTEL_I8XX_ERRSTS, 0x001c, 2);
+ break;
+
+ default: /* Intel Generic (maybe) */
+ pci_write_config(dev, AGP_INTEL_ERRSTS + 1, 7, 1);
+ }
+
+ return 0;
+}
+
+static int
+agp_intel_detach(device_t dev)
+{
+ struct agp_intel_softc *sc = device_get_softc(dev);
+ u_int32_t type = pci_get_devid(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ switch (type) {
+ case 0x1a218086: /* i840 */
+ case 0x25308086: /* i850 */
+ case 0x25318086: /* i860 */
+ printf("%s: set MCHCFG to %x\n", __func__, (unsigned)
+ (pci_read_config(dev, AGP_INTEL_MCHCFG, 2)
+ & ~(1 << 9)));
+ pci_write_config(dev, AGP_INTEL_MCHCFG,
+ (pci_read_config(dev, AGP_INTEL_MCHCFG, 2)
+ & ~(1 << 9)), 2);
+
+ case 0x25008086: /* i820 */
+ printf("%s: set RDCR to %x\n", __func__, (unsigned)
+ (pci_read_config(dev, AGP_INTEL_I820_RDCR, 1)
+ & ~(1 << 1)));
+ pci_write_config(dev, AGP_INTEL_I820_RDCR,
+ (pci_read_config(dev, AGP_INTEL_I820_RDCR, 1)
+ & ~(1 << 1)), 1);
+
+ case 0x1a308086: /* i845 */
+ printf("%s: set MCHCFG to %x\n", __func__, (unsigned)
+ (pci_read_config(dev, AGP_INTEL_I845_MCHCFG, 1)
+ & ~(1 << 1)));
+ pci_write_config(dev, AGP_INTEL_MCHCFG,
+ (pci_read_config(dev, AGP_INTEL_I845_MCHCFG, 1)
+ & ~(1 << 1)), 1);
+
+ default: /* Intel Generic (maybe) */
+ printf("%s: set NBXCFG to %x\n", __func__,
+ (pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
+ & ~(1 << 9)));
+ pci_write_config(dev, AGP_INTEL_NBXCFG,
+ (pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
+ & ~(1 << 9)), 4);
+ }
+ pci_write_config(dev, AGP_INTEL_ATTBASE, 0, 4);
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+ agp_free_gatt(sc->gatt);
+
+ return 0;
+}
+
+static u_int32_t
+agp_intel_get_aperture(device_t dev)
+{
+ u_int32_t apsize;
+
+ apsize = pci_read_config(dev, AGP_INTEL_APSIZE, 1) & 0x1f;
+
+ /*
+ * The size is determined by the number of low bits of
+ * register APBASE which are forced to zero. The low 22 bits
+ * are always forced to zero and each zero bit in the apsize
+ * field just read forces the corresponding bit in the 27:22
+ * to be zero. We calculate the aperture size accordingly.
+ */
+ return (((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1;
+}
+
+static int
+agp_intel_set_aperture(device_t dev, u_int32_t aperture)
+{
+ u_int32_t apsize;
+
+ /*
+ * Reverse the magic from get_aperture.
+ */
+ apsize = ((aperture - 1) >> 22) ^ 0x1f;
+
+ /*
+ * Double check for sanity.
+ */
+ if ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1 != aperture)
+ return EINVAL;
+
+ pci_write_config(dev, AGP_INTEL_APSIZE, apsize, 1);
+
+ return 0;
+}
+
+static int
+agp_intel_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_intel_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
+ return 0;
+}
+
+static int
+agp_intel_unbind_page(device_t dev, int offset)
+{
+ struct agp_intel_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+ return 0;
+}
+
+static void
+agp_intel_flush_tlb(device_t dev)
+{
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2200, 4);
+ pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
+}
+
+static device_method_t agp_intel_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_intel_probe),
+ DEVMETHOD(device_attach, agp_intel_attach),
+ DEVMETHOD(device_detach, agp_intel_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_intel_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_intel_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_intel_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_intel_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_intel_flush_tlb),
+ DEVMETHOD(agp_enable, agp_generic_enable),
+ DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_generic_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_intel_driver = {
+ "agp",
+ agp_intel_methods,
+ sizeof(struct agp_intel_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_intel, pci, agp_intel_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agp_sis.c b/sys/pci/agp_sis.c
new file mode 100644
index 0000000..adc258f
--- /dev/null
+++ b/sys/pci/agp_sis.c
@@ -0,0 +1,258 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+
+struct agp_sis_softc {
+ struct agp_softc agp;
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_gatt *gatt;
+};
+
+static const char*
+agp_sis_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_BRIDGE
+ || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ if (agp_find_caps(dev) == 0)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ case 0x00011039:
+ return ("SiS 5591 host to AGP bridge");
+ };
+
+ if (pci_get_vendor(dev) == 0x1039)
+ return ("SIS Generic host to PCI bridge");
+
+ return NULL;
+}
+
+static int
+agp_sis_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_sis_match(dev);
+ if (desc) {
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_sis_attach(device_t dev)
+{
+ struct agp_sis_softc *sc = device_get_softc(dev);
+ struct agp_gatt *gatt;
+ int error;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ for (;;) {
+ gatt = agp_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ }
+ sc->gatt = gatt;
+
+ /* Install the gatt. */
+ pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4);
+
+ /* Enable the aperture. */
+ pci_write_config(dev, AGP_SIS_WINCTRL,
+ pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1);
+
+ /*
+ * Enable the TLB and make it automatically invalidate entries
+ * when the GATT is written.
+ */
+ pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1);
+
+ return 0;
+}
+
+static int
+agp_sis_detach(device_t dev)
+{
+ struct agp_sis_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ /* Disable the aperture.. */
+ pci_write_config(dev, AGP_SIS_WINCTRL,
+ pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1);
+
+ /* and the TLB. */
+ pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1);
+
+ /* Put the aperture back the way it started. */
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+
+ agp_free_gatt(sc->gatt);
+ return 0;
+}
+
+static u_int32_t
+agp_sis_get_aperture(device_t dev)
+{
+ int gws;
+
+ /*
+ * The aperture size is equal to 4M<<gws.
+ */
+ gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4;
+ return (4*1024*1024) << gws;
+}
+
+static int
+agp_sis_set_aperture(device_t dev, u_int32_t aperture)
+{
+ int gws;
+
+ /*
+ * Check for a power of two and make sure its within the
+ * programmable range.
+ */
+ if (aperture & (aperture - 1)
+ || aperture < 4*1024*1024
+ || aperture > 256*1024*1024)
+ return EINVAL;
+
+ gws = ffs(aperture / 4*1024*1024) - 1;
+
+ pci_write_config(dev, AGP_SIS_WINCTRL,
+ ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70)
+ | gws << 4), 1);
+
+ return 0;
+}
+
+static int
+agp_sis_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_sis_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
+ return 0;
+}
+
+static int
+agp_sis_unbind_page(device_t dev, int offset)
+{
+ struct agp_sis_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+ return 0;
+}
+
+static void
+agp_sis_flush_tlb(device_t dev)
+{
+ pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1);
+}
+
+static device_method_t agp_sis_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_sis_probe),
+ DEVMETHOD(device_attach, agp_sis_attach),
+ DEVMETHOD(device_detach, agp_sis_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_sis_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_sis_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_sis_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_sis_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb),
+ DEVMETHOD(agp_enable, agp_generic_enable),
+ DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_generic_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_sis_driver = {
+ "agp",
+ agp_sis_methods,
+ sizeof(struct agp_sis_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_sis, pci, agp_sis_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agp_via.c b/sys/pci/agp_via.c
new file mode 100644
index 0000000..3651cf2
--- /dev/null
+++ b/sys/pci/agp_via.c
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_bus.h"
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+
+struct agp_via_softc {
+ struct agp_softc agp;
+ u_int32_t initial_aperture; /* aperture size at startup */
+ struct agp_gatt *gatt;
+};
+
+static const char*
+agp_via_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_BRIDGE
+ || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ if (agp_find_caps(dev) == 0)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ case 0x05011106:
+ return ("VIA 8501 (Apollo MVP4) host to PCI bridge");
+ case 0x05971106:
+ return ("VIA 82C597 (Apollo VP3) host to PCI bridge");
+ case 0x05981106:
+ return ("VIA 82C598 (Apollo MVP3) host to PCI bridge");
+ case 0x06911106:
+ return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
+ case 0x03051106:
+ return ("VIA 82C8363 (Apollo KT133A) host to PCI bridge");
+ };
+
+ if (pci_get_vendor(dev) == 0x1106)
+ return ("VIA Generic host to PCI bridge");
+
+ return NULL;
+}
+
+static int
+agp_via_probe(device_t dev)
+{
+ const char *desc;
+
+ desc = agp_via_match(dev);
+ if (desc) {
+ device_verbose(dev);
+ device_set_desc(dev, desc);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+agp_via_attach(device_t dev)
+{
+ struct agp_via_softc *sc = device_get_softc(dev);
+ struct agp_gatt *gatt;
+ int error;
+
+ error = agp_generic_attach(dev);
+ if (error)
+ return error;
+
+ sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+ for (;;) {
+ gatt = agp_alloc_gatt(dev);
+ if (gatt)
+ break;
+
+ /*
+ * Probably contigmalloc failure. Try reducing the
+ * aperture so that the gatt size reduces.
+ */
+ if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+ agp_generic_detach(dev);
+ return ENOMEM;
+ }
+ }
+ sc->gatt = gatt;
+
+ /* Install the gatt. */
+ pci_write_config(dev, AGP_VIA_ATTBASE, gatt->ag_physical | 3, 4);
+
+ /* Enable the aperture. */
+ pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
+
+ return 0;
+}
+
+static int
+agp_via_detach(device_t dev)
+{
+ struct agp_via_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = agp_generic_detach(dev);
+ if (error)
+ return error;
+
+ pci_write_config(dev, AGP_VIA_GARTCTRL, 0, 4);
+ pci_write_config(dev, AGP_VIA_ATTBASE, 0, 4);
+ AGP_SET_APERTURE(dev, sc->initial_aperture);
+ agp_free_gatt(sc->gatt);
+
+ return 0;
+}
+
+static u_int32_t
+agp_via_get_aperture(device_t dev)
+{
+ u_int32_t apsize;
+
+ apsize = pci_read_config(dev, AGP_VIA_APSIZE, 1) & 0x1f;
+
+ /*
+ * The size is determined by the number of low bits of
+ * register APBASE which are forced to zero. The low 20 bits
+ * are always forced to zero and each zero bit in the apsize
+ * field just read forces the corresponding bit in the 27:20
+ * to be zero. We calculate the aperture size accordingly.
+ */
+ return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1;
+}
+
+static int
+agp_via_set_aperture(device_t dev, u_int32_t aperture)
+{
+ u_int32_t apsize;
+
+ /*
+ * Reverse the magic from get_aperture.
+ */
+ apsize = ((aperture - 1) >> 20) ^ 0xff;
+
+ /*
+ * Double check for sanity.
+ */
+ if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
+ return EINVAL;
+
+ pci_write_config(dev, AGP_VIA_APSIZE, apsize, 1);
+
+ return 0;
+}
+
+static int
+agp_via_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+ struct agp_via_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
+ return 0;
+}
+
+static int
+agp_via_unbind_page(device_t dev, int offset)
+{
+ struct agp_via_softc *sc = device_get_softc(dev);
+
+ if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return EINVAL;
+
+ sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+ return 0;
+}
+
+static void
+agp_via_flush_tlb(device_t dev)
+{
+ pci_write_config(dev, AGP_VIA_GARTCTRL, 0x8f, 4);
+ pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
+}
+
+static device_method_t agp_via_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, agp_via_probe),
+ DEVMETHOD(device_attach, agp_via_attach),
+ DEVMETHOD(device_detach, agp_via_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* AGP interface */
+ DEVMETHOD(agp_get_aperture, agp_via_get_aperture),
+ DEVMETHOD(agp_set_aperture, agp_via_set_aperture),
+ DEVMETHOD(agp_bind_page, agp_via_bind_page),
+ DEVMETHOD(agp_unbind_page, agp_via_unbind_page),
+ DEVMETHOD(agp_flush_tlb, agp_via_flush_tlb),
+ DEVMETHOD(agp_enable, agp_generic_enable),
+ DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
+ DEVMETHOD(agp_free_memory, agp_generic_free_memory),
+ DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
+ DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
+
+ { 0, 0 }
+};
+
+static driver_t agp_via_driver = {
+ "agp",
+ agp_via_methods,
+ sizeof(struct agp_via_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_via, pci, agp_via_driver, agp_devclass, 0, 0);
diff --git a/sys/pci/agppriv.h b/sys/pci/agppriv.h
new file mode 100644
index 0000000..1c5f022
--- /dev/null
+++ b/sys/pci/agppriv.h
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PCI_AGPPRIV_H_
+#define _PCI_AGPPRIV_H_
+
+/*
+ * This file *must not* be included by code outside the agp driver itself.
+ */
+
+#include <sys/agpio.h>
+#include <pci/agpvar.h>
+
+#define AGP_DEBUGxx
+
+#ifdef AGP_DEBUG
+#define AGP_DPF(x...) do { \
+ printf("agp: "); \
+ printf(##x); \
+} while (0)
+#else
+#define AGP_DPF(x...) do {} while (0)
+#endif
+
+#include "agp_if.h"
+
+/*
+ * Data structure to describe an AGP memory allocation.
+ */
+TAILQ_HEAD(agp_memory_list, agp_memory);
+struct agp_memory {
+ TAILQ_ENTRY(agp_memory) am_link; /* wiring for the tailq */
+ int am_id; /* unique id for block */
+ vm_size_t am_size; /* number of bytes allocated */
+ int am_type; /* chipset specific type */
+ struct vm_object *am_obj; /* VM object owning pages */
+ vm_offset_t am_physical; /* bogus hack for i810 */
+ vm_offset_t am_offset; /* page offset if bound */
+ int am_is_bound; /* non-zero if bound */
+};
+
+/*
+ * All chipset drivers must have this at the start of their softc.
+ */
+struct agp_softc {
+ struct resource *as_aperture; /* location of aperture */
+ u_int32_t as_maxmem; /* allocation upper bound */
+ u_int32_t as_allocated; /* amount allocated */
+ enum agp_acquire_state as_state;
+ struct agp_memory_list as_memory; /* list of allocated memory */
+ int as_nextid; /* next memory block id */
+ int as_isopen; /* user device is open */
+ dev_t as_devnode; /* from make_dev */
+ struct lock as_lock; /* lock for access to GATT */
+};
+
+struct agp_gatt {
+ u_int32_t ag_entries;
+ u_int32_t *ag_virtual;
+ vm_offset_t ag_physical;
+};
+
+void agp_flush_cache(void);
+u_int8_t agp_find_caps(device_t dev);
+struct agp_gatt *agp_alloc_gatt(device_t dev);
+void agp_free_gatt(struct agp_gatt *gatt);
+int agp_generic_attach(device_t dev);
+int agp_generic_detach(device_t dev);
+int agp_generic_enable(device_t dev, u_int32_t mode);
+struct agp_memory *agp_generic_alloc_memory(device_t dev, int type,
+ vm_size_t size);
+int agp_generic_free_memory(device_t dev,
+ struct agp_memory *mem);
+int agp_generic_bind_memory(device_t dev,
+ struct agp_memory *mem,
+ vm_offset_t offset);
+int agp_generic_unbind_memory(device_t dev,
+ struct agp_memory *mem);
+
+#endif /* !_PCI_AGPPRIV_H_ */
diff --git a/sys/pci/agpreg.h b/sys/pci/agpreg.h
new file mode 100644
index 0000000..13f08e3
--- /dev/null
+++ b/sys/pci/agpreg.h
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PCI_AGPREG_H_
+#define _PCI_AGPREG_H_
+
+/*
+ * Offsets for various AGP configuration registers.
+ */
+#define AGP_APBASE 0x10
+#define AGP_CAPPTR 0x34
+
+/*
+ * Offsets from the AGP Capability pointer.
+ */
+#define AGP_CAPID 0x0
+#define AGP_CAPID_GET_MAJOR(x) (((x) & 0x00f00000U) >> 20)
+#define AGP_CAPID_GET_MINOR(x) (((x) & 0x000f0000U) >> 16)
+#define AGP_CAPID_GET_NEXT_PTR(x) (((x) & 0x0000ff00U) >> 8)
+#define AGP_CAPID_GET_CAP_ID(x) (((x) & 0x000000ffU) >> 0)
+
+#define AGP_STATUS 0x4
+#define AGP_COMMAND 0x8
+
+/*
+ * Config offsets for Intel AGP chipsets.
+ */
+#define AGP_INTEL_NBXCFG 0x50
+#define AGP_INTEL_ERRSTS 0x91
+#define AGP_INTEL_AGPCTRL 0xb0
+#define AGP_INTEL_APSIZE 0xb4
+#define AGP_INTEL_ATTBASE 0xb8
+
+/*
+ * Config offsets for Intel i820/i840/i845/i850/i860 AGP chipsets.
+ */
+#define AGP_INTEL_MCHCFG 0x50
+#define AGP_INTEL_I820_RDCR 0x51
+#define AGP_INTEL_I845_MCHCFG 0x51
+#define AGP_INTEL_I8XX_ERRSTS 0xc8
+
+/*
+ * Config offsets for VIA AGP chipsets.
+ */
+#define AGP_VIA_GARTCTRL 0x80
+#define AGP_VIA_APSIZE 0x84
+#define AGP_VIA_ATTBASE 0x88
+
+/*
+ * Config offsets for SiS AGP chipsets.
+ */
+#define AGP_SIS_ATTBASE 0x90
+#define AGP_SIS_WINCTRL 0x94
+#define AGP_SIS_TLBCTRL 0x97
+#define AGP_SIS_TLBFLUSH 0x98
+
+/*
+ * Config offsets for Ali AGP chipsets.
+ */
+#define AGP_ALI_AGPCTRL 0xb8
+#define AGP_ALI_ATTBASE 0xbc
+#define AGP_ALI_TLBCTRL 0xc0
+
+/*
+ * Config offsets for the AMD 751 chipset.
+ */
+#define AGP_AMD751_APBASE 0x10
+#define AGP_AMD751_REGISTERS 0x14
+#define AGP_AMD751_APCTRL 0xac
+#define AGP_AMD751_MODECTRL 0xb0
+#define AGP_AMD751_MODECTRL_SYNEN 0x80
+#define AGP_AMD751_MODECTRL2 0xb2
+#define AGP_AMD751_MODECTRL2_G1LM 0x01
+#define AGP_AMD751_MODECTRL2_GPDCE 0x02
+#define AGP_AMD751_MODECTRL2_NGSE 0x08
+
+/*
+ * Memory mapped register offsets for AMD 751 chipset.
+ */
+#define AGP_AMD751_CAPS 0x00
+#define AGP_AMD751_CAPS_EHI 0x0800
+#define AGP_AMD751_CAPS_P2P 0x0400
+#define AGP_AMD751_CAPS_MPC 0x0200
+#define AGP_AMD751_CAPS_VBE 0x0100
+#define AGP_AMD751_CAPS_REV 0x00ff
+#define AGP_AMD751_STATUS 0x02
+#define AGP_AMD751_STATUS_P2PS 0x0800
+#define AGP_AMD751_STATUS_GCS 0x0400
+#define AGP_AMD751_STATUS_MPS 0x0200
+#define AGP_AMD751_STATUS_VBES 0x0100
+#define AGP_AMD751_STATUS_P2PE 0x0008
+#define AGP_AMD751_STATUS_GCE 0x0004
+#define AGP_AMD751_STATUS_VBEE 0x0001
+#define AGP_AMD751_ATTBASE 0x04
+#define AGP_AMD751_TLBCTRL 0x0c
+
+/*
+ * Config registers for i810 device 0
+ */
+#define AGP_I810_SMRAM 0x70
+#define AGP_I810_SMRAM_GMS 0xc0
+#define AGP_I810_SMRAM_GMS_DISABLED 0x00
+#define AGP_I810_SMRAM_GMS_ENABLED_0 0x40
+#define AGP_I810_SMRAM_GMS_ENABLED_512 0x80
+#define AGP_I810_SMRAM_GMS_ENABLED_1024 0xc0
+#define AGP_I810_MISCC 0x72
+#define AGP_I810_MISCC_WINSIZE 0x0001
+#define AGP_I810_MISCC_WINSIZE_64 0x0000
+#define AGP_I810_MISCC_WINSIZE_32 0x0001
+#define AGP_I810_MISCC_PLCK 0x0008
+#define AGP_I810_MISCC_PLCK_UNLOCKED 0x0000
+#define AGP_I810_MISCC_PLCK_LOCKED 0x0008
+#define AGP_I810_MISCC_WPTC 0x0030
+#define AGP_I810_MISCC_WPTC_NOLIMIT 0x0000
+#define AGP_I810_MISCC_WPTC_62 0x0010
+#define AGP_I810_MISCC_WPTC_50 0x0020
+#define AGP_I810_MISCC_WPTC_37 0x0030
+#define AGP_I810_MISCC_RPTC 0x00c0
+#define AGP_I810_MISCC_RPTC_NOLIMIT 0x0000
+#define AGP_I810_MISCC_RPTC_62 0x0040
+#define AGP_I810_MISCC_RPTC_50 0x0080
+#define AGP_I810_MISCC_RPTC_37 0x00c0
+
+/*
+ * Config registers for i810 device 1
+ */
+#define AGP_I810_GMADR 0x10
+#define AGP_I810_MMADR 0x14
+
+/*
+ * Memory mapped register offsets for i810 chipset.
+ */
+#define AGP_I810_PGTBL_CTL 0x2020
+#define AGP_I810_DRT 0x3000
+#define AGP_I810_DRT_UNPOPULATED 0x00
+#define AGP_I810_DRT_POPULATED 0x01
+#define AGP_I810_GTT 0x10000
+
+#endif /* !_PCI_AGPREG_H_ */
diff --git a/sys/pci/agpvar.h b/sys/pci/agpvar.h
new file mode 100644
index 0000000..0869c26
--- /dev/null
+++ b/sys/pci/agpvar.h
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PCI_AGPVAR_H_
+#define _PCI_AGPVAR_H_
+
+/*
+ * The AGP chipset can be acquired by user or kernel code. If the
+ * chipset has already been acquired, it cannot be acquired by another
+ * user until the previous user has released it.
+ */
+enum agp_acquire_state {
+ AGP_ACQUIRE_FREE,
+ AGP_ACQUIRE_USER,
+ AGP_ACQUIRE_KERNEL
+};
+
+/*
+ * This structure is used to query the state of the AGP system.
+ */
+struct agp_info {
+ u_int32_t ai_mode;
+ vm_offset_t ai_aperture_base;
+ vm_size_t ai_aperture_size;
+ vm_offset_t ai_aperture_va;
+ vm_size_t ai_memory_allowed;
+ vm_size_t ai_memory_used;
+ u_int32_t ai_devid;
+};
+
+struct agp_memory_info {
+ vm_size_t ami_size; /* size in bytes */
+ vm_offset_t ami_physical; /* bogus hack for i810 */
+ vm_offset_t ami_offset; /* page offset if bound */
+ int ami_is_bound; /* non-zero if bound */
+};
+
+/*
+ * Find the AGP device and return it.
+ */
+device_t agp_find_device(void);
+
+/*
+ * Return the current owner of the AGP chipset.
+ */
+enum agp_acquire_state agp_state(device_t dev);
+
+/*
+ * Query the state of the AGP system.
+ */
+void agp_get_info(device_t dev, struct agp_info *info);
+
+/*
+ * Acquire the AGP chipset for use by the kernel. Returns EBUSY if the
+ * AGP chipset is already acquired by another user.
+ */
+int agp_acquire(device_t dev);
+
+/*
+ * Release the AGP chipset.
+ */
+int agp_release(device_t dev);
+
+/*
+ * Enable the agp hardware with the relavent mode. The mode bits are
+ * defined in <pci/agpreg.h>
+ */
+int agp_enable(device_t dev, u_int32_t mode);
+
+/*
+ * Allocate physical memory suitable for mapping into the AGP
+ * aperture. The value returned is an opaque handle which can be
+ * passed to agp_bind(), agp_unbind() or agp_deallocate().
+ */
+void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes);
+
+/*
+ * Free memory which was allocated with agp_allocate().
+ */
+void agp_free_memory(device_t dev, void *handle);
+
+/*
+ * Bind memory allocated with agp_allocate() at a given offset within
+ * the AGP aperture. Returns EINVAL if the memory is already bound or
+ * the offset is not at an AGP page boundary.
+ */
+int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset);
+
+/*
+ * Unbind memory from the AGP aperture. Returns EINVAL if the memory
+ * is not bound.
+ */
+int agp_unbind_memory(device_t dev, void *handle);
+
+/*
+ * Retrieve information about a memory block allocated with
+ * agp_alloc_memory().
+ */
+void agp_memory_info(device_t dev, void *handle, struct agp_memory_info *mi);
+
+#endif /* !_PCI_AGPVAR_H_ */
diff --git a/sys/pci/alpm.c b/sys/pci/alpm.c
new file mode 100644
index 0000000..ae12197f
--- /dev/null
+++ b/sys/pci/alpm.c
@@ -0,0 +1,641 @@
+/*-
+ * Copyright (c) 1998, 1999, 2001 Nicolas Souchu
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Power Management support for the Acer M15x3 chipsets
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/uio.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/smbus/smbconf.h>
+#include "smbus_if.h"
+
+#define ALPM_DEBUG(x) if (alpm_debug) (x)
+
+#ifdef DEBUG
+static int alpm_debug = 1;
+#else
+static int alpm_debug = 0;
+#endif
+
+#define ACER_M1543_PMU_ID 0x710110b9
+
+/* Uncomment this line to force another I/O base address for SMB */
+/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */
+
+/* I/O registers offsets - the base address is programmed via the
+ * SMBBA PCI configuration register
+ */
+#define SMBSTS 0x0 /* SMBus host/slave status register */
+#define SMBCMD 0x1 /* SMBus host/slave command register */
+#define SMBSTART 0x2 /* start to generate programmed cycle */
+#define SMBHADDR 0x3 /* host address register */
+#define SMBHDATA 0x4 /* data A register for host controller */
+#define SMBHDATB 0x5 /* data B register for host controller */
+#define SMBHBLOCK 0x6 /* block register for host controller */
+#define SMBHCMD 0x7 /* command register for host controller */
+
+/* SMBSTS masks */
+#define TERMINATE 0x80
+#define BUS_COLLI 0x40
+#define DEVICE_ERR 0x20
+#define SMI_I_STS 0x10
+#define HST_BSY 0x08
+#define IDL_STS 0x04
+#define HSTSLV_STS 0x02
+#define HSTSLV_BSY 0x01
+
+/* SMBCMD masks */
+#define SMB_BLK_CLR 0x80
+#define T_OUT_CMD 0x08
+#define ABORT_HOST 0x04
+
+/* SMBus commands */
+#define SMBQUICK 0x00
+#define SMBSRBYTE 0x10 /* send/receive byte */
+#define SMBWRBYTE 0x20 /* write/read byte */
+#define SMBWRWORD 0x30 /* write/read word */
+#define SMBWRBLOCK 0x40 /* write/read block */
+
+/* PCI configuration registers and masks
+ */
+#define COM 0x4
+#define COM_ENABLE_IO 0x1
+
+#define SMBBA 0x14
+
+#define ATPC 0x5b
+#define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */
+
+#define SMBHSI 0xe0
+#define SMBHSI_SLAVE 0x2
+#define SMBHSI_HOST 0x1
+
+#define SMBHCBC 0xe2
+#define SMBHCBC_CLOCK 0x70
+
+#define SMBCLOCK_149K 0x0
+#define SMBCLOCK_74K 0x20
+#define SMBCLOCK_37K 0x40
+#define SMBCLOCK_223K 0x80
+#define SMBCLOCK_111K 0xa0
+#define SMBCLOCK_55K 0xc0
+
+struct alpm_softc {
+ int base;
+ struct resource *res;
+ bus_space_tag_t smbst;
+ bus_space_handle_t smbsh;
+ device_t smbus;
+};
+
+#define ALPM_SMBINB(alpm,register) \
+ (bus_space_read_1(alpm->smbst, alpm->smbsh, register))
+#define ALPM_SMBOUTB(alpm,register,value) \
+ (bus_space_write_1(alpm->smbst, alpm->smbsh, register, value))
+
+static int
+alpm_probe(device_t dev)
+{
+#ifdef ALPM_SMBIO_BASE_ADDR
+ u_int32_t l;
+#endif
+
+ if (pci_get_devid(dev) == ACER_M1543_PMU_ID) {
+ device_set_desc(dev, "AcerLabs M15x3 Power Management Unit");
+
+#ifdef ALPM_SMBIO_BASE_ADDR
+ if (bootverbose || alpm_debug)
+ device_printf(dev, "forcing base I/O at 0x%x\n",
+ ALPM_SMBIO_BASE_ADDR);
+
+ /* disable I/O */
+ l = pci_read_config(dev, COM, 2);
+ pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2);
+
+ /* set the I/O base address */
+ pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4);
+
+ /* enable I/O */
+ pci_write_config(dev, COM, l | COM_ENABLE_IO, 2);
+
+ if (bus_set_resource(dev, SYS_RES_IOPORT, SMBBA,
+ ALPM_SMBIO_BASE_ADDR, 256)) {
+ device_printf(dev, "could not set bus resource\n");
+ return (ENXIO);
+ }
+#endif
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+static int
+alpm_attach(device_t dev)
+{
+ int rid, unit;
+ u_int32_t l;
+ struct alpm_softc *alpm;
+
+ alpm = device_get_softc(dev);
+ unit = device_get_unit(dev);
+
+ /* Unlock SMBIO base register access */
+ l = pci_read_config(dev, ATPC, 1);
+ pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1);
+
+ /*
+ * XX linux sets clock to 74k, should we?
+ l = pci_read_config(dev, SMBHCBC, 1);
+ l &= 0x1f;
+ l |= SMBCLOCK_74K;
+ pci_write_config(dev, SMBHCBC, l, 1);
+ */
+
+ if (bootverbose || alpm_debug) {
+ l = pci_read_config(dev, SMBHSI, 1);
+ device_printf(dev, "%s/%s",
+ (l & SMBHSI_HOST) ? "host":"nohost",
+ (l & SMBHSI_SLAVE) ? "slave":"noslave");
+
+ l = pci_read_config(dev, SMBHCBC, 1);
+ switch (l & SMBHCBC_CLOCK) {
+ case SMBCLOCK_149K:
+ printf(" 149K");
+ break;
+ case SMBCLOCK_74K:
+ printf(" 74K");
+ break;
+ case SMBCLOCK_37K:
+ printf(" 37K");
+ break;
+ case SMBCLOCK_223K:
+ printf(" 223K");
+ break;
+ case SMBCLOCK_111K:
+ printf(" 111K");
+ break;
+ case SMBCLOCK_55K:
+ printf(" 55K");
+ break;
+ default:
+ printf("unkown");
+ break;
+ }
+ printf("\n");
+ }
+
+ rid = SMBBA;
+ alpm->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (alpm->res == NULL) {
+ device_printf(dev,"Could not allocate Bus space\n");
+ return (ENXIO);
+ }
+ alpm->smbst = rman_get_bustag(alpm->res);
+ alpm->smbsh = rman_get_bushandle(alpm->res);
+
+ /* attach the smbus */
+ alpm->smbus = device_add_child(dev, "smbus", -1);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static int
+alpm_detach(device_t dev)
+{
+ struct alpm_softc *alpm = device_get_softc(dev);
+
+ if (alpm->smbus) {
+ device_delete_child(dev, alpm->smbus);
+ alpm->smbus = NULL;
+ }
+
+ if (alpm->res)
+ bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res);
+
+ return (0);
+}
+
+static int
+alpm_callback(device_t dev, int index, caddr_t *data)
+{
+ int error = 0;
+
+ switch (index) {
+ case SMB_REQUEST_BUS:
+ case SMB_RELEASE_BUS:
+ /* ok, bus allocation accepted */
+ break;
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+static int
+alpm_clear(struct alpm_softc *sc)
+{
+ ALPM_SMBOUTB(sc, SMBSTS, 0xff);
+ DELAY(10);
+
+ return (0);
+}
+
+#if 0
+static int
+alpm_abort(struct alpm_softc *sc)
+{
+ ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST);
+
+ return (0);
+}
+#endif
+
+static int
+alpm_idle(struct alpm_softc *sc)
+{
+ u_char sts;
+
+ sts = ALPM_SMBINB(sc, SMBSTS);
+
+ ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts));
+
+ return (sts & IDL_STS);
+}
+
+/*
+ * Poll the SMBus controller
+ */
+static int
+alpm_wait(struct alpm_softc *sc)
+{
+ int count = 10000;
+ u_char sts = 0;
+ int error;
+
+ /* wait for command to complete and SMBus controller is idle */
+ while(count--) {
+ DELAY(10);
+ sts = ALPM_SMBINB(sc, SMBSTS);
+ if (sts & SMI_I_STS)
+ break;
+ }
+
+ ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts));
+
+ error = SMB_ENOERR;
+
+ if (!count)
+ error |= SMB_ETIMEOUT;
+
+ if (sts & TERMINATE)
+ error |= SMB_EABORT;
+
+ if (sts & BUS_COLLI)
+ error |= SMB_ENOACK;
+
+ if (sts & DEVICE_ERR)
+ error |= SMB_EBUSERR;
+
+ if (error != SMB_ENOERR)
+ alpm_clear(sc);
+
+ return (error);
+}
+
+static int
+alpm_quick(device_t dev, u_char slave, int how)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (EBUSY);
+
+ switch (how) {
+ case SMB_QWRITE:
+ ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave));
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ break;
+ case SMB_QREAD:
+ ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave));
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ break;
+ default:
+ panic("%s: unknown QUICK command (%x)!", __func__,
+ how);
+ }
+ ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alpm_wait(sc);
+
+ ALPM_DEBUG(printf(", error=0x%x\n", error));
+
+ return (error);
+}
+
+static int
+alpm_sendb(device_t dev, u_char slave, char byte)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
+ ALPM_SMBOUTB(sc, SMBHDATA, byte);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alpm_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
+
+ return (error);
+}
+
+static int
+alpm_recvb(device_t dev, u_char slave, char *byte)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alpm_wait(sc)) == SMB_ENOERR)
+ *byte = ALPM_SMBINB(sc, SMBHDATA);
+
+ ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
+
+ return (error);
+}
+
+static int
+alpm_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
+ ALPM_SMBOUTB(sc, SMBHDATA, byte);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alpm_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
+
+ return (error);
+}
+
+static int
+alpm_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alpm_wait(sc)) == SMB_ENOERR)
+ *byte = ALPM_SMBINB(sc, SMBHDATA);
+
+ ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
+
+ return (error);
+}
+
+static int
+alpm_writew(device_t dev, u_char slave, char cmd, short word)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
+ ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff);
+ ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alpm_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
+
+ return (error);
+}
+
+static int
+alpm_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ int error;
+ u_char high, low;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alpm_wait(sc)) == SMB_ENOERR) {
+ low = ALPM_SMBINB(sc, SMBHDATA);
+ high = ALPM_SMBINB(sc, SMBHDATB);
+
+ *word = ((high & 0xff) << 8) | (low & 0xff);
+ }
+
+ ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
+
+ return (error);
+}
+
+static int
+alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ alpm_clear(sc);
+ if(!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ len = min(remain, 32);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+
+ /* set the cmd and reset the
+ * 32-byte long internal buffer */
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
+
+ ALPM_SMBOUTB(sc, SMBHDATA, len);
+
+ /* fill the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]);
+ DELAY(2);
+ }
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alpm_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ remain -= len;
+ }
+
+error:
+ ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static int
+alpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ alpm_clear(sc);
+ if (!alpm_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+
+ /* set the cmd and reset the
+ * 32-byte long internal buffer */
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
+
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alpm_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ len = ALPM_SMBINB(sc, SMBHDATA);
+
+ /* read the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK);
+ DELAY(2);
+ }
+
+ remain -= len;
+ }
+error:
+ ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static devclass_t alpm_devclass;
+
+static device_method_t alpm_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, alpm_probe),
+ DEVMETHOD(device_attach, alpm_attach),
+ DEVMETHOD(device_detach, alpm_detach),
+
+ /* smbus interface */
+ DEVMETHOD(smbus_callback, alpm_callback),
+ DEVMETHOD(smbus_quick, alpm_quick),
+ DEVMETHOD(smbus_sendb, alpm_sendb),
+ DEVMETHOD(smbus_recvb, alpm_recvb),
+ DEVMETHOD(smbus_writeb, alpm_writeb),
+ DEVMETHOD(smbus_readb, alpm_readb),
+ DEVMETHOD(smbus_writew, alpm_writew),
+ DEVMETHOD(smbus_readw, alpm_readw),
+ DEVMETHOD(smbus_bwrite, alpm_bwrite),
+ DEVMETHOD(smbus_bread, alpm_bread),
+
+ { 0, 0 }
+};
+
+static driver_t alpm_driver = {
+ "alpm",
+ alpm_methods,
+ sizeof(struct alpm_softc)
+};
+
+DRIVER_MODULE(alpm, pci, alpm_driver, alpm_devclass, 0, 0);
+MODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(alpm, 1);
diff --git a/sys/pci/amd.c b/sys/pci/amd.c
new file mode 100644
index 0000000..5089371
--- /dev/null
+++ b/sys/pci/amd.c
@@ -0,0 +1,2453 @@
+/*
+ *********************************************************************
+ * FILE NAME : amd.c
+ * BY : C.L. Huang (ching@tekram.com.tw)
+ * Erich Chen (erich@tekram.com.tw)
+ * Description: Device Driver for the amd53c974 PCI Bus Master
+ * SCSI Host adapter found on cards such as
+ * the Tekram DC-390(T).
+ * (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
+ *
+ * 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. 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 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.
+ *********************************************************************
+ * $FreeBSD$
+ */
+
+/*
+ *********************************************************************
+ * HISTORY:
+ *
+ * REV# DATE NAME DESCRIPTION
+ * 1.00 07/02/96 CLH First release for RELEASE-2.1.0
+ * 1.01 08/20/96 CLH Update for RELEASE-2.1.5
+ * 1.02 11/06/96 CLH Fixed more than 1 LUN scanning
+ * 1.03 12/20/96 CLH Modify to support 2.2-ALPHA
+ * 1.04 12/26/97 CLH Modify to support RELEASE-2.2.5
+ * 1.05 01/01/99 ERICH CHEN Modify to support RELEASE-3.0.x (CAM)
+ *********************************************************************
+ */
+
+/* #define AMD_DEBUG0 */
+/* #define AMD_DEBUG_SCSI_PHASE */
+
+#include <sys/param.h>
+
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/amd.h>
+
+#define PCI_DEVICE_ID_AMD53C974 0x20201022ul
+#define PCI_BASE_ADDR0 0x10
+
+typedef u_int (phase_handler_t)(struct amd_softc *, struct amd_srb *, u_int);
+typedef phase_handler_t *phase_handler_func_t;
+
+static void amd_intr(void *vamd);
+static int amdstart(struct amd_softc *amd, struct amd_srb * pSRB);
+static phase_handler_t amd_NopPhase;
+
+static phase_handler_t amd_DataOutPhase0;
+static phase_handler_t amd_DataInPhase0;
+#define amd_CommandPhase0 amd_NopPhase
+static phase_handler_t amd_StatusPhase0;
+static phase_handler_t amd_MsgOutPhase0;
+static phase_handler_t amd_MsgInPhase0;
+static phase_handler_t amd_DataOutPhase1;
+static phase_handler_t amd_DataInPhase1;
+static phase_handler_t amd_CommandPhase1;
+static phase_handler_t amd_StatusPhase1;
+static phase_handler_t amd_MsgOutPhase1;
+static phase_handler_t amd_MsgInPhase1;
+
+static void amdsetupcommand(struct amd_softc *amd, struct amd_srb *srb);
+static int amdparsemsg(struct amd_softc *amd);
+static int amdhandlemsgreject(struct amd_softc *amd);
+static void amdconstructsdtr(struct amd_softc *amd,
+ u_int period, u_int offset);
+static u_int amdfindclockrate(struct amd_softc *amd, u_int *period);
+static int amdsentmsg(struct amd_softc *amd, u_int msgtype, int full);
+
+static void DataIO_Comm(struct amd_softc *amd, struct amd_srb *pSRB, u_int dir);
+static void amd_Disconnect(struct amd_softc *amd);
+static void amd_Reselect(struct amd_softc *amd);
+static void SRBdone(struct amd_softc *amd, struct amd_srb *pSRB);
+static void amd_ScsiRstDetect(struct amd_softc *amd);
+static void amd_ResetSCSIBus(struct amd_softc *amd);
+static void RequestSense(struct amd_softc *amd, struct amd_srb *pSRB);
+static void amd_InvalidCmd(struct amd_softc *amd);
+
+#if 0
+static void amd_timeout(void *arg1);
+static void amd_reset(struct amd_softc *amd);
+#endif
+static u_int8_t * phystovirt(struct amd_srb *pSRB, u_int32_t xferCnt);
+
+void amd_linkSRB(struct amd_softc *amd);
+static int amd_init(device_t);
+static void amd_load_defaults(struct amd_softc *amd);
+static void amd_load_eeprom_or_defaults(struct amd_softc *amd);
+static int amd_EEpromInDO(struct amd_softc *amd);
+static u_int16_t EEpromGetData1(struct amd_softc *amd);
+static void amd_EnDisableCE(struct amd_softc *amd, int mode, int *regval);
+static void amd_EEpromOutDI(struct amd_softc *amd, int *regval, int Carry);
+static void amd_Prepare(struct amd_softc *amd, int *regval, u_int8_t EEpromCmd);
+static void amd_ReadEEprom(struct amd_softc *amd);
+
+static int amd_probe(device_t);
+static int amd_attach(device_t);
+static void amdcompletematch(struct amd_softc *amd, target_id_t target,
+ lun_id_t lun, u_int tag, struct srb_queue *queue,
+ cam_status status);
+static void amdsetsync(struct amd_softc *amd, u_int target, u_int clockrate,
+ u_int period, u_int offset, u_int type);
+static void amdsettags(struct amd_softc *amd, u_int target, int tagenb);
+
+static __inline void amd_clear_msg_state(struct amd_softc *amd);
+
+static __inline void
+amd_clear_msg_state(struct amd_softc *amd)
+{
+ amd->msgout_len = 0;
+ amd->msgout_index = 0;
+ amd->msgin_index = 0;
+}
+
+/* CAM SIM entry points */
+#define ccb_srb_ptr spriv_ptr0
+#define ccb_amd_ptr spriv_ptr1
+static void amd_action(struct cam_sim *sim, union ccb *ccb);
+static void amd_poll(struct cam_sim *sim);
+
+/*
+ * State engine function tables indexed by SCSI phase number
+ */
+phase_handler_func_t amd_SCSI_phase0[] = {
+ amd_DataOutPhase0,
+ amd_DataInPhase0,
+ amd_CommandPhase0,
+ amd_StatusPhase0,
+ amd_NopPhase,
+ amd_NopPhase,
+ amd_MsgOutPhase0,
+ amd_MsgInPhase0
+};
+
+phase_handler_func_t amd_SCSI_phase1[] = {
+ amd_DataOutPhase1,
+ amd_DataInPhase1,
+ amd_CommandPhase1,
+ amd_StatusPhase1,
+ amd_NopPhase,
+ amd_NopPhase,
+ amd_MsgOutPhase1,
+ amd_MsgInPhase1
+};
+
+/*
+ * EEProm/BIOS negotiation periods
+ */
+u_int8_t eeprom_period[] = {
+ 25, /* 10.0MHz */
+ 32, /* 8.0MHz */
+ 38, /* 6.6MHz */
+ 44, /* 5.7MHz */
+ 50, /* 5.0MHz */
+ 63, /* 4.0MHz */
+ 83, /* 3.0MHz */
+ 125 /* 2.0MHz */
+};
+
+/*
+ * chip clock setting to SCSI specified sync parameter table.
+ */
+u_int8_t tinfo_sync_period[] = {
+ 25, /* 10.0 */
+ 32, /* 8.0 */
+ 38, /* 6.6 */
+ 44, /* 5.7 */
+ 50, /* 5.0 */
+ 57, /* 4.4 */
+ 63, /* 4.0 */
+ 70, /* 3.6 */
+ 76, /* 3.3 */
+ 83 /* 3.0 */
+};
+
+static __inline struct amd_srb *
+amdgetsrb(struct amd_softc * amd)
+{
+ int intflag;
+ struct amd_srb * pSRB;
+
+ intflag = splcam();
+ pSRB = TAILQ_FIRST(&amd->free_srbs);
+ if (pSRB)
+ TAILQ_REMOVE(&amd->free_srbs, pSRB, links);
+ splx(intflag);
+ return (pSRB);
+}
+
+static void
+amdsetupcommand(struct amd_softc *amd, struct amd_srb *srb)
+{
+ struct scsi_request_sense sense_cmd;
+ struct ccb_scsiio *csio;
+ u_int8_t *cdb;
+ u_int cdb_len;
+
+ csio = &srb->pccb->csio;
+
+ if (srb->SRBFlag & AUTO_REQSENSE) {
+ sense_cmd.opcode = REQUEST_SENSE;
+ sense_cmd.byte2 = srb->pccb->ccb_h.target_lun << 5;
+ sense_cmd.unused[0] = 0;
+ sense_cmd.unused[1] = 0;
+ sense_cmd.length = csio->sense_len;
+ sense_cmd.control = 0;
+ cdb = &sense_cmd.opcode;
+ cdb_len = sizeof(sense_cmd);
+ } else {
+ cdb = &srb->CmdBlock[0];
+ cdb_len = srb->ScsiCmdLen;
+ }
+ amd_write8_multi(amd, SCSIFIFOREG, cdb, cdb_len);
+}
+
+/*
+ * Attempt to start a waiting transaction. Interrupts must be disabled
+ * upon entry to this function.
+ */
+static void
+amdrunwaiting(struct amd_softc *amd) {
+ struct amd_srb *srb;
+
+ if (amd->last_phase != SCSI_BUS_FREE)
+ return;
+
+ srb = TAILQ_FIRST(&amd->waiting_srbs);
+ if (srb == NULL)
+ return;
+
+ if (amdstart(amd, srb) == 0) {
+ TAILQ_REMOVE(&amd->waiting_srbs, srb, links);
+ TAILQ_INSERT_HEAD(&amd->running_srbs, srb, links);
+ }
+}
+
+static void
+amdexecutesrb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
+{
+ struct amd_srb *srb;
+ union ccb *ccb;
+ struct amd_softc *amd;
+ int s;
+
+ srb = (struct amd_srb *)arg;
+ ccb = srb->pccb;
+ amd = (struct amd_softc *)ccb->ccb_h.ccb_amd_ptr;
+
+ if (error != 0) {
+ if (error != EFBIG)
+ printf("amd%d: Unexepected error 0x%x returned from "
+ "bus_dmamap_load\n", amd->unit, error);
+ if (ccb->ccb_h.status == CAM_REQ_INPROG) {
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
+ }
+ TAILQ_INSERT_HEAD(&amd->free_srbs, srb, links);
+ xpt_done(ccb);
+ return;
+ }
+
+ if (nseg != 0) {
+ struct amd_sg *sg;
+ bus_dma_segment_t *end_seg;
+ bus_dmasync_op_t op;
+
+ end_seg = dm_segs + nseg;
+
+ /* Copy the segments into our SG list */
+ srb->pSGlist = &srb->SGsegment[0];
+ sg = srb->pSGlist;
+ while (dm_segs < end_seg) {
+ sg->SGXLen = dm_segs->ds_len;
+ sg->SGXPtr = dm_segs->ds_addr;
+ sg++;
+ dm_segs++;
+ }
+
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_PREREAD;
+ else
+ op = BUS_DMASYNC_PREWRITE;
+
+ bus_dmamap_sync(amd->buffer_dmat, srb->dmamap, op);
+
+ }
+ srb->SGcount = nseg;
+ srb->SGIndex = 0;
+ srb->AdaptStatus = 0;
+ srb->TargetStatus = 0;
+ srb->MsgCnt = 0;
+ srb->SRBStatus = 0;
+ srb->SRBFlag = 0;
+ srb->SRBState = 0;
+ srb->TotalXferredLen = 0;
+ srb->SGPhysAddr = 0;
+ srb->SGToBeXferLen = 0;
+ srb->EndMessage = 0;
+
+ s = splcam();
+
+ /*
+ * Last time we need to check if this CCB needs to
+ * be aborted.
+ */
+ if (ccb->ccb_h.status != CAM_REQ_INPROG) {
+ if (nseg != 0)
+ bus_dmamap_unload(amd->buffer_dmat, srb->dmamap);
+ TAILQ_INSERT_HEAD(&amd->free_srbs, srb, links);
+ xpt_done(ccb);
+ splx(s);
+ return;
+ }
+ ccb->ccb_h.status |= CAM_SIM_QUEUED;
+#if 0
+ /* XXX Need a timeout handler */
+ ccb->ccb_h.timeout_ch =
+ timeout(amdtimeout, (caddr_t)srb,
+ (ccb->ccb_h.timeout * hz) / 1000);
+#endif
+ TAILQ_INSERT_TAIL(&amd->waiting_srbs, srb, links);
+ amdrunwaiting(amd);
+ splx(s);
+}
+
+static void
+amd_action(struct cam_sim * psim, union ccb * pccb)
+{
+ struct amd_softc * amd;
+ u_int target_id, target_lun;
+
+ CAM_DEBUG(pccb->ccb_h.path, CAM_DEBUG_TRACE, ("amd_action\n"));
+
+ amd = (struct amd_softc *) cam_sim_softc(psim);
+ target_id = pccb->ccb_h.target_id;
+ target_lun = pccb->ccb_h.target_lun;
+
+ switch (pccb->ccb_h.func_code) {
+ case XPT_SCSI_IO:
+ {
+ struct amd_srb * pSRB;
+ struct ccb_scsiio *pcsio;
+
+ pcsio = &pccb->csio;
+
+ /*
+ * Assign an SRB and connect it with this ccb.
+ */
+ pSRB = amdgetsrb(amd);
+
+ if (!pSRB) {
+ /* Freeze SIMQ */
+ pccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(pccb);
+ return;
+ }
+ pSRB->pccb = pccb;
+ pccb->ccb_h.ccb_srb_ptr = pSRB;
+ pccb->ccb_h.ccb_amd_ptr = amd;
+ pSRB->ScsiCmdLen = pcsio->cdb_len;
+ bcopy(pcsio->cdb_io.cdb_bytes, pSRB->CmdBlock, pcsio->cdb_len);
+ if ((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if ((pccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
+ /*
+ * We've been given a pointer
+ * to a single buffer.
+ */
+ if ((pccb->ccb_h.flags & CAM_DATA_PHYS) == 0) {
+ int s;
+ int error;
+
+ s = splsoftvm();
+ error =
+ bus_dmamap_load(amd->buffer_dmat,
+ pSRB->dmamap,
+ pcsio->data_ptr,
+ pcsio->dxfer_len,
+ amdexecutesrb,
+ pSRB, /*flags*/0);
+ if (error == EINPROGRESS) {
+ /*
+ * So as to maintain
+ * ordering, freeze the
+ * controller queue
+ * until our mapping is
+ * returned.
+ */
+ xpt_freeze_simq(amd->psim, 1);
+ pccb->ccb_h.status |=
+ CAM_RELEASE_SIMQ;
+ }
+ splx(s);
+ } else {
+ struct bus_dma_segment seg;
+
+ /* Pointer to physical buffer */
+ seg.ds_addr =
+ (bus_addr_t)pcsio->data_ptr;
+ seg.ds_len = pcsio->dxfer_len;
+ amdexecutesrb(pSRB, &seg, 1, 0);
+ }
+ } else {
+ struct bus_dma_segment *segs;
+
+ if ((pccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0
+ || (pccb->ccb_h.flags & CAM_DATA_PHYS) != 0) {
+ TAILQ_INSERT_HEAD(&amd->free_srbs,
+ pSRB, links);
+ pccb->ccb_h.status = CAM_PROVIDE_FAIL;
+ xpt_done(pccb);
+ return;
+ }
+
+ /* Just use the segments provided */
+ segs =
+ (struct bus_dma_segment *)pcsio->data_ptr;
+ amdexecutesrb(pSRB, segs, pcsio->sglist_cnt, 0);
+ }
+ } else
+ amdexecutesrb(pSRB, NULL, 0, 0);
+ break;
+ }
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = &pccb->cpi;
+
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = 0;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 7;
+ cpi->max_lun = amd->max_lun; /* 7 or 0 */
+ cpi->initiator_id = amd->AdaptSCSIID;
+ cpi->bus_id = cam_sim_bus(psim);
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "TRM-AMD", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(psim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(pccb);
+ break;
+ }
+ case XPT_ABORT:
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ break;
+ case XPT_RESET_BUS:
+ {
+
+ int i;
+
+ amd_ResetSCSIBus(amd);
+ amd->ACBFlag = 0;
+
+ for (i = 0; i < 500; i++) {
+ DELAY(1000); /* Wait until our interrupt
+ * handler sees it */
+ }
+
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(pccb);
+ break;
+ }
+ case XPT_RESET_DEV:
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ break;
+ case XPT_TERM_IO:
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ struct amd_target_info *targ_info;
+ struct amd_transinfo *tinfo;
+ int intflag;
+
+ cts = &pccb->cts;
+ intflag = splcam();
+ targ_info = &amd->tinfo[target_id];
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ /* current transfer settings */
+ if (targ_info->disc_tag & AMD_CUR_DISCENB) {
+ cts->flags = CCB_TRANS_DISC_ENB;
+ } else {
+ cts->flags = 0; /* no tag & disconnect */
+ }
+ if (targ_info->disc_tag & AMD_CUR_TAGENB) {
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ }
+ tinfo = &targ_info->current;
+ } else {
+ /* default(user) transfer settings */
+ if (targ_info->disc_tag & AMD_USR_DISCENB) {
+ cts->flags = CCB_TRANS_DISC_ENB;
+ } else {
+ cts->flags = 0;
+ }
+ if (targ_info->disc_tag & AMD_USR_TAGENB) {
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ }
+ tinfo = &targ_info->user;
+ }
+
+ cts->sync_period = tinfo->period;
+ cts->sync_offset = tinfo->offset;
+ cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ splx(intflag);
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(pccb);
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ struct amd_target_info *targ_info;
+ u_int update_type;
+ int intflag;
+ int last_entry;
+
+ cts = &pccb->cts;
+ update_type = 0;
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ update_type |= AMD_TRANS_GOAL;
+ } else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
+ update_type |= AMD_TRANS_USER;
+ }
+ if (update_type == 0
+ || update_type == (AMD_TRANS_USER|AMD_TRANS_GOAL)) {
+ cts->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ }
+
+ intflag = splcam();
+ targ_info = &amd->tinfo[target_id];
+
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
+ if (update_type & AMD_TRANS_GOAL) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
+ targ_info->disc_tag |= AMD_CUR_DISCENB;
+ } else {
+ targ_info->disc_tag &= ~AMD_CUR_DISCENB;
+ }
+ }
+ if (update_type & AMD_TRANS_USER) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
+ targ_info->disc_tag |= AMD_USR_DISCENB;
+ } else {
+ targ_info->disc_tag &= ~AMD_USR_DISCENB;
+ }
+ }
+ }
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
+ if (update_type & AMD_TRANS_GOAL) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
+ targ_info->disc_tag |= AMD_CUR_TAGENB;
+ } else {
+ targ_info->disc_tag &= ~AMD_CUR_TAGENB;
+ }
+ }
+ if (update_type & AMD_TRANS_USER) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
+ targ_info->disc_tag |= AMD_USR_TAGENB;
+ } else {
+ targ_info->disc_tag &= ~AMD_USR_TAGENB;
+ }
+ }
+ }
+
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) {
+ if (update_type & AMD_TRANS_GOAL)
+ cts->sync_offset = targ_info->goal.offset;
+ else
+ cts->sync_offset = targ_info->user.offset;
+ }
+
+ if (cts->sync_offset > AMD_MAX_SYNC_OFFSET)
+ cts->sync_offset = AMD_MAX_SYNC_OFFSET;
+
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) {
+ if (update_type & AMD_TRANS_GOAL)
+ cts->sync_period = targ_info->goal.period;
+ else
+ cts->sync_period = targ_info->user.period;
+ }
+
+ last_entry = sizeof(tinfo_sync_period) - 1;
+ if ((cts->sync_period != 0)
+ && (cts->sync_period < tinfo_sync_period[0]))
+ cts->sync_period = tinfo_sync_period[0];
+ if (cts->sync_period > tinfo_sync_period[last_entry])
+ cts->sync_period = 0;
+ if (cts->sync_offset == 0)
+ cts->sync_period = 0;
+
+ if ((update_type & AMD_TRANS_USER) != 0) {
+ targ_info->user.period = cts->sync_period;
+ targ_info->user.offset = cts->sync_offset;
+ }
+ if ((update_type & AMD_TRANS_GOAL) != 0) {
+ targ_info->goal.period = cts->sync_period;
+ targ_info->goal.offset = cts->sync_offset;
+ }
+ splx(intflag);
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(pccb);
+ break;
+ }
+ case XPT_CALC_GEOMETRY:
+ {
+ struct ccb_calc_geometry *ccg;
+ u_int32_t size_mb;
+ u_int32_t secs_per_cylinder;
+ int extended;
+
+ ccg = &pccb->ccg;
+ size_mb = ccg->volume_size/((1024L * 1024L)/ccg->block_size);
+ extended = (amd->eepromBuf[EE_MODE2] & GREATER_1G) != 0;
+
+ if (size_mb > 1024 && extended) {
+ ccg->heads = 255;
+ ccg->secs_per_track = 63;
+ } else {
+ ccg->heads = 64;
+ ccg->secs_per_track = 32;
+ }
+ secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+ ccg->cylinders = ccg->volume_size / secs_per_cylinder;
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(pccb);
+ break;
+ }
+ default:
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ break;
+ }
+}
+
+static void
+amd_poll(struct cam_sim * psim)
+{
+ amd_intr(cam_sim_softc(psim));
+}
+
+static u_int8_t *
+phystovirt(struct amd_srb * pSRB, u_int32_t xferCnt)
+{
+ int dataPtr;
+ struct ccb_scsiio *pcsio;
+ u_int8_t i;
+ struct amd_sg * pseg;
+
+ dataPtr = 0;
+ pcsio = &pSRB->pccb->csio;
+
+ dataPtr = (int) pcsio->data_ptr;
+ pseg = pSRB->SGsegment;
+ for (i = 0; i < pSRB->SGIndex; i++) {
+ dataPtr += (int) pseg->SGXLen;
+ pseg++;
+ }
+ dataPtr += (int) xferCnt;
+ return ((u_int8_t *) dataPtr);
+}
+
+static void
+ResetDevParam(struct amd_softc * amd)
+{
+ u_int target;
+
+ for (target = 0; target <= amd->max_id; target++) {
+ if (amd->AdaptSCSIID != target) {
+ amdsetsync(amd, target, /*clockrate*/0,
+ /*period*/0, /*offset*/0, AMD_TRANS_CUR);
+ }
+ }
+}
+
+static void
+amdcompletematch(struct amd_softc *amd, target_id_t target, lun_id_t lun,
+ u_int tag, struct srb_queue *queue, cam_status status)
+{
+ struct amd_srb *srb;
+ struct amd_srb *next_srb;
+
+ for (srb = TAILQ_FIRST(queue); srb != NULL; srb = next_srb) {
+ union ccb *ccb;
+
+ next_srb = TAILQ_NEXT(srb, links);
+ if (srb->pccb->ccb_h.target_id != target
+ && target != CAM_TARGET_WILDCARD)
+ continue;
+
+ if (srb->pccb->ccb_h.target_lun != lun
+ && lun != CAM_LUN_WILDCARD)
+ continue;
+
+ if (srb->TagNumber != tag
+ && tag != AMD_TAG_WILDCARD)
+ continue;
+
+ ccb = srb->pccb;
+ TAILQ_REMOVE(queue, srb, links);
+ TAILQ_INSERT_HEAD(&amd->free_srbs, srb, links);
+ if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0
+ && (status & CAM_DEV_QFRZN) != 0)
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status = status;
+ xpt_done(ccb);
+ }
+
+}
+
+static void
+amdsetsync(struct amd_softc *amd, u_int target, u_int clockrate,
+ u_int period, u_int offset, u_int type)
+{
+ struct amd_target_info *tinfo;
+ u_int old_period;
+ u_int old_offset;
+
+ tinfo = &amd->tinfo[target];
+ old_period = tinfo->current.period;
+ old_offset = tinfo->current.offset;
+ if ((type & AMD_TRANS_CUR) != 0
+ && (old_period != period || old_offset != offset)) {
+ struct cam_path *path;
+
+ tinfo->current.period = period;
+ tinfo->current.offset = offset;
+ tinfo->sync_period_reg = clockrate;
+ tinfo->sync_offset_reg = offset;
+ tinfo->CtrlR3 &= ~FAST_SCSI;
+ tinfo->CtrlR4 &= ~EATER_25NS;
+ if (clockrate > 7)
+ tinfo->CtrlR4 |= EATER_25NS;
+ else
+ tinfo->CtrlR3 |= FAST_SCSI;
+
+ if ((type & AMD_TRANS_ACTIVE) == AMD_TRANS_ACTIVE) {
+ amd_write8(amd, SYNCPERIOREG, tinfo->sync_period_reg);
+ amd_write8(amd, SYNCOFFREG, tinfo->sync_offset_reg);
+ amd_write8(amd, CNTLREG3, tinfo->CtrlR3);
+ amd_write8(amd, CNTLREG4, tinfo->CtrlR4);
+ }
+ /* If possible, update the XPT's notion of our transfer rate */
+ if (xpt_create_path(&path, /*periph*/NULL,
+ cam_sim_path(amd->psim), target,
+ CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
+ struct ccb_trans_settings neg;
+
+ xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
+ neg.sync_period = period;
+ neg.sync_offset = offset;
+ neg.valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID;
+ xpt_async(AC_TRANSFER_NEG, path, &neg);
+ xpt_free_path(path);
+ }
+ }
+ if ((type & AMD_TRANS_GOAL) != 0) {
+ tinfo->goal.period = period;
+ tinfo->goal.offset = offset;
+ }
+
+ if ((type & AMD_TRANS_USER) != 0) {
+ tinfo->user.period = period;
+ tinfo->user.offset = offset;
+ }
+}
+
+static void
+amdsettags(struct amd_softc *amd, u_int target, int tagenb)
+{
+ panic("Implement me!\n");
+}
+
+
+#if 0
+/*
+ **********************************************************************
+ * Function : amd_reset (struct amd_softc * amd)
+ * Purpose : perform a hard reset on the SCSI bus( and AMD chip).
+ * Inputs : cmd - command which caused the SCSI RESET
+ **********************************************************************
+ */
+static void
+amd_reset(struct amd_softc * amd)
+{
+ int intflag;
+ u_int8_t bval;
+ u_int16_t i;
+
+
+#ifdef AMD_DEBUG0
+ printf("DC390: RESET");
+#endif
+
+ intflag = splcam();
+ bval = amd_read8(amd, CNTLREG1);
+ bval |= DIS_INT_ON_SCSI_RST;
+ amd_write8(amd, CNTLREG1, bval); /* disable interrupt */
+ amd_ResetSCSIBus(amd);
+
+ for (i = 0; i < 500; i++) {
+ DELAY(1000);
+ }
+
+ bval = amd_read8(amd, CNTLREG1);
+ bval &= ~DIS_INT_ON_SCSI_RST;
+ amd_write8(amd, CNTLREG1, bval); /* re-enable interrupt */
+
+ amd_write8(amd, DMA_Cmd, DMA_IDLE_CMD);
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+
+ ResetDevParam(amd);
+ amdcompletematch(amd, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD,
+ AMD_TAG_WILDCARD, &amd->running_srbs,
+ CAM_DEV_QFRZN|CAM_SCSI_BUS_RESET);
+ amdcompletematch(amd, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD,
+ AMD_TAG_WILDCARD, &amd->waiting_srbs,
+ CAM_DEV_QFRZN|CAM_SCSI_BUS_RESET);
+ amd->active_srb = NULL;
+ amd->ACBFlag = 0;
+ splx(intflag);
+ return;
+}
+
+void
+amd_timeout(void *arg1)
+{
+ struct amd_srb * pSRB;
+
+ pSRB = (struct amd_srb *) arg1;
+}
+#endif
+
+static int
+amdstart(struct amd_softc *amd, struct amd_srb *pSRB)
+{
+ union ccb *pccb;
+ struct ccb_scsiio *pcsio;
+ struct amd_target_info *targ_info;
+ u_int identify_msg;
+ u_int command;
+ u_int target;
+ u_int lun;
+ int tagged;
+
+ pccb = pSRB->pccb;
+ pcsio = &pccb->csio;
+ target = pccb->ccb_h.target_id;
+ lun = pccb->ccb_h.target_lun;
+ targ_info = &amd->tinfo[target];
+
+ amd_clear_msg_state(amd);
+ amd_write8(amd, SCSIDESTIDREG, target);
+ amd_write8(amd, SYNCPERIOREG, targ_info->sync_period_reg);
+ amd_write8(amd, SYNCOFFREG, targ_info->sync_offset_reg);
+ amd_write8(amd, CNTLREG1, targ_info->CtrlR1);
+ amd_write8(amd, CNTLREG3, targ_info->CtrlR3);
+ amd_write8(amd, CNTLREG4, targ_info->CtrlR4);
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+
+ identify_msg = MSG_IDENTIFYFLAG | lun;
+ if ((targ_info->disc_tag & AMD_CUR_DISCENB) != 0
+ && (pccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0
+ && (pSRB->CmdBlock[0] != REQUEST_SENSE)
+ && (pSRB->SRBFlag & AUTO_REQSENSE) == 0)
+ identify_msg |= MSG_IDENTIFY_DISCFLAG;
+
+ amd_write8(amd, SCSIFIFOREG, identify_msg);
+ tagged = 0;
+ if ((targ_info->disc_tag & AMD_CUR_TAGENB) == 0
+ || (identify_msg & MSG_IDENTIFY_DISCFLAG) == 0)
+ pccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID;
+ if (targ_info->current.period != targ_info->goal.period
+ || targ_info->current.offset != targ_info->goal.offset) {
+ command = SEL_W_ATN_STOP;
+ amdconstructsdtr(amd, targ_info->goal.period,
+ targ_info->goal.offset);
+ } else if ((pccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
+ command = SEL_W_ATN2;
+ pSRB->SRBState = SRB_START;
+ amd_write8(amd, SCSIFIFOREG, pcsio->tag_action);
+ amd_write8(amd, SCSIFIFOREG, pSRB->TagNumber);
+ tagged++;
+ } else {
+ command = SEL_W_ATN;
+ pSRB->SRBState = SRB_START;
+ }
+ if (command != SEL_W_ATN_STOP)
+ amdsetupcommand(amd, pSRB);
+
+ if (amd_read8(amd, SCSISTATREG) & INTERRUPT) {
+ pSRB->SRBState = SRB_READY;
+ return (1);
+ } else {
+ amd->last_phase = SCSI_ARBITRATING;
+ amd_write8(amd, SCSICMDREG, command);
+ amd->active_srb = pSRB;
+ amd->cur_target = target;
+ amd->cur_lun = lun;
+ return (0);
+ }
+}
+
+/*
+ * Catch an interrupt from the adapter.
+ * Process pending device interrupts.
+ */
+static void
+amd_intr(void *arg)
+{
+ struct amd_softc *amd;
+ struct amd_srb *pSRB;
+ u_int internstat = 0;
+ u_int scsistat;
+ u_int intstat;
+
+ amd = (struct amd_softc *)arg;
+
+ if (amd == NULL) {
+#ifdef AMD_DEBUG0
+ printf("amd_intr: amd NULL return......");
+#endif
+ return;
+ }
+
+ scsistat = amd_read8(amd, SCSISTATREG);
+ if (!(scsistat & INTERRUPT)) {
+#ifdef AMD_DEBUG0
+ printf("amd_intr: scsistat = NULL ,return......");
+#endif
+ return;
+ }
+#ifdef AMD_DEBUG_SCSI_PHASE
+ printf("scsistat=%2x,", scsistat);
+#endif
+
+ internstat = amd_read8(amd, INTERNSTATREG);
+ intstat = amd_read8(amd, INTSTATREG);
+
+#ifdef AMD_DEBUG_SCSI_PHASE
+ printf("intstat=%2x,", intstat);
+#endif
+
+ if (intstat & DISCONNECTED) {
+ amd_Disconnect(amd);
+ return;
+ }
+ if (intstat & RESELECTED) {
+ amd_Reselect(amd);
+ return;
+ }
+ if (intstat & INVALID_CMD) {
+ amd_InvalidCmd(amd);
+ return;
+ }
+ if (intstat & SCSI_RESET_) {
+ amd_ScsiRstDetect(amd);
+ return;
+ }
+ if (intstat & (SUCCESSFUL_OP + SERVICE_REQUEST)) {
+ pSRB = amd->active_srb;
+ /*
+ * Run our state engine. First perform
+ * post processing for the last phase we
+ * were in, followed by any processing
+ * required to handle the current phase.
+ */
+ scsistat =
+ amd_SCSI_phase0[amd->last_phase](amd, pSRB, scsistat);
+ amd->last_phase = scsistat & SCSI_PHASE_MASK;
+ (void)amd_SCSI_phase1[amd->last_phase](amd, pSRB, scsistat);
+ }
+}
+
+static u_int
+amd_DataOutPhase0(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ struct amd_sg *psgl;
+ u_int32_t ResidCnt, xferCnt;
+
+ if (!(pSRB->SRBState & SRB_XFERPAD)) {
+ if (scsistat & PARITY_ERR) {
+ pSRB->SRBStatus |= PARITY_ERROR;
+ }
+ if (scsistat & COUNT_2_ZERO) {
+ while ((amd_read8(amd, DMA_Status)&DMA_XFER_DONE) == 0)
+ ;
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if (pSRB->SGIndex < pSRB->SGcount) {
+ pSRB->pSGlist++;
+ psgl = pSRB->pSGlist;
+ pSRB->SGPhysAddr = psgl->SGXPtr;
+ pSRB->SGToBeXferLen = psgl->SGXLen;
+ } else {
+ pSRB->SGToBeXferLen = 0;
+ }
+ } else {
+ ResidCnt = amd_read8(amd, CURRENTFIFOREG) & 0x1f;
+ ResidCnt += amd_read8(amd, CTCREG_LOW)
+ | (amd_read8(amd, CTCREG_MID) << 8)
+ | (amd_read8(amd, CURTXTCNTREG) << 16);
+
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+ }
+ }
+ amd_write8(amd, DMA_Cmd, WRITE_DIRECTION | DMA_IDLE_CMD);
+ return (scsistat);
+}
+
+static u_int
+amd_DataInPhase0(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ u_int8_t bval;
+ u_int16_t i, residual;
+ struct amd_sg *psgl;
+ u_int32_t ResidCnt, xferCnt;
+ u_int8_t * ptr;
+
+ if (!(pSRB->SRBState & SRB_XFERPAD)) {
+ if (scsistat & PARITY_ERR) {
+ pSRB->SRBStatus |= PARITY_ERROR;
+ }
+ if (scsistat & COUNT_2_ZERO) {
+ while (1) {
+ bval = amd_read8(amd, DMA_Status);
+ if ((bval & DMA_XFER_DONE) != 0)
+ break;
+ }
+ amd_write8(amd, DMA_Cmd, READ_DIRECTION|DMA_IDLE_CMD);
+
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if (pSRB->SGIndex < pSRB->SGcount) {
+ pSRB->pSGlist++;
+ psgl = pSRB->pSGlist;
+ pSRB->SGPhysAddr = psgl->SGXPtr;
+ pSRB->SGToBeXferLen = psgl->SGXLen;
+ } else {
+ pSRB->SGToBeXferLen = 0;
+ }
+ } else { /* phase changed */
+ residual = 0;
+ bval = amd_read8(amd, CURRENTFIFOREG);
+ while (bval & 0x1f) {
+ if ((bval & 0x1f) == 1) {
+ for (i = 0; i < 0x100; i++) {
+ bval = amd_read8(amd, CURRENTFIFOREG);
+ if (!(bval & 0x1f)) {
+ goto din_1;
+ } else if (i == 0x0ff) {
+ residual = 1;
+ goto din_1;
+ }
+ }
+ } else {
+ bval = amd_read8(amd, CURRENTFIFOREG);
+ }
+ }
+ din_1:
+ amd_write8(amd, DMA_Cmd, READ_DIRECTION|DMA_BLAST_CMD);
+ for (i = 0; i < 0x8000; i++) {
+ if ((amd_read8(amd, DMA_Status)&BLAST_COMPLETE))
+ break;
+ }
+ amd_write8(amd, DMA_Cmd, READ_DIRECTION|DMA_IDLE_CMD);
+
+ ResidCnt = amd_read8(amd, CTCREG_LOW)
+ | (amd_read8(amd, CTCREG_MID) << 8)
+ | (amd_read8(amd, CURTXTCNTREG) << 16);
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+ if (residual) {
+ /* get residual byte */
+ bval = amd_read8(amd, SCSIFIFOREG);
+ ptr = phystovirt(pSRB, xferCnt);
+ *ptr = bval;
+ pSRB->SGPhysAddr++;
+ pSRB->TotalXferredLen++;
+ pSRB->SGToBeXferLen--;
+ }
+ }
+ }
+ return (scsistat);
+}
+
+static u_int
+amd_StatusPhase0(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ pSRB->TargetStatus = amd_read8(amd, SCSIFIFOREG);
+ /* get message */
+ pSRB->EndMessage = amd_read8(amd, SCSIFIFOREG);
+ pSRB->SRBState = SRB_COMPLETED;
+ amd_write8(amd, SCSICMDREG, MSG_ACCEPTED_CMD);
+ return (SCSI_NOP0);
+}
+
+static u_int
+amd_MsgOutPhase0(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ if (pSRB->SRBState & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) {
+ scsistat = SCSI_NOP0;
+ }
+ return (scsistat);
+}
+
+static u_int
+amd_MsgInPhase0(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ int done;
+
+ amd->msgin_buf[amd->msgin_index] = amd_read8(amd, SCSIFIFOREG);
+
+ done = amdparsemsg(amd);
+ if (done)
+ amd->msgin_index = 0;
+ else
+ amd->msgin_index++;
+ return (SCSI_NOP0);
+}
+
+static int
+amdparsemsg(struct amd_softc *amd)
+{
+ struct amd_target_info *targ_info;
+ int reject;
+ int done;
+ int response;
+
+ done = FALSE;
+ response = FALSE;
+ reject = FALSE;
+
+ targ_info = &amd->tinfo[amd->cur_target];
+
+ /*
+ * Parse as much of the message as is availible,
+ * rejecting it if we don't support it. When
+ * the entire message is availible and has been
+ * handled, return TRUE indicating that we have
+ * parsed an entire message.
+ */
+ switch (amd->msgin_buf[0]) {
+ case MSG_DISCONNECT:
+ amd->active_srb->SRBState = SRB_DISCONNECT;
+ amd->disc_count[amd->cur_target][amd->cur_lun]++;
+ done = TRUE;
+ break;
+ case MSG_SIMPLE_Q_TAG:
+ {
+ struct amd_srb *disc_srb;
+
+ if (amd->msgin_index < 1)
+ break;
+ disc_srb = &amd->SRB_array[amd->msgin_buf[1]];
+ if (amd->active_srb != NULL
+ || disc_srb->SRBState != SRB_DISCONNECT
+ || disc_srb->pccb->ccb_h.target_id != amd->cur_target
+ || disc_srb->pccb->ccb_h.target_lun != amd->cur_lun) {
+ printf("amd%d: Unexpected tagged reselection "
+ "for target %d, Issuing Abort\n", amd->unit,
+ amd->cur_target);
+ amd->msgout_buf[0] = MSG_ABORT;
+ amd->msgout_len = 1;
+ response = TRUE;
+ break;
+ }
+ amd->active_srb = disc_srb;
+ amd->disc_count[amd->cur_target][amd->cur_lun]--;
+ done = TRUE;
+ break;
+ }
+ case MSG_MESSAGE_REJECT:
+ response = amdhandlemsgreject(amd);
+ if (response == FALSE)
+ amd_write8(amd, SCSICMDREG, RESET_ATN_CMD);
+ /* FALLTHROUGH */
+ case MSG_NOOP:
+ done = TRUE;
+ break;
+ case MSG_EXTENDED:
+ {
+ u_int clockrate;
+ u_int period;
+ u_int offset;
+ u_int saved_offset;
+
+ /* Wait for enough of the message to begin validation */
+ if (amd->msgin_index < 1)
+ break;
+ if (amd->msgin_buf[1] != MSG_EXT_SDTR_LEN) {
+ reject = TRUE;
+ break;
+ }
+
+ /* Wait for opcode */
+ if (amd->msgin_index < 2)
+ break;
+
+ if (amd->msgin_buf[2] != MSG_EXT_SDTR) {
+ reject = TRUE;
+ break;
+ }
+
+ /*
+ * Wait until we have both args before validating
+ * and acting on this message.
+ *
+ * Add one to MSG_EXT_SDTR_LEN to account for
+ * the extended message preamble.
+ */
+ if (amd->msgin_index < (MSG_EXT_SDTR_LEN + 1))
+ break;
+
+ period = amd->msgin_buf[3];
+ saved_offset = offset = amd->msgin_buf[4];
+ clockrate = amdfindclockrate(amd, &period);
+ if (offset > AMD_MAX_SYNC_OFFSET)
+ offset = AMD_MAX_SYNC_OFFSET;
+ if (period == 0 || offset == 0) {
+ offset = 0;
+ period = 0;
+ clockrate = 0;
+ }
+ amdsetsync(amd, amd->cur_target, clockrate, period, offset,
+ AMD_TRANS_ACTIVE|AMD_TRANS_GOAL);
+
+ /*
+ * See if we initiated Sync Negotiation
+ * and didn't have to fall down to async
+ * transfers.
+ */
+ if (amdsentmsg(amd, MSG_EXT_SDTR, /*full*/TRUE)) {
+ /* We started it */
+ if (saved_offset != offset) {
+ /* Went too low - force async */
+ reject = TRUE;
+ }
+ } else {
+ /*
+ * Send our own SDTR in reply
+ */
+ if (bootverbose)
+ printf("Sending SDTR!\n");
+ amd->msgout_index = 0;
+ amd->msgout_len = 0;
+ amdconstructsdtr(amd, period, offset);
+ amd->msgout_index = 0;
+ response = TRUE;
+ }
+ done = TRUE;
+ break;
+ }
+ case MSG_SAVEDATAPOINTER:
+ case MSG_RESTOREPOINTERS:
+ /* XXX Implement!!! */
+ done = TRUE;
+ break;
+ default:
+ reject = TRUE;
+ break;
+ }
+
+ if (reject) {
+ amd->msgout_index = 0;
+ amd->msgout_len = 1;
+ amd->msgout_buf[0] = MSG_MESSAGE_REJECT;
+ done = TRUE;
+ response = TRUE;
+ }
+
+ if (response)
+ amd_write8(amd, SCSICMDREG, SET_ATN_CMD);
+
+ if (done && !response)
+ /* Clear the outgoing message buffer */
+ amd->msgout_len = 0;
+
+ /* Drop Ack */
+ amd_write8(amd, SCSICMDREG, MSG_ACCEPTED_CMD);
+
+ return (done);
+}
+
+static u_int
+amdfindclockrate(struct amd_softc *amd, u_int *period)
+{
+ u_int i;
+ u_int clockrate;
+
+ for (i = 0; i < sizeof(tinfo_sync_period); i++) {
+ u_int8_t *table_entry;
+
+ table_entry = &tinfo_sync_period[i];
+ if (*period <= *table_entry) {
+ /*
+ * When responding to a target that requests
+ * sync, the requested rate may fall between
+ * two rates that we can output, but still be
+ * a rate that we can receive. Because of this,
+ * we want to respond to the target with
+ * the same rate that it sent to us even
+ * if the period we use to send data to it
+ * is lower. Only lower the response period
+ * if we must.
+ */
+ if (i == 0) {
+ *period = *table_entry;
+ }
+ break;
+ }
+ }
+
+ if (i == sizeof(tinfo_sync_period)) {
+ /* Too slow for us. Use asnyc transfers. */
+ *period = 0;
+ clockrate = 0;
+ } else
+ clockrate = i + 4;
+
+ return (clockrate);
+}
+
+/*
+ * See if we sent a particular extended message to the target.
+ * If "full" is true, the target saw the full message.
+ * If "full" is false, the target saw at least the first
+ * byte of the message.
+ */
+static int
+amdsentmsg(struct amd_softc *amd, u_int msgtype, int full)
+{
+ int found;
+ int index;
+
+ found = FALSE;
+ index = 0;
+
+ while (index < amd->msgout_len) {
+ if ((amd->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0
+ || amd->msgout_buf[index] == MSG_MESSAGE_REJECT)
+ index++;
+ else if (amd->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
+ && amd->msgout_buf[index] < MSG_IGN_WIDE_RESIDUE) {
+ /* Skip tag type and tag id */
+ index += 2;
+ } else if (amd->msgout_buf[index] == MSG_EXTENDED) {
+ /* Found a candidate */
+ if (amd->msgout_buf[index+2] == msgtype) {
+ u_int end_index;
+
+ end_index = index + 1
+ + amd->msgout_buf[index + 1];
+ if (full) {
+ if (amd->msgout_index > end_index)
+ found = TRUE;
+ } else if (amd->msgout_index > index)
+ found = TRUE;
+ }
+ break;
+ } else {
+ panic("amdsentmsg: Inconsistent msg buffer");
+ }
+ }
+ return (found);
+}
+
+static void
+amdconstructsdtr(struct amd_softc *amd, u_int period, u_int offset)
+{
+ amd->msgout_buf[amd->msgout_index++] = MSG_EXTENDED;
+ amd->msgout_buf[amd->msgout_index++] = MSG_EXT_SDTR_LEN;
+ amd->msgout_buf[amd->msgout_index++] = MSG_EXT_SDTR;
+ amd->msgout_buf[amd->msgout_index++] = period;
+ amd->msgout_buf[amd->msgout_index++] = offset;
+ amd->msgout_len += 5;
+}
+
+static int
+amdhandlemsgreject(struct amd_softc *amd)
+{
+ /*
+ * If we had an outstanding SDTR for this
+ * target, this is a signal that the target
+ * is refusing negotiation. Also watch out
+ * for rejected tag messages.
+ */
+ struct amd_srb *srb;
+ struct amd_target_info *targ_info;
+ int response = FALSE;
+
+ srb = amd->active_srb;
+ targ_info = &amd->tinfo[amd->cur_target];
+ if (amdsentmsg(amd, MSG_EXT_SDTR, /*full*/FALSE)) {
+ /* note asynch xfers and clear flag */
+ amdsetsync(amd, amd->cur_target, /*clockrate*/0,
+ /*period*/0, /*offset*/0,
+ AMD_TRANS_ACTIVE|AMD_TRANS_GOAL);
+ printf("amd%d:%d: refuses synchronous negotiation. "
+ "Using asynchronous transfers\n",
+ amd->unit, amd->cur_target);
+ } else if ((srb != NULL)
+ && (srb->pccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
+ struct ccb_trans_settings neg;
+
+ printf("amd%d:%d: refuses tagged commands. Performing "
+ "non-tagged I/O\n", amd->unit, amd->cur_target);
+
+ amdsettags(amd, amd->cur_target, FALSE);
+ neg.flags = 0;
+ neg.valid = CCB_TRANS_TQ_VALID;
+ xpt_setup_ccb(&neg.ccb_h, srb->pccb->ccb_h.path, /*priority*/1);
+ xpt_async(AC_TRANSFER_NEG, srb->pccb->ccb_h.path, &neg);
+
+ /*
+ * Resend the identify for this CCB as the target
+ * may believe that the selection is invalid otherwise.
+ */
+ if (amd->msgout_len != 0)
+ bcopy(&amd->msgout_buf[0], &amd->msgout_buf[1],
+ amd->msgout_len);
+ amd->msgout_buf[0] = MSG_IDENTIFYFLAG
+ | srb->pccb->ccb_h.target_lun;
+ amd->msgout_len++;
+ if ((targ_info->disc_tag & AMD_CUR_DISCENB) != 0
+ && (srb->pccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0)
+ amd->msgout_buf[0] |= MSG_IDENTIFY_DISCFLAG;
+
+ srb->pccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID;
+
+ /*
+ * Requeue all tagged commands for this target
+ * currently in our posession so they can be
+ * converted to untagged commands.
+ */
+ amdcompletematch(amd, amd->cur_target, amd->cur_lun,
+ AMD_TAG_WILDCARD, &amd->waiting_srbs,
+ CAM_DEV_QFRZN|CAM_REQUEUE_REQ);
+ } else {
+ /*
+ * Otherwise, we ignore it.
+ */
+ printf("amd%d:%d: Message reject received -- ignored\n",
+ amd->unit, amd->cur_target);
+ }
+ return (response);
+}
+
+#if 0
+ if (!(pSRB->SRBState & SRB_MSGIN_MULTI)) {
+ if (bval == MSG_DISCONNECT) {
+ pSRB->SRBState = SRB_DISCONNECT;
+ } else if (bval == MSG_SAVEDATAPOINTER) {
+ goto min6;
+ } else if ((bval == MSG_EXTENDED)
+ || ((bval >= MSG_SIMPLE_Q_TAG)
+ && (bval <= MSG_ORDERED_Q_TAG))) {
+ pSRB->SRBState |= SRB_MSGIN_MULTI;
+ pSRB->MsgInBuf[0] = bval;
+ pSRB->MsgCnt = 1;
+ pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+ } else if (bval == MSG_MESSAGE_REJECT) {
+ amd_write8(amd, SCSICMDREG, RESET_ATN_CMD);
+
+ if (pSRB->SRBState & DO_SYNC_NEGO) {
+ goto set_async;
+ }
+ } else if (bval == MSG_RESTOREPOINTERS) {
+ goto min6;
+ } else {
+ goto min6;
+ }
+ } else { /* minx: */
+ *pSRB->pMsgPtr = bval;
+ pSRB->MsgCnt++;
+ pSRB->pMsgPtr++;
+ if ((pSRB->MsgInBuf[0] >= MSG_SIMPLE_Q_TAG)
+ && (pSRB->MsgInBuf[0] <= MSG_ORDERED_Q_TAG)) {
+ if (pSRB->MsgCnt == 2) {
+ pSRB->SRBState = 0;
+ pSRB = &amd->SRB_array[pSRB->MsgInBuf[1]];
+ if (pSRB->SRBState & SRB_DISCONNECT) == 0) {
+ pSRB = amd->pTmpSRB;
+ pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+ EnableMsgOut2(amd, pSRB);
+ } else {
+ if (pDCB->DCBFlag & ABORT_DEV_) {
+ pSRB->SRBState = SRB_ABORT_SENT;
+ EnableMsgOut1(amd, pSRB);
+ }
+ pDCB->pActiveSRB = pSRB;
+ pSRB->SRBState = SRB_DATA_XFER;
+ }
+ }
+ } else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED)
+ && (pSRB->MsgCnt == 5)) {
+ pSRB->SRBState &= ~(SRB_MSGIN_MULTI + DO_SYNC_NEGO);
+ if ((pSRB->MsgInBuf[1] != 3)
+ || (pSRB->MsgInBuf[2] != 1)) { /* reject_msg: */
+ pSRB->MsgCnt = 1;
+ pSRB->MsgInBuf[0] = MSG_MESSAGE_REJECT;
+ amd_write8(amd, SCSICMDREG, SET_ATN_CMD);
+ } else if (!(pSRB->MsgInBuf[3])
+ || !(pSRB->MsgInBuf[4])) {
+ set_async: /* set async */
+
+ pDCB = pSRB->pSRBDCB;
+ /* disable sync & sync nego */
+ pDCB->SyncMode &= ~(SYNC_ENABLE|SYNC_NEGO_DONE);
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+
+ pDCB->tinfo.goal.period = 0;
+ pDCB->tinfo.goal.offset = 0;
+
+ pDCB->tinfo.current.period = 0;
+ pDCB->tinfo.current.offset = 0;
+ pDCB->tinfo.current.width =
+ MSG_EXT_WDTR_BUS_8_BIT;
+
+ pDCB->CtrlR3 = FAST_CLK; /* non_fast */
+ pDCB->CtrlR4 &= 0x3f;
+ pDCB->CtrlR4 |= EATER_25NS;
+ goto re_prog;
+ } else {/* set sync */
+
+ pDCB = pSRB->pSRBDCB;
+ /* enable sync & sync nego */
+ pDCB->SyncMode |= SYNC_ENABLE|SYNC_NEGO_DONE;
+
+ /* set sync offset */
+ pDCB->SyncOffset &= 0x0f0;
+ pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+
+ /* set sync period */
+ pDCB->MaxNegoPeriod = pSRB->MsgInBuf[3];
+
+ wval = (u_int16_t) pSRB->MsgInBuf[3];
+ wval = wval << 2;
+ wval--;
+ wval1 = wval / 25;
+ if ((wval1 * 25) != wval) {
+ wval1++;
+ }
+ bval = FAST_CLK|FAST_SCSI;
+ pDCB->CtrlR4 &= 0x3f;
+ if (wval1 >= 8) {
+ /* Fast SCSI */
+ wval1--;
+ bval = FAST_CLK;
+ pDCB->CtrlR4 |= EATER_25NS;
+ }
+ pDCB->CtrlR3 = bval;
+ pDCB->SyncPeriod = (u_int8_t) wval1;
+
+ pDCB->tinfo.goal.period =
+ tinfo_sync_period[pDCB->SyncPeriod - 4];
+ pDCB->tinfo.goal.offset = pDCB->SyncOffset;
+ pDCB->tinfo.current.period =
+ tinfo_sync_period[pDCB->SyncPeriod - 4];;
+ pDCB->tinfo.current.offset = pDCB->SyncOffset;
+
+ /*
+ * program SCSI control register
+ */
+ re_prog:
+ amd_write8(amd, SYNCPERIOREG, pDCB->SyncPeriod);
+ amd_write8(amd, SYNCOFFREG, pDCB->SyncOffset);
+ amd_write8(amd, CNTLREG3, pDCB->CtrlR3);
+ amd_write8(amd, CNTLREG4, pDCB->CtrlR4);
+ }
+ }
+ }
+min6:
+ amd_write8(amd, SCSICMDREG, MSG_ACCEPTED_CMD);
+ return (SCSI_NOP0);
+}
+#endif
+
+static u_int
+amd_DataOutPhase1(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ DataIO_Comm(amd, pSRB, WRITE_DIRECTION);
+ return (scsistat);
+}
+
+static u_int
+amd_DataInPhase1(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ DataIO_Comm(amd, pSRB, READ_DIRECTION);
+ return (scsistat);
+}
+
+static void
+DataIO_Comm(struct amd_softc *amd, struct amd_srb *pSRB, u_int ioDir)
+{
+ struct amd_sg * psgl;
+ u_int32_t lval;
+
+ if (pSRB->SGIndex < pSRB->SGcount) {
+ amd_write8(amd, DMA_Cmd, DMA_IDLE_CMD|ioDir);/* |EN_DMA_INT */
+
+ if (!pSRB->SGToBeXferLen) {
+ psgl = pSRB->pSGlist;
+ pSRB->SGPhysAddr = psgl->SGXPtr;
+ pSRB->SGToBeXferLen = psgl->SGXLen;
+ }
+ lval = pSRB->SGToBeXferLen;
+ amd_write8(amd, CTCREG_LOW, lval);
+ amd_write8(amd, CTCREG_MID, lval >> 8);
+ amd_write8(amd, CURTXTCNTREG, lval >> 16);
+
+ amd_write32(amd, DMA_XferCnt, pSRB->SGToBeXferLen);
+
+ amd_write32(amd, DMA_XferAddr, pSRB->SGPhysAddr);
+
+ pSRB->SRBState = SRB_DATA_XFER;
+
+ amd_write8(amd, SCSICMDREG, DMA_COMMAND|INFO_XFER_CMD);
+
+ amd_write8(amd, DMA_Cmd, DMA_IDLE_CMD|ioDir); /* |EN_DMA_INT */
+
+ amd_write8(amd, DMA_Cmd, DMA_START_CMD|ioDir);/* |EN_DMA_INT */
+ } else { /* xfer pad */
+ if (pSRB->SGcount) {
+ pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+ pSRB->SRBStatus |= OVER_RUN;
+ }
+ amd_write8(amd, CTCREG_LOW, 0);
+ amd_write8(amd, CTCREG_MID, 0);
+ amd_write8(amd, CURTXTCNTREG, 0);
+
+ pSRB->SRBState |= SRB_XFERPAD;
+ amd_write8(amd, SCSICMDREG, DMA_COMMAND|XFER_PAD_BYTE);
+ }
+}
+
+static u_int
+amd_CommandPhase1(struct amd_softc *amd, struct amd_srb *srb, u_int scsistat)
+{
+ amd_write8(amd, SCSICMDREG, RESET_ATN_CMD);
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+
+ amdsetupcommand(amd, srb);
+
+ srb->SRBState = SRB_COMMAND;
+ amd_write8(amd, SCSICMDREG, INFO_XFER_CMD);
+ return (scsistat);
+}
+
+static u_int
+amd_StatusPhase1(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+ pSRB->SRBState = SRB_STATUS;
+ amd_write8(amd, SCSICMDREG, INITIATOR_CMD_CMPLTE);
+ return (scsistat);
+}
+
+static u_int
+amd_MsgOutPhase1(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+
+ if (amd->msgout_len == 0) {
+ amd->msgout_buf[0] = MSG_NOOP;
+ amd->msgout_len = 1;
+ }
+ amd_write8_multi(amd, SCSIFIFOREG, amd->msgout_buf, amd->msgout_len);
+ amd_write8(amd, SCSICMDREG, INFO_XFER_CMD);
+ return (scsistat);
+}
+
+static u_int
+amd_MsgInPhase1(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+ amd_write8(amd, SCSICMDREG, INFO_XFER_CMD);
+ return (scsistat);
+}
+
+static u_int
+amd_NopPhase(struct amd_softc *amd, struct amd_srb *pSRB, u_int scsistat)
+{
+ return (scsistat);
+}
+
+static void
+amd_Disconnect(struct amd_softc * amd)
+{
+ struct amd_srb *srb;
+ int target;
+ int lun;
+
+ srb = amd->active_srb;
+ amd->active_srb = NULL;
+ amd->last_phase = SCSI_BUS_FREE;
+ amd_write8(amd, SCSICMDREG, EN_SEL_RESEL);
+ target = amd->cur_target;
+ lun = amd->cur_lun;
+
+ if (srb == NULL) {
+ /* Invalid reselection */
+ amdrunwaiting(amd);
+ } else if (srb->SRBState & SRB_ABORT_SENT) {
+ /* Clean up and done this srb */
+#if 0
+ while (( = TAILQ_FIRST(&amd->running_srbs)) != NULL) {
+ /* XXX What about "done'ing" these srbs??? */
+ if (pSRB->pSRBDCB == pDCB) {
+ TAILQ_REMOVE(&amd->running_srbs, pSRB, links);
+ TAILQ_INSERT_HEAD(&amd->free_srbs, pSRB, links);
+ }
+ }
+ amdrunwaiting(amd);
+#endif
+ } else {
+ if ((srb->SRBState & (SRB_START | SRB_MSGOUT))
+ || !(srb->SRBState & (SRB_DISCONNECT | SRB_COMPLETED))) {
+ srb->TargetStatus = AMD_SCSI_STAT_SEL_TIMEOUT;
+ goto disc1;
+ } else if (srb->SRBState & SRB_DISCONNECT) {
+ if (!(srb->pccb->ccb_h.flags & CAM_TAG_ACTION_VALID))
+ amd->untagged_srbs[target][lun] = srb;
+ amdrunwaiting(amd);
+ } else if (srb->SRBState & SRB_COMPLETED) {
+ disc1:
+ srb->SRBState = SRB_FREE;
+ SRBdone(amd, srb);
+ }
+ }
+ return;
+}
+
+static void
+amd_Reselect(struct amd_softc *amd)
+{
+ struct amd_target_info *tinfo;
+ u_int16_t disc_count;
+
+ amd_clear_msg_state(amd);
+ if (amd->active_srb != NULL) {
+ /* Requeue the SRB for our attempted Selection */
+ TAILQ_REMOVE(&amd->running_srbs, amd->active_srb, links);
+ TAILQ_INSERT_HEAD(&amd->waiting_srbs, amd->active_srb, links);
+ amd->active_srb = NULL;
+ }
+ /* get ID */
+ amd->cur_target = amd_read8(amd, SCSIFIFOREG);
+ amd->cur_target ^= amd->HostID_Bit;
+ amd->cur_target = ffs(amd->cur_target) - 1;
+ amd->cur_lun = amd_read8(amd, SCSIFIFOREG) & 7;
+ tinfo = &amd->tinfo[amd->cur_target];
+ amd->active_srb = amd->untagged_srbs[amd->cur_target][amd->cur_lun];
+ disc_count = amd->disc_count[amd->cur_target][amd->cur_lun];
+ if (disc_count == 0) {
+ printf("amd%d: Unexpected reselection for target %d, "
+ "Issuing Abort\n", amd->unit, amd->cur_target);
+ amd->msgout_buf[0] = MSG_ABORT;
+ amd->msgout_len = 1;
+ amd_write8(amd, SCSICMDREG, SET_ATN_CMD);
+ }
+ if (amd->active_srb != NULL) {
+ amd->disc_count[amd->cur_target][amd->cur_lun]--;
+ amd->untagged_srbs[amd->cur_target][amd->cur_lun] = NULL;
+ }
+
+ amd_write8(amd, SCSIDESTIDREG, amd->cur_target);
+ amd_write8(amd, SYNCPERIOREG, tinfo->sync_period_reg);
+ amd_write8(amd, SYNCOFFREG, tinfo->sync_offset_reg);
+ amd_write8(amd, CNTLREG1, tinfo->CtrlR1);
+ amd_write8(amd, CNTLREG3, tinfo->CtrlR3);
+ amd_write8(amd, CNTLREG4, tinfo->CtrlR4);
+ amd_write8(amd, SCSICMDREG, MSG_ACCEPTED_CMD);/* drop /ACK */
+ amd->last_phase = SCSI_NOP0;
+}
+
+static void
+SRBdone(struct amd_softc *amd, struct amd_srb *pSRB)
+{
+ u_int8_t bval, i, status;
+ union ccb *pccb;
+ struct ccb_scsiio *pcsio;
+ int intflag;
+ struct amd_sg *ptr2;
+ u_int32_t swlval;
+ u_int target_id, target_lun;
+
+ pccb = pSRB->pccb;
+ pcsio = &pccb->csio;
+ target_id = pSRB->pccb->ccb_h.target_id;
+ target_lun = pSRB->pccb->ccb_h.target_lun;
+
+ CAM_DEBUG(pccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("SRBdone - TagNumber %d\n", pSRB->TagNumber));
+
+ if ((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ bus_dmasync_op_t op;
+
+ if ((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_POSTREAD;
+ else
+ op = BUS_DMASYNC_POSTWRITE;
+ bus_dmamap_sync(amd->buffer_dmat, pSRB->dmamap, op);
+ bus_dmamap_unload(amd->buffer_dmat, pSRB->dmamap);
+ }
+
+ status = pSRB->TargetStatus;
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ pccb->ccb_h.status = CAM_REQ_CMP;
+ if (pSRB->SRBFlag & AUTO_REQSENSE) {
+ pSRB->SRBFlag &= ~AUTO_REQSENSE;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = SCSI_STATUS_CHECK_COND;
+
+ if (status == SCSI_STATUS_CHECK_COND) {
+ pccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ goto ckc_e;
+ }
+ *((u_int32_t *)&(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+
+ pcsio->sense_resid = pcsio->sense_len
+ - pSRB->TotalXferredLen;
+ pSRB->TotalXferredLen = pSRB->Segment1[1];
+ if (pSRB->TotalXferredLen) {
+ /* ???? */
+ pcsio->resid = pcsio->dxfer_len
+ - pSRB->TotalXferredLen;
+ /* The resid field contains valid data */
+ /* Flush resid bytes on complete */
+ } else {
+ pcsio->scsi_status = SCSI_STATUS_CHECK_COND;
+ }
+ pccb->ccb_h.status = CAM_AUTOSNS_VALID|CAM_SCSI_STATUS_ERROR;
+ goto ckc_e;
+ }
+ if (status) {
+ if (status == SCSI_STATUS_CHECK_COND) {
+
+ if ((pSRB->SGIndex < pSRB->SGcount)
+ && (pSRB->SGcount) && (pSRB->SGToBeXferLen)) {
+ bval = pSRB->SGcount;
+ swlval = pSRB->SGToBeXferLen;
+ ptr2 = pSRB->pSGlist;
+ ptr2++;
+ for (i = pSRB->SGIndex + 1; i < bval; i++) {
+ swlval += ptr2->SGXLen;
+ ptr2++;
+ }
+ /* ??????? */
+ pcsio->resid = (u_int32_t) swlval;
+
+#ifdef AMD_DEBUG0
+ printf("XferredLen=%8x,NotYetXferLen=%8x,",
+ pSRB->TotalXferredLen, swlval);
+#endif
+ }
+ if ((pcsio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
+#ifdef AMD_DEBUG0
+ printf("RequestSense..................\n");
+#endif
+ RequestSense(amd, pSRB);
+ return;
+ }
+ pcsio->scsi_status = SCSI_STATUS_CHECK_COND;
+ pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ goto ckc_e;
+ } else if (status == SCSI_STATUS_QUEUE_FULL) {
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pcsio->scsi_status = SCSI_STATUS_QUEUE_FULL;
+ pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ goto ckc_e;
+ } else if (status == AMD_SCSI_STAT_SEL_TIMEOUT) {
+ pSRB->AdaptStatus = H_SEL_TIMEOUT;
+ pSRB->TargetStatus = 0;
+
+ pcsio->scsi_status = AMD_SCSI_STAT_SEL_TIMEOUT;
+ pccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ } else if (status == SCSI_STATUS_BUSY) {
+#ifdef AMD_DEBUG0
+ printf("DC390: target busy at %s %d\n",
+ __FILE__, __LINE__);
+#endif
+ pcsio->scsi_status = SCSI_STATUS_BUSY;
+ pccb->ccb_h.status = CAM_SCSI_BUSY;
+ } else if (status == SCSI_STATUS_RESERV_CONFLICT) {
+#ifdef AMD_DEBUG0
+ printf("DC390: target reserved at %s %d\n",
+ __FILE__, __LINE__);
+#endif
+ pcsio->scsi_status = SCSI_STATUS_RESERV_CONFLICT;
+ pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; /* XXX */
+ } else {
+ pSRB->AdaptStatus = 0;
+#ifdef AMD_DEBUG0
+ printf("DC390: driver stuffup at %s %d\n",
+ __FILE__, __LINE__);
+#endif
+ pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ }
+ } else {
+ status = pSRB->AdaptStatus;
+ if (status & H_OVER_UNDER_RUN) {
+ pSRB->TargetStatus = 0;
+
+ pccb->ccb_h.status = CAM_DATA_RUN_ERR;
+ } else if (pSRB->SRBStatus & PARITY_ERROR) {
+#ifdef AMD_DEBUG0
+ printf("DC390: driver stuffup %s %d\n",
+ __FILE__, __LINE__);
+#endif
+ /* Driver failed to perform operation */
+ pccb->ccb_h.status = CAM_UNCOR_PARITY;
+ } else { /* No error */
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pcsio->resid = 0;
+ /* there is no error, (sense is invalid) */
+ }
+ }
+ckc_e:
+ intflag = splcam();
+ if ((pccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ /* CAM request not yet complete =>device_Q frozen */
+ xpt_freeze_devq(pccb->ccb_h.path, 1);
+ pccb->ccb_h.status |= CAM_DEV_QFRZN;
+ }
+ TAILQ_REMOVE(&amd->running_srbs, pSRB, links);
+ TAILQ_INSERT_HEAD(&amd->free_srbs, pSRB, links);
+ amdrunwaiting(amd);
+ splx(intflag);
+ xpt_done(pccb);
+
+}
+
+static void
+amd_ResetSCSIBus(struct amd_softc * amd)
+{
+ int intflag;
+
+ intflag = splcam();
+ amd->ACBFlag |= RESET_DEV;
+ amd_write8(amd, DMA_Cmd, DMA_IDLE_CMD);
+ amd_write8(amd, SCSICMDREG, RST_SCSI_BUS_CMD);
+ splx(intflag);
+ return;
+}
+
+static void
+amd_ScsiRstDetect(struct amd_softc * amd)
+{
+ int intflag;
+ u_int32_t wlval;
+
+#ifdef AMD_DEBUG0
+ printf("amd_ScsiRstDetect \n");
+#endif
+
+ wlval = 1000;
+ while (--wlval) { /* delay 1 sec */
+ DELAY(1000);
+ }
+ intflag = splcam();
+
+ amd_write8(amd, DMA_Cmd, DMA_IDLE_CMD);
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+
+ if (amd->ACBFlag & RESET_DEV) {
+ amd->ACBFlag |= RESET_DONE;
+ } else {
+ amd->ACBFlag |= RESET_DETECT;
+ ResetDevParam(amd);
+ amdcompletematch(amd, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD,
+ AMD_TAG_WILDCARD, &amd->running_srbs,
+ CAM_DEV_QFRZN|CAM_SCSI_BUS_RESET);
+ amdcompletematch(amd, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD,
+ AMD_TAG_WILDCARD, &amd->waiting_srbs,
+ CAM_DEV_QFRZN|CAM_SCSI_BUS_RESET);
+ amd->active_srb = NULL;
+ amd->ACBFlag = 0;
+ amdrunwaiting(amd);
+ }
+ splx(intflag);
+ return;
+}
+
+static void
+RequestSense(struct amd_softc *amd, struct amd_srb *pSRB)
+{
+ union ccb *pccb;
+ struct ccb_scsiio *pcsio;
+
+ pccb = pSRB->pccb;
+ pcsio = &pccb->csio;
+
+ pSRB->SRBFlag |= AUTO_REQSENSE;
+ pSRB->Segment0[0] = *((u_int32_t *) & (pSRB->CmdBlock[0]));
+ pSRB->Segment0[1] = *((u_int32_t *) & (pSRB->CmdBlock[4]));
+ pSRB->Segment1[0] = (pSRB->ScsiCmdLen << 8) + pSRB->SGcount;
+ pSRB->Segment1[1] = pSRB->TotalXferredLen;
+
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+
+ pSRB->Segmentx.SGXPtr = (u_int32_t) vtophys(&pcsio->sense_data);
+ pSRB->Segmentx.SGXLen = (u_int32_t) pcsio->sense_len;
+
+ pSRB->pSGlist = &pSRB->Segmentx;
+ pSRB->SGcount = 1;
+ pSRB->SGIndex = 0;
+
+ *((u_int32_t *) & (pSRB->CmdBlock[0])) = 0x00000003;
+ pSRB->CmdBlock[1] = pSRB->pccb->ccb_h.target_lun << 5;
+ *((u_int16_t *) & (pSRB->CmdBlock[4])) = pcsio->sense_len;
+ pSRB->ScsiCmdLen = 6;
+
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if (amdstart(amd, pSRB) != 0) {
+ TAILQ_REMOVE(&amd->running_srbs, pSRB, links);
+ TAILQ_INSERT_HEAD(&amd->waiting_srbs, pSRB, links);
+ }
+}
+
+static void
+amd_InvalidCmd(struct amd_softc * amd)
+{
+ struct amd_srb *srb;
+
+ srb = amd->active_srb;
+ if (srb->SRBState & (SRB_START|SRB_MSGOUT))
+ amd_write8(amd, SCSICMDREG, CLEAR_FIFO_CMD);
+}
+
+void
+amd_linkSRB(struct amd_softc *amd)
+{
+ u_int16_t count, i;
+ struct amd_srb *psrb;
+
+ count = amd->SRBCount;
+
+ for (i = 0; i < count; i++) {
+ psrb = (struct amd_srb *)&amd->SRB_array[i];
+ psrb->TagNumber = i;
+ TAILQ_INSERT_TAIL(&amd->free_srbs, psrb, links);
+ }
+}
+
+void
+amd_EnDisableCE(struct amd_softc *amd, int mode, int *regval)
+{
+ if (mode == ENABLE_CE) {
+ *regval = 0xc0;
+ } else {
+ *regval = 0x80;
+ }
+ pci_write_config(amd->dev, *regval, 0, /*bytes*/1);
+ if (mode == DISABLE_CE) {
+ pci_write_config(amd->dev, *regval, 0, /*bytes*/1);
+ }
+ DELAY(160);
+}
+
+void
+amd_EEpromOutDI(struct amd_softc *amd, int *regval, int Carry)
+{
+ u_int bval;
+
+ bval = 0;
+ if (Carry) {
+ bval = 0x40;
+ *regval = 0x80;
+ pci_write_config(amd->dev, *regval, bval, /*bytes*/1);
+ }
+ DELAY(160);
+ bval |= 0x80;
+ pci_write_config(amd->dev, *regval, bval, /*bytes*/1);
+ DELAY(160);
+ pci_write_config(amd->dev, *regval, 0, /*bytes*/1);
+ DELAY(160);
+}
+
+static int
+amd_EEpromInDO(struct amd_softc *amd)
+{
+ pci_write_config(amd->dev, 0x80, 0x80, /*bytes*/1);
+ DELAY(160);
+ pci_write_config(amd->dev, 0x80, 0x40, /*bytes*/1);
+ DELAY(160);
+ if (pci_read_config(amd->dev, 0, /*bytes*/1) == 0x22)
+ return (1);
+ return (0);
+}
+
+static u_int16_t
+EEpromGetData1(struct amd_softc *amd)
+{
+ u_int i;
+ u_int carryFlag;
+ u_int16_t wval;
+
+ wval = 0;
+ for (i = 0; i < 16; i++) {
+ wval <<= 1;
+ carryFlag = amd_EEpromInDO(amd);
+ wval |= carryFlag;
+ }
+ return (wval);
+}
+
+static void
+amd_Prepare(struct amd_softc *amd, int *regval, u_int8_t EEpromCmd)
+{
+ u_int i, j;
+ int carryFlag;
+
+ carryFlag = 1;
+ j = 0x80;
+ for (i = 0; i < 9; i++) {
+ amd_EEpromOutDI(amd, regval, carryFlag);
+ carryFlag = (EEpromCmd & j) ? 1 : 0;
+ j >>= 1;
+ }
+}
+
+static void
+amd_ReadEEprom(struct amd_softc *amd)
+{
+ int regval;
+ u_int i;
+ u_int16_t *ptr;
+ u_int8_t cmd;
+
+ ptr = (u_int16_t *)&amd->eepromBuf[0];
+ cmd = EEPROM_READ;
+ for (i = 0; i < 0x40; i++) {
+ amd_EnDisableCE(amd, ENABLE_CE, &regval);
+ amd_Prepare(amd, &regval, cmd);
+ *ptr = EEpromGetData1(amd);
+ ptr++;
+ cmd++;
+ amd_EnDisableCE(amd, DISABLE_CE, &regval);
+ }
+}
+
+static void
+amd_load_defaults(struct amd_softc *amd)
+{
+ int target;
+
+ bzero(&amd->eepromBuf, sizeof amd->eepromBuf);
+ for (target = 0; target < MAX_SCSI_ID; target++)
+ amd->eepromBuf[target << 2] =
+ (TAG_QUEUING|EN_DISCONNECT|SYNC_NEGO|PARITY_CHK);
+ amd->eepromBuf[EE_ADAPT_SCSI_ID] = 7;
+ amd->eepromBuf[EE_MODE2] = ACTIVE_NEGATION|LUN_CHECK|GREATER_1G;
+ amd->eepromBuf[EE_TAG_CMD_NUM] = 4;
+}
+
+static void
+amd_load_eeprom_or_defaults(struct amd_softc *amd)
+{
+ u_int16_t wval, *ptr;
+ u_int8_t i;
+
+ amd_ReadEEprom(amd);
+ wval = 0;
+ ptr = (u_int16_t *) & amd->eepromBuf[0];
+ for (i = 0; i < EE_DATA_SIZE; i += 2, ptr++)
+ wval += *ptr;
+
+ if (wval != EE_CHECKSUM) {
+ if (bootverbose)
+ printf("amd%d: SEEPROM data unavailable. "
+ "Using default device parameters.\n",
+ amd->unit);
+ amd_load_defaults(amd);
+ }
+}
+
+/*
+ **********************************************************************
+ * Function : static int amd_init (struct Scsi_Host *host)
+ * Purpose : initialize the internal structures for a given SCSI host
+ * Inputs : host - pointer to this host adapter's structure/
+ **********************************************************************
+ */
+static int
+amd_init(device_t dev)
+{
+ struct amd_softc *amd = device_get_softc(dev);
+ struct resource *iores;
+ int i, rid;
+ u_int bval;
+
+ rid = PCI_BASE_ADDR0;
+ iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (iores == NULL) {
+ if (bootverbose)
+ printf("amd_init: bus_alloc_resource failure!\n");
+ return ENXIO;
+ }
+ amd->tag = rman_get_bustag(iores);
+ amd->bsh = rman_get_bushandle(iores);
+
+ /* DMA tag for mapping buffers into device visible space. */
+ if (bus_dma_tag_create(/*parent_dmat*/NULL, /*alignment*/1,
+ /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/MAXBSIZE, /*nsegments*/AMD_NSEG,
+ /*maxsegsz*/AMD_MAXTRANSFER_SIZE,
+ /*flags*/BUS_DMA_ALLOCNOW,
+ &amd->buffer_dmat) != 0) {
+ if (bootverbose)
+ printf("amd_init: bus_dma_tag_create failure!\n");
+ return ENXIO;
+ }
+ TAILQ_INIT(&amd->free_srbs);
+ TAILQ_INIT(&amd->running_srbs);
+ TAILQ_INIT(&amd->waiting_srbs);
+ amd->last_phase = SCSI_BUS_FREE;
+ amd->dev = dev;
+ amd->unit = device_get_unit(dev);
+ amd->SRBCount = MAX_SRB_CNT;
+ amd->status = 0;
+ amd_load_eeprom_or_defaults(amd);
+ amd->max_id = 7;
+ if (amd->eepromBuf[EE_MODE2] & LUN_CHECK) {
+ amd->max_lun = 7;
+ } else {
+ amd->max_lun = 0;
+ }
+ amd->AdaptSCSIID = amd->eepromBuf[EE_ADAPT_SCSI_ID];
+ amd->HostID_Bit = (1 << amd->AdaptSCSIID);
+ amd->AdaptSCSILUN = 0;
+ /* (eepromBuf[EE_TAG_CMD_NUM]) << 2; */
+ amd->ACBFlag = 0;
+ amd->Gmode2 = amd->eepromBuf[EE_MODE2];
+ amd_linkSRB(amd);
+ for (i = 0; i <= amd->max_id; i++) {
+
+ if (amd->AdaptSCSIID != i) {
+ struct amd_target_info *tinfo;
+ PEEprom prom;
+
+ tinfo = &amd->tinfo[i];
+ prom = (PEEprom)&amd->eepromBuf[i << 2];
+ if ((prom->EE_MODE1 & EN_DISCONNECT) != 0) {
+ tinfo->disc_tag |= AMD_USR_DISCENB;
+ if ((prom->EE_MODE1 & TAG_QUEUING) != 0)
+ tinfo->disc_tag |= AMD_USR_TAGENB;
+ }
+ if ((prom->EE_MODE1 & SYNC_NEGO) != 0) {
+ tinfo->user.period =
+ eeprom_period[prom->EE_SPEED];
+ tinfo->user.offset = AMD_MAX_SYNC_OFFSET;
+ }
+ tinfo->CtrlR1 = amd->AdaptSCSIID;
+ if ((prom->EE_MODE1 & PARITY_CHK) != 0)
+ tinfo->CtrlR1 |= PARITY_ERR_REPO;
+ tinfo->CtrlR3 = FAST_CLK;
+ tinfo->CtrlR4 = EATER_25NS;
+ if ((amd->eepromBuf[EE_MODE2] & ACTIVE_NEGATION) != 0)
+ tinfo->CtrlR4 |= NEGATE_REQACKDATA;
+ }
+ }
+ amd_write8(amd, SCSITIMEOUTREG, 153); /* 250ms selection timeout */
+ /* Conversion factor = 0 , 40MHz clock */
+ amd_write8(amd, CLKFACTREG, CLK_FREQ_40MHZ);
+ /* NOP cmd - clear command register */
+ amd_write8(amd, SCSICMDREG, NOP_CMD);
+ amd_write8(amd, CNTLREG2, EN_FEATURE|EN_SCSI2_CMD);
+ amd_write8(amd, CNTLREG3, FAST_CLK);
+ bval = EATER_25NS;
+ if (amd->eepromBuf[EE_MODE2] & ACTIVE_NEGATION) {
+ bval |= NEGATE_REQACKDATA;
+ }
+ amd_write8(amd, CNTLREG4, bval);
+
+ /* Disable SCSI bus reset interrupt */
+ amd_write8(amd, CNTLREG1, DIS_INT_ON_SCSI_RST);
+
+ return 0;
+}
+
+/*
+ * attach and init a host adapter
+ */
+static int
+amd_attach(device_t dev)
+{
+ struct cam_devq *devq; /* Device Queue to use for this SIM */
+ u_int8_t intstat;
+ struct amd_softc *amd = device_get_softc(dev);
+ int unit = device_get_unit(dev);
+ int rid;
+ void *ih;
+ struct resource *irqres;
+
+ if (amd_init(dev)) {
+ if (bootverbose)
+ printf("amd_attach: amd_init failure!\n");
+ return ENXIO;
+ }
+
+ /* Reset Pending INT */
+ intstat = amd_read8(amd, INTSTATREG);
+
+ /* After setting up the adapter, map our interrupt */
+ rid = 0;
+ irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (irqres == NULL ||
+ bus_setup_intr(dev, irqres, INTR_TYPE_CAM | INTR_ENTROPY,
+ amd_intr, amd, &ih)) {
+ if (bootverbose)
+ printf("amd%d: unable to register interrupt handler!\n",
+ unit);
+ return ENXIO;
+ }
+
+ /*
+ * Now let the CAM generic SCSI layer find the SCSI devices on
+ * the bus * start queue to reset to the idle loop. *
+ * Create device queue of SIM(s) * (MAX_START_JOB - 1) :
+ * max_sim_transactions
+ */
+ devq = cam_simq_alloc(MAX_START_JOB);
+ if (devq == NULL) {
+ if (bootverbose)
+ printf("amd_attach: cam_simq_alloc failure!\n");
+ return ENXIO;
+ }
+
+ amd->psim = cam_sim_alloc(amd_action, amd_poll, "amd",
+ amd, amd->unit, 1, MAX_TAGS_CMD_QUEUE,
+ devq);
+ if (amd->psim == NULL) {
+ cam_simq_free(devq);
+ if (bootverbose)
+ printf("amd_attach: cam_sim_alloc failure!\n");
+ return ENXIO;
+ }
+
+ if (xpt_bus_register(amd->psim, 0) != CAM_SUCCESS) {
+ cam_sim_free(amd->psim, /*free_devq*/TRUE);
+ if (bootverbose)
+ printf("amd_attach: xpt_bus_register failure!\n");
+ return ENXIO;
+ }
+
+ if (xpt_create_path(&amd->ppath, /* periph */ NULL,
+ cam_sim_path(amd->psim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_bus_deregister(cam_sim_path(amd->psim));
+ cam_sim_free(amd->psim, /* free_simq */ TRUE);
+ if (bootverbose)
+ printf("amd_attach: xpt_create_path failure!\n");
+ return ENXIO;
+ }
+
+ return 0;
+}
+
+static int
+amd_probe(device_t dev)
+{
+ if (pci_get_devid(dev) == PCI_DEVICE_ID_AMD53C974) {
+ device_set_desc(dev,
+ "Tekram DC390(T)/AMD53c974 SCSI Host Adapter");
+ return 0;
+ }
+ return ENXIO;
+}
+
+static device_method_t amd_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, amd_probe),
+ DEVMETHOD(device_attach, amd_attach),
+ { 0, 0 }
+};
+
+static driver_t amd_driver = {
+ "amd", amd_methods, sizeof(struct amd_softc)
+};
+
+static devclass_t amd_devclass;
+DRIVER_MODULE(amd, pci, amd_driver, amd_devclass, 0, 0);
diff --git a/sys/pci/amd.h b/sys/pci/amd.h
new file mode 100644
index 0000000..85f4f80
--- /dev/null
+++ b/sys/pci/amd.h
@@ -0,0 +1,580 @@
+/*
+ *********************************************************************
+ * FILE NAME : amd.h
+ * BY : C.L. Huang (ching@tekram.com.tw)
+ * Erich Chen (erich@tekram.com.tw)
+ * Description: Device Driver for the amd53c974 PCI Bus Master
+ * SCSI Host adapter found on cards such as
+ * the Tekram DC-390(T).
+ * (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
+ *
+ * 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. 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 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.
+ *********************************************************************
+ * $FreeBSD$
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+#define AMD_TRANS_CUR 0x01 /* Modify current neogtiation status */
+#define AMD_TRANS_ACTIVE 0x03 /* Assume this is the active target */
+#define AMD_TRANS_GOAL 0x04 /* Modify negotiation goal */
+#define AMD_TRANS_USER 0x08 /* Modify user negotiation settings */
+
+/*
+ * Per target transfer parameters.
+ */
+struct amd_transinfo {
+ u_int8_t period;
+ u_int8_t offset;
+};
+
+struct amd_target_info {
+ /*
+ * Records the currently active and user/default settings for
+ * tagged queueing and disconnection for each target.
+ */
+ u_int8_t disc_tag;
+#define AMD_CUR_DISCENB 0x01
+#define AMD_CUR_TAGENB 0x02
+#define AMD_USR_DISCENB 0x04
+#define AMD_USR_TAGENB 0x08
+ u_int8_t CtrlR1;
+ u_int8_t CtrlR3;
+ u_int8_t CtrlR4;
+ u_int8_t sync_period_reg;
+ u_int8_t sync_offset_reg;
+
+ /*
+ * Currently active transfer settings.
+ */
+ struct amd_transinfo current;
+ /*
+ * Transfer settings we wish to achieve
+ * through negotiation.
+ */
+ struct amd_transinfo goal;
+ /*
+ * User defined or default transfer settings.
+ */
+ struct amd_transinfo user;
+};
+
+/*
+ * Scatter/Gather Segment entry.
+ */
+struct amd_sg {
+ u_int32_t SGXLen;
+ u_int32_t SGXPtr;
+};
+
+/*
+ * Chipset feature limits
+ */
+#define MAX_SCSI_ID 8
+#define AMD_MAX_SYNC_OFFSET 15
+#define AMD_TARGET_MAX 7
+#define AMD_LUN_MAX 7
+#define AMD_NSEG (btoc(MAXPHYS) + 1)
+#define AMD_MAXTRANSFER_SIZE 0xFFFFFF /* restricted by 24 bit counter */
+#define MAX_DEVICES 10
+#define MAX_TAGS_CMD_QUEUE 256
+#define MAX_CMD_PER_LUN 6
+#define MAX_SRB_CNT 256
+#define MAX_START_JOB 256
+
+/*
+ * BIT position to integer mapping.
+ */
+#define BIT(N) (0x01 << N)
+
+/*
+ * EEPROM storage offsets and data structures.
+ */
+typedef struct _EEprom {
+ u_int8_t EE_MODE1;
+ u_int8_t EE_SPEED;
+ u_int8_t xx1;
+ u_int8_t xx2;
+} EEprom, *PEEprom;
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2 65
+#define EE_DELAY 66
+#define EE_TAG_CMD_NUM 67
+#define EE_DATA_SIZE 128
+#define EE_CHECKSUM 0x1234
+
+/*
+ * EE_MODE1 bits definition
+ */
+#define PARITY_CHK BIT(0)
+#define SYNC_NEGO BIT(1)
+#define EN_DISCONNECT BIT(2)
+#define SEND_START BIT(3)
+#define TAG_QUEUING BIT(4)
+
+/*
+ * EE_MODE2 bits definition
+ */
+#define MORE2_DRV BIT(0)
+#define GREATER_1G BIT(1)
+#define RST_SCSI_BUS BIT(2)
+#define ACTIVE_NEGATION BIT(3)
+#define NO_SEEK BIT(4)
+#define LUN_CHECK BIT(5)
+
+#define ENABLE_CE 1
+#define DISABLE_CE 0
+#define EEPROM_READ 0x80
+
+#define AMD_TAG_WILDCARD ((u_int)(~0))
+
+/*
+ * SCSI Request Block
+ */
+struct amd_srb {
+ TAILQ_ENTRY(amd_srb) links;
+ u_int8_t CmdBlock[12];
+ union ccb *pccb;
+ bus_dmamap_t dmamap;
+ struct amd_sg *pSGlist;
+
+ u_int32_t TotalXferredLen;
+ u_int32_t SGPhysAddr; /* a segment starting address */
+ u_int32_t SGToBeXferLen; /* to be xfer length */
+ u_int32_t Segment0[2];
+ u_int32_t Segment1[2];
+
+ struct amd_sg SGsegment[AMD_NSEG];
+ struct amd_sg Segmentx;/* a one entry of S/G list table */
+ u_int8_t *pMsgPtr;
+ u_int16_t SRBState;
+
+ u_int8_t AdaptStatus;
+ u_int8_t TargetStatus;
+ u_int8_t MsgCnt;
+ u_int8_t EndMessage;
+ u_int8_t TagNumber;
+ u_int8_t SGcount;
+ u_int8_t SGIndex;
+ u_int8_t IORBFlag; /* ;81h-Reset, 2-retry */
+
+ u_int8_t SRBStatus;
+ u_int8_t SRBFlag;
+ /* ; b0-AutoReqSense,b6-Read,b7-write */
+ /* ; b4-settimeout,b5-Residual valid */
+ u_int8_t ScsiCmdLen;
+};
+
+TAILQ_HEAD(srb_queue, amd_srb);
+
+/*
+ * Per-adapter, software configuration.
+ */
+struct amd_softc {
+ device_t dev;
+ bus_space_tag_t tag;
+ bus_space_handle_t bsh;
+ bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */
+ int unit;
+
+ int last_phase;
+ int cur_target;
+ int cur_lun;
+ struct amd_srb *active_srb;
+ struct amd_srb *untagged_srbs[AMD_TARGET_MAX+1][AMD_LUN_MAX+1];
+ struct amd_target_info tinfo[AMD_TARGET_MAX+1];
+ u_int16_t disc_count[AMD_TARGET_MAX+1][AMD_LUN_MAX+1];
+
+ struct srb_queue free_srbs;
+ struct srb_queue waiting_srbs;
+ struct srb_queue running_srbs;
+
+ struct amd_srb *pTmpSRB;
+
+ u_int16_t SRBCount;
+
+ u_int16_t max_id;
+ u_int16_t max_lun;
+
+ /* Hooks into the CAM XPT */
+ struct cam_sim *psim;
+ struct cam_path *ppath;
+
+ u_int8_t msgin_buf[6];
+ u_int8_t msgout_buf[6];
+ u_int msgin_index;
+ u_int msgout_index;
+ u_int msgout_len;
+
+ u_int8_t status;
+ u_int8_t AdaptSCSIID; /* ; Adapter SCSI Target ID */
+ u_int8_t AdaptSCSILUN; /* ; Adapter SCSI LUN */
+
+ u_int8_t ACBFlag;
+
+ u_int8_t Gmode2;
+
+ u_int8_t HostID_Bit;
+
+ u_int8_t InitDCB_flag[8][8]; /* flag of initDCB for device */
+ struct amd_srb SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */
+ struct amd_srb TmpSRB;
+ /* Setup data stored in an 93c46 serial eeprom */
+ u_int8_t eepromBuf[EE_DATA_SIZE];
+};
+
+/*
+ * ----SRB State machine definition
+ */
+#define SRB_FREE 0
+#define SRB_READY BIT(1)
+#define SRB_MSGOUT BIT(2) /* ;arbitration+msg_out 1st byte */
+#define SRB_MSGIN BIT(3)
+#define SRB_MSGIN_MULTI BIT(4)
+#define SRB_COMMAND BIT(5)
+#define SRB_START BIT(6) /* ;arbitration+msg_out+command_out */
+#define SRB_DISCONNECT BIT(7)
+#define SRB_DATA_XFER BIT(8)
+#define SRB_XFERPAD BIT(9)
+#define SRB_STATUS BIT(10)
+#define SRB_COMPLETED BIT(11)
+#define SRB_ABORT_SENT BIT(12)
+#define DO_SYNC_NEGO BIT(13)
+#define SRB_UNEXPECT_RESEL BIT(14)
+
+/*
+ * ---ACB Flag
+ */
+#define RESET_DEV BIT(0)
+#define RESET_DETECT BIT(1)
+#define RESET_DONE BIT(2)
+
+/*
+ * ---DCB Flag
+ */
+#define ABORT_DEV_ BIT(0)
+
+/*
+ * ---SRB status
+ */
+#define SRB_OK BIT(0)
+#define ABORTION BIT(1)
+#define OVER_RUN BIT(2)
+#define UNDER_RUN BIT(3)
+#define PARITY_ERROR BIT(4)
+#define SRB_ERROR BIT(5)
+
+/*
+ * ---SRB Flags
+ */
+#define DATAOUT BIT(7)
+#define DATAIN BIT(6)
+#define RESIDUAL_VALID BIT(5)
+#define ENABLE_TIMER BIT(4)
+#define RESET_DEV0 BIT(2)
+#define ABORT_DEV BIT(1)
+#define AUTO_REQSENSE BIT(0)
+
+/*
+ * ---Adapter status
+ */
+#define H_STATUS_GOOD 0
+#define H_SEL_TIMEOUT 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB 0x19
+#define H_BAD_CCB_OR_SG 0x1A
+#define H_ABORT 0x0FF
+
+/*
+ * AMD specific "status" codes returned in the SCSI status byte.
+ */
+#define AMD_SCSI_STAT_UNEXP_BUS_F 0xFD /* ; Unexpect Bus Free */
+#define AMD_SCSI_STAT_BUS_RST_DETECT 0xFE /* ; Scsi Bus Reset detected */
+#define AMD_SCSI_STAT_SEL_TIMEOUT 0xFF /* ; Selection Time out */
+
+/*
+ * ---Sync_Mode
+ */
+#define SYNC_DISABLE 0
+#define SYNC_ENABLE BIT(0)
+#define SYNC_NEGO_DONE BIT(1)
+#define WIDE_ENABLE BIT(2)
+#define WIDE_NEGO_DONE BIT(3)
+#define EN_TAG_QUEUING BIT(4)
+#define EN_ATN_STOP BIT(5)
+
+#define SYNC_NEGO_OFFSET 15
+
+/*
+ * ---SCSI bus phase
+ */
+#define SCSI_DATA_OUT 0
+#define SCSI_DATA_IN 1
+#define SCSI_COMMAND 2
+#define SCSI_STATUS 3
+#define SCSI_NOP0 4
+#define SCSI_ARBITRATING 5
+#define SCSI_MSG_OUT 6
+#define SCSI_MSG_IN 7
+#define SCSI_BUS_FREE 8
+
+/*
+ *==========================================================
+ * AMD 53C974 Registers bit Definition
+ *==========================================================
+ */
+
+/*
+ * ------SCSI Register-------
+ * Command Reg.(+0CH)
+ */
+#define DMA_COMMAND BIT(7)
+#define NOP_CMD 0
+#define CLEAR_FIFO_CMD 1
+#define RST_DEVICE_CMD 2
+#define RST_SCSI_BUS_CMD 3
+#define INFO_XFER_CMD 0x10
+#define INITIATOR_CMD_CMPLTE 0x11
+#define MSG_ACCEPTED_CMD 0x12
+#define XFER_PAD_BYTE 0x18
+#define SET_ATN_CMD 0x1A
+#define RESET_ATN_CMD 0x1B
+#define SEL_W_ATN 0x42
+#define SEL_W_ATN_STOP 0x43
+#define EN_SEL_RESEL 0x44
+#define SEL_W_ATN2 0x46
+#define DATA_XFER_CMD INFO_XFER_CMD
+
+
+/*
+ * ------SCSI Register-------
+ * SCSI Status Reg.(+10H)
+ */
+#define INTERRUPT BIT(7)
+#define ILLEGAL_OP_ERR BIT(6)
+#define PARITY_ERR BIT(5)
+#define COUNT_2_ZERO BIT(4)
+#define GROUP_CODE_VALID BIT(3)
+#define SCSI_PHASE_MASK (BIT(2)+BIT(1)+BIT(0))
+
+/*
+ * ------SCSI Register-------
+ * Interrupt Status Reg.(+14H)
+ */
+#define SCSI_RESET_ BIT(7)
+#define INVALID_CMD BIT(6)
+#define DISCONNECTED BIT(5)
+#define SERVICE_REQUEST BIT(4)
+#define SUCCESSFUL_OP BIT(3)
+#define RESELECTED BIT(2)
+#define SEL_ATTENTION BIT(1)
+#define SELECTED BIT(0)
+
+/*
+ * ------SCSI Register-------
+ * Internal State Reg.(+18H)
+ */
+#define SYNC_OFFSET_FLAG BIT(3)
+#define INTRN_STATE_MASK (BIT(2)+BIT(1)+BIT(0))
+
+/*
+ * ------SCSI Register-------
+ * Clock Factor Reg.(+24H)
+ */
+#define CLK_FREQ_40MHZ 0
+#define CLK_FREQ_35MHZ (BIT(2)+BIT(1)+BIT(0))
+#define CLK_FREQ_30MHZ (BIT(2)+BIT(1))
+#define CLK_FREQ_25MHZ (BIT(2)+BIT(0))
+#define CLK_FREQ_20MHZ BIT(2)
+#define CLK_FREQ_15MHZ (BIT(1)+BIT(0))
+#define CLK_FREQ_10MHZ BIT(1)
+
+/*
+ * ------SCSI Register-------
+ * Control Reg. 1(+20H)
+ */
+#define EXTENDED_TIMING BIT(7)
+#define DIS_INT_ON_SCSI_RST BIT(6)
+#define PARITY_ERR_REPO BIT(4)
+#define SCSI_ID_ON_BUS (BIT(2)+BIT(1)+BIT(0))
+
+/*
+ * ------SCSI Register-------
+ * Control Reg. 2(+2CH)
+ */
+#define EN_FEATURE BIT(6)
+#define EN_SCSI2_CMD BIT(3)
+
+/*
+ * ------SCSI Register-------
+ * Control Reg. 3(+30H)
+ */
+#define ID_MSG_CHECK BIT(7)
+#define EN_QTAG_MSG BIT(6)
+#define EN_GRP2_CMD BIT(5)
+#define FAST_SCSI BIT(4) /* ;10MB/SEC */
+#define FAST_CLK BIT(3) /* ;25 - 40 MHZ */
+
+/*
+ * ------SCSI Register-------
+ * Control Reg. 4(+34H)
+ */
+#define EATER_12NS 0
+#define EATER_25NS BIT(7)
+#define EATER_35NS BIT(6)
+#define EATER_0NS (BIT(7)+BIT(6))
+#define NEGATE_REQACKDATA BIT(2)
+#define NEGATE_REQACK BIT(3)
+
+/*
+ *========================================
+ * DMA Register
+ *========================================
+ */
+
+/*
+ * -------DMA Register--------
+ * DMA Command Reg.(+40H)
+ */
+#define READ_DIRECTION BIT(7)
+#define WRITE_DIRECTION 0
+#define EN_DMA_INT BIT(6)
+#define MAP_TO_MDL BIT(5)
+#define DMA_DIAGNOSTIC BIT(4)
+#define DMA_IDLE_CMD 0
+#define DMA_BLAST_CMD BIT(0)
+#define DMA_ABORT_CMD BIT(1)
+#define DMA_START_CMD (BIT(1)|BIT(0))
+
+/*
+ * -------DMA Register--------
+ * DMA Status Reg.(+54H)
+ */
+#define PCI_MS_ABORT BIT(6)
+#define BLAST_COMPLETE BIT(5)
+#define SCSI_INTERRUPT BIT(4)
+#define DMA_XFER_DONE BIT(3)
+#define DMA_XFER_ABORT BIT(2)
+#define DMA_XFER_ERROR BIT(1)
+#define POWER_DOWN BIT(0)
+
+/*
+ * -------DMA Register--------
+ * DMA SCSI Bus and Ctrl.(+70H)
+ * EN_INT_ON_PCI_ABORT
+ */
+
+/*
+ *==========================================================
+ * SCSI Chip register address offset
+ *==========================================================
+ */
+#define CTCREG_LOW 0x00 /* (R) current transfer count register low */
+#define STCREG_LOW 0x00 /* (W) start transfer count register low */
+
+#define CTCREG_MID 0x04 /* (R) current transfer count register
+ * middle */
+#define STCREG_MID 0x04 /* (W) start transfer count register middle */
+
+#define SCSIFIFOREG 0x08 /* (R/W) SCSI FIFO register */
+
+#define SCSICMDREG 0x0C /* (R/W) SCSI command register */
+
+#define SCSISTATREG 0x10 /* (R) SCSI status register */
+#define SCSIDESTIDREG 0x10 /* (W) SCSI destination ID register */
+
+#define INTSTATREG 0x14 /* (R) interrupt status register */
+#define SCSITIMEOUTREG 0x14 /* (W) SCSI timeout register */
+
+
+#define INTERNSTATREG 0x18 /* (R) internal state register */
+#define SYNCPERIOREG 0x18 /* (W) synchronous transfer period register */
+
+#define CURRENTFIFOREG 0x1C /* (R) current FIFO/internal state register */
+#define SYNCOFFREG 0x1C/* (W) synchronous transfer period register */
+
+#define CNTLREG1 0x20 /* (R/W) control register 1 */
+#define CLKFACTREG 0x24 /* (W) clock factor register */
+#define CNTLREG2 0x2C /* (R/W) control register 2 */
+#define CNTLREG3 0x30 /* (R/W) control register 3 */
+#define CNTLREG4 0x34 /* (R/W) control register 4 */
+
+#define CURTXTCNTREG 0x38 /* (R) current transfer count register
+ * high/part-unique ID code */
+#define STCREG_HIGH 0x38 /* (W) Start current transfer count register
+ * high */
+
+/*
+ *********************************************************
+ *
+ * SCSI DMA register
+ *
+ *********************************************************
+ */
+#define DMA_Cmd 0x40 /* (R/W) command register */
+#define DMA_XferCnt 0x44 /* (R/W) starting transfer count */
+#define DMA_XferAddr 0x48 /* (R/W) starting Physical address */
+#define DMA_Wk_ByteCntr 0x4C /* ( R ) working byte counter */
+#define DMA_Wk_AddrCntr 0x50 /* ( R ) working address counter */
+#define DMA_Status 0x54 /* ( R ) status register */
+#define DMA_MDL_Addr 0x58 /* (R/W) starting memory descriptor list (MDL)
+ * address */
+#define DMA_Wk_MDL_Cntr 0x5C /* ( R ) working MDL counter */
+#define DMA_ScsiBusCtrl 0x70 /* (bits R/W) SCSI BUS and control */
+
+/* ******************************************************* */
+#define am_target SCSISTATREG
+#define am_timeout INTSTATREG
+#define am_seq_step SYNCPERIOREG
+#define am_fifo_count SYNCOFFREG
+
+
+#define amd_read8(amd, port) \
+ bus_space_read_1((amd)->tag, (amd)->bsh, port)
+
+#define amd_read16(amd, port) \
+ bus_space_read_2((amd)->tag, (amd)->bsh, port)
+
+#define amd_read32(amd, port) \
+ bus_space_read_4((amd)->tag, (amd)->bsh, port)
+
+#define amd_write8(amd, port, value) \
+ bus_space_write_1((amd)->tag, (amd)->bsh, port, value)
+
+#define amd_write8_multi(amd, port, ptr, len) \
+ bus_space_write_multi_1((amd)->tag, (amd)->bsh, port, ptr, len)
+
+#define amd_write16(amd, port, value) \
+ bus_space_write_2((amd)->tag, (amd)->bsh, port, value)
+
+#define amd_write32(amd, port, value) \
+ bus_space_write_4((amd)->tag, (amd)->bsh, port, value)
+
+#endif /* AMD_H */
diff --git a/sys/pci/amdpm.c b/sys/pci/amdpm.c
new file mode 100644
index 0000000..9664ce2
--- /dev/null
+++ b/sys/pci/amdpm.c
@@ -0,0 +1,640 @@
+/*-
+ * Copyright (c) 2000 Matthew C. Forman
+ *
+ * Based (heavily) on alpm.c which is:
+ *
+ * Copyright (c) 1998, 1999 Nicolas Souchu
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Power management function/SMBus function support for the AMD 756 chip.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/uio.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/clock.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/smbus/smbconf.h>
+#include "smbus_if.h"
+
+#define AMDPM_DEBUG(x) if (amdpm_debug) (x)
+
+#ifdef DEBUG
+static int amdpm_debug = 1;
+#else
+static int amdpm_debug = 0;
+#endif
+
+#define AMDPM_VENDORID_AMD 0x1022
+#define AMDPM_DEVICEID_AMD756PM 0x740b
+
+/* PCI Configuration space registers */
+#define AMDPCI_PMBASE 0x58
+
+#define AMDPCI_GEN_CONFIG_PM 0x41
+#define AMDPCI_PMIOEN (1<<7)
+
+#define AMDPCI_SCIINT_CONFIG_PM 0x42
+#define AMDPCI_SCISEL_IRQ11 11
+
+#define AMDPCI_REVID 0x08
+
+/*
+ * I/O registers.
+ * Base address programmed via AMDPCI_PMBASE.
+ */
+#define AMDSMB_GLOBAL_STATUS 0xE0
+#define AMDSMB_GS_TO_STS (1<<5)
+#define AMDSMB_GS_HCYC_STS (1<<4)
+#define AMDSMB_GS_HST_STS (1<<3)
+#define AMDSMB_GS_PRERR_STS (1<<2)
+#define AMDSMB_GS_COL_STS (1<<1)
+#define AMDSMB_GS_ABRT_STS (1<<0)
+#define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS)
+
+#define AMDSMB_GLOBAL_ENABLE 0xE2
+#define AMDSMB_GE_ABORT (1<<5)
+#define AMDSMB_GE_HCYC_EN (1<<4)
+#define AMDSMB_GE_HOST_STC (1<<3)
+#define AMDSMB_GE_CYC_QUICK 0
+#define AMDSMB_GE_CYC_BYTE 1
+#define AMDSMB_GE_CYC_BDATA 2
+#define AMDSMB_GE_CYC_WDATA 3
+#define AMDSMB_GE_CYC_PROCCALL 4
+#define AMDSMB_GE_CYC_BLOCK 5
+
+#define AMDSMB_HSTADDR 0xE4
+#define AMDSMB_HSTDATA 0xE6
+#define AMDSMB_HSTCMD 0xE8
+#define AMDSMB_HSTDFIFO 0xE9
+#define AMDSMB_HSLVDATA 0xEA
+#define AMDSMB_HSLVDA 0xEC
+#define AMDSMB_HSLVDDR 0xEE
+#define AMDSMB_SNPADDR 0xEF
+
+struct amdpm_softc {
+ int base;
+ int rid;
+ struct resource *res;
+ bus_space_tag_t smbst;
+ bus_space_handle_t smbsh;
+};
+
+struct amdsmb_softc {
+ int base;
+ device_t smbus;
+ struct amdpm_softc *amdpm;
+};
+
+#define AMDPM_SMBINB(amdsmb,register) \
+ (bus_space_read_1(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register))
+#define AMDPM_SMBOUTB(amdsmb,register,value) \
+ (bus_space_write_1(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register, value))
+#define AMDPM_SMBINW(amdsmb,register) \
+ (bus_space_read_2(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register))
+#define AMDPM_SMBOUTW(amdsmb,register,value) \
+ (bus_space_write_2(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register, value))
+
+static int amdsmb_probe(device_t);
+static int amdsmb_attach(device_t);
+static int amdsmb_smb_callback(device_t, int, caddr_t *);
+static int amdsmb_smb_quick(device_t dev, u_char slave, int how);
+static int amdsmb_smb_sendb(device_t dev, u_char slave, char byte);
+static int amdsmb_smb_recvb(device_t dev, u_char slave, char *byte);
+static int amdsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte);
+static int amdsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte);
+static int amdsmb_smb_writew(device_t dev, u_char slave, char cmd, short word);
+static int amdsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word);
+static int amdsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
+static int amdsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte);
+
+static int amdpm_probe(device_t);
+static int amdpm_attach(device_t);
+
+
+static int
+amdpm_probe(device_t dev)
+{
+ u_long base;
+
+ if ((pci_get_vendor(dev) == AMDPM_VENDORID_AMD) &&
+ (pci_get_device(dev) == AMDPM_DEVICEID_AMD756PM)) {
+ device_set_desc(dev, "AMD 756 Power Management Controller");
+
+ /*
+ * We have to do this, since the BIOS won't give us the
+ * resource info (not mine, anyway).
+ */
+ base = pci_read_config(dev, AMDPCI_PMBASE, 4);
+ base &= 0xff00;
+ bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, base, 256);
+ return (0);
+ }
+ return ENXIO;
+}
+
+static int
+amdpm_attach(device_t dev)
+{
+ struct amdpm_softc *amdpm_sc = device_get_softc(dev);
+ u_char val_b;
+ int unit = device_get_unit(dev);
+ device_t smbinterface;
+
+ /* Enable I/O block access */
+ val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1);
+ pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1);
+
+ /* Allocate I/O space */
+ amdpm_sc->rid = AMDPCI_PMBASE;
+ amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE);
+
+ if (amdpm_sc->res == NULL) {
+ device_printf(dev, "could not map i/o space\n");
+ return (ENXIO);
+ }
+
+ amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
+ amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
+
+ smbinterface = device_add_child(dev, "amdsmb", unit);
+ if (!smbinterface)
+ device_printf(dev, "could not add SMBus device\n");
+ else
+ device_probe_and_attach(smbinterface);
+
+ return (0);
+}
+
+static int
+amdsmb_probe(device_t dev)
+{
+ struct amdsmb_softc *amdsmb_sc = (struct amdsmb_softc *)device_get_softc(dev);
+
+ device_set_desc(dev, "AMD 756 SMBus interface");
+ device_printf(dev, "AMD 756 SMBus interface\n");
+
+ /* Allocate a new smbus device */
+ amdsmb_sc->smbus = device_add_child(dev, "smbus", -1);
+ if (!amdsmb_sc->smbus)
+ return (EINVAL);
+
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static int
+amdsmb_attach(device_t dev)
+{
+ struct amdsmb_softc *amdsmb_sc = (struct amdsmb_softc *)device_get_softc(dev);
+
+ amdsmb_sc->amdpm = device_get_softc(device_get_parent(dev));
+
+ /* Probe and attach the smbus */
+ device_probe_and_attach(amdsmb_sc->smbus);
+
+ return (0);
+}
+
+static int
+amdsmb_smb_callback(device_t dev, int index, caddr_t *data)
+{
+ int error = 0;
+
+ switch (index) {
+ case SMB_REQUEST_BUS:
+ case SMB_RELEASE_BUS:
+ break;
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+static int
+amdsmb_clear(struct amdsmb_softc *sc)
+{
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
+ DELAY(10);
+
+ return (0);
+}
+
+#if 0
+static int
+amdsmb_abort(struct amdsmb_softc *sc)
+{
+ u_short l;
+
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
+
+ return (0);
+}
+#endif
+
+static int
+amdsmb_idle(struct amdsmb_softc *sc)
+{
+ u_short sts;
+
+ sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
+
+ AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
+
+ return (~(sts & AMDSMB_GS_HST_STS));
+}
+
+/*
+ * Poll the SMBus controller
+ */
+static int
+amdsmb_wait(struct amdsmb_softc *sc)
+{
+ int count = 10000;
+ u_short sts = 0;
+ int error;
+
+ /* Wait for command to complete (SMBus controller is idle) */
+ while(count--) {
+ DELAY(10);
+ sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
+ if (!(sts & AMDSMB_GS_HST_STS))
+ break;
+ }
+
+ AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
+
+ error = SMB_ENOERR;
+
+ if (!count)
+ error |= SMB_ETIMEOUT;
+
+ if (sts & AMDSMB_GS_ABRT_STS)
+ error |= SMB_EABORT;
+
+ if (sts & AMDSMB_GS_COL_STS)
+ error |= SMB_ENOACK;
+
+ if (sts & AMDSMB_GS_PRERR_STS)
+ error |= SMB_EBUSERR;
+
+ if (error != SMB_ENOERR)
+ amdsmb_clear(sc);
+
+ return (error);
+}
+
+static int
+amdsmb_smb_quick(device_t dev, u_char slave, int how)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (EBUSY);
+
+ switch (how) {
+ case SMB_QWRITE:
+ AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
+ break;
+ case SMB_QREAD:
+ AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
+ break;
+ default:
+ panic("%s: unknown QUICK command (%x)!", __func__, how);
+ }
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
+
+ error = amdsmb_wait(sc);
+
+ AMDPM_DEBUG(printf(", error=0x%x\n", error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_sendb(device_t dev, u_char slave, char byte)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
+
+ error = amdsmb_wait(sc);
+
+ AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_recvb(device_t dev, u_char slave, char *byte)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
+
+ if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
+ *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
+
+ AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
+
+ error = amdsmb_wait(sc);
+
+ AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
+
+ if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
+ *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
+
+ AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_writew(device_t dev, u_char slave, char cmd, short word)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
+
+ error = amdsmb_wait(sc);
+
+ AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ int error;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
+
+ if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
+ *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
+
+ AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if(!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ len = min(remain, 32);
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
+
+ /*
+ * Do we have to reset the internal 32-byte buffer?
+ * Can't see how to do this from the data sheet.
+ */
+
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len);
+
+ /* Fill the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]);
+ DELAY(2);
+ }
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
+
+ if ((error = amdsmb_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ remain -= len;
+ }
+
+error:
+ AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static int
+amdsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+ u_short l;
+
+ amdsmb_clear(sc);
+ if (!amdsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
+
+ AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
+
+ l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
+ AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
+
+ if ((error = amdsmb_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
+
+ /* Read the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
+ DELAY(2);
+ }
+
+ remain -= len;
+ }
+error:
+ AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static devclass_t amdpm_devclass;
+
+static device_method_t amdpm_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, amdpm_probe),
+ DEVMETHOD(device_attach, amdpm_attach),
+
+ { 0, 0 }
+};
+
+static driver_t amdpm_driver = {
+ "amdpm",
+ amdpm_methods,
+ sizeof(struct amdpm_softc),
+};
+
+static devclass_t amdsmb_devclass;
+
+static device_method_t amdsmb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, amdsmb_probe),
+ DEVMETHOD(device_attach, amdsmb_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ /* SMBus interface */
+ DEVMETHOD(smbus_callback, amdsmb_smb_callback),
+ DEVMETHOD(smbus_quick, amdsmb_smb_quick),
+ DEVMETHOD(smbus_sendb, amdsmb_smb_sendb),
+ DEVMETHOD(smbus_recvb, amdsmb_smb_recvb),
+ DEVMETHOD(smbus_writeb, amdsmb_smb_writeb),
+ DEVMETHOD(smbus_readb, amdsmb_smb_readb),
+ DEVMETHOD(smbus_writew, amdsmb_smb_writew),
+ DEVMETHOD(smbus_readw, amdsmb_smb_readw),
+ DEVMETHOD(smbus_bwrite, amdsmb_smb_bwrite),
+ DEVMETHOD(smbus_bread, amdsmb_smb_bread),
+
+ { 0, 0 }
+};
+
+static driver_t amdsmb_driver = {
+ "amdsmb",
+ amdsmb_methods,
+ sizeof(struct amdsmb_softc),
+};
+
+DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
+DRIVER_MODULE(amdsmb, amdpm, amdsmb_driver, amdsmb_devclass, 0, 0);
+MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(amdpm, 1);
diff --git a/sys/pci/cy_pci.c b/sys/pci/cy_pci.c
new file mode 100644
index 0000000..72cb961
--- /dev/null
+++ b/sys/pci/cy_pci.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1996, David Greenman
+ * 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 unmodified, 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Cyclades Y PCI serial interface driver
+ */
+
+#include "opt_cy_pci_fastintr.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/pci/pcivar.h>
+
+#define CY_PCI_BASE_ADDR0 0x10
+#define CY_PCI_BASE_ADDR1 0x14
+#define CY_PCI_BASE_ADDR2 0x18
+
+#define CY_PLX_9050_ICS 0x4c
+#define CY_PLX_9060_ICS 0x68
+#define CY_PLX_9050_ICS_IENABLE 0x040
+#define CY_PLX_9050_ICS_LOCAL_IENABLE 0x001
+#define CY_PLX_9050_ICS_LOCAL_IPOLARITY 0x002
+#define CY_PLX_9060_ICS_IENABLE 0x100
+#define CY_PLX_9060_ICS_LOCAL_IENABLE 0x800
+
+/* Cyclom-Y Custom Register for PLX ID. */
+#define PLX_VER 0x3400
+#define PLX_9050 0x0b
+#define PLX_9060 0x0c
+#define PLX_9080 0x0d
+
+extern int cyattach_common(void *, int); /* Not exactly correct */
+extern void cyintr(int);
+
+static int cy_pci_attach(device_t dev);
+static int cy_pci_probe(device_t dev);
+
+static device_method_t cy_pci_methods[] = {
+ /* Device interface. */
+ DEVMETHOD(device_probe, cy_pci_probe),
+ DEVMETHOD(device_attach, cy_pci_attach),
+
+ { 0, 0 }
+};
+
+static driver_t cy_pci_driver = {
+ "cy",
+ cy_pci_methods,
+ 0,
+};
+
+static devclass_t cy_devclass;
+
+DRIVER_MODULE(cy, pci, cy_pci_driver, cy_devclass, 0, 0);
+
+static int
+cy_pci_probe(dev)
+ device_t dev;
+{
+ u_int32_t device_id;
+
+ device_id = pci_get_devid(dev);
+ device_id &= ~0x00060000;
+ if (device_id != 0x0100120e && device_id != 0x0101120e)
+ return (ENXIO);
+ device_set_desc(dev, "Cyclades Cyclom-Y Serial Adapter");
+ return (0);
+}
+
+static int
+cy_pci_attach(dev)
+ device_t dev;
+{
+ struct resource *ioport_res, *irq_res, *mem_res;
+ void *irq_cookie, *vaddr;
+ u_int32_t ioport;
+ int adapter, irq_setup, ioport_rid, irq_rid, mem_rid;
+ u_char plx_ver;
+
+ ioport_res = NULL;
+ irq_res = NULL;
+ mem_res = NULL;
+
+ ioport_rid = CY_PCI_BASE_ADDR1;
+ ioport_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &ioport_rid,
+ 0ul, ~0ul, 0ul, RF_ACTIVE);
+ if (ioport_res == NULL) {
+ device_printf(dev, "ioport resource allocation failed\n");
+ goto fail;
+ }
+ ioport = rman_get_start(ioport_res);
+
+ mem_rid = CY_PCI_BASE_ADDR2;
+ mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &mem_rid,
+ 0ul, ~0ul, 0ul, RF_ACTIVE);
+ if (mem_res == NULL) {
+ device_printf(dev, "memory resource allocation failed\n");
+ goto fail;
+ }
+ vaddr = rman_get_virtual(mem_res);
+
+ adapter = cyattach_common(vaddr, 1);
+ if (adapter < 0) {
+ device_printf(dev, "no ports found!\n");
+ goto fail;
+ }
+
+ /*
+ * Allocate our interrupt.
+ * XXX Using the ISA interrupt handler directly is a bit of a violation
+ * since it doesn't actually take the same argument. For PCI, the
+ * argument is a void * token, but for ISA it is a unit. Since
+ * there is no overlap in PCI/ISA unit numbers for this driver, and
+ * since the ISA driver must handle the interrupt anyway, we use
+ * the unit number as the token even for PCI.
+ */
+ irq_rid = 0;
+ irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &irq_rid, 0ul, ~0ul, 0ul,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (irq_res == NULL) {
+ device_printf(dev, "interrupt resource allocation failed\n");
+ goto fail;
+ }
+#ifdef CY_PCI_FASTINTR
+ irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY | INTR_FAST,
+ (driver_intr_t *)cyintr, (void *)adapter, &irq_cookie);
+#else
+ irq_setup = ENXIO;
+#endif
+ if (irq_setup != 0)
+ irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY,
+ (driver_intr_t *)cyintr, (void *)adapter, &irq_cookie);
+ if (irq_setup != 0) {
+ device_printf(dev, "interrupt setup failed\n");
+ goto fail;
+ }
+
+ /*
+ * Enable the "local" interrupt input to generate a
+ * PCI interrupt.
+ */
+ plx_ver = *((u_char *)vaddr + PLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+ outw(ioport + CY_PLX_9050_ICS,
+ CY_PLX_9050_ICS_IENABLE | CY_PLX_9050_ICS_LOCAL_IENABLE |
+ CY_PLX_9050_ICS_LOCAL_IPOLARITY);
+ break;
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old board, use PLX_9060 values. */
+ outw(ioport + CY_PLX_9060_ICS,
+ inw(ioport + CY_PLX_9060_ICS) | CY_PLX_9060_ICS_IENABLE |
+ CY_PLX_9060_ICS_LOCAL_IENABLE);
+ break;
+ }
+
+ return (0);
+
+fail:
+ if (ioport_res != NULL)
+ bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid,
+ ioport_res);
+ if (irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res);
+ if (mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res);
+ return (ENXIO);
+}
diff --git a/sys/pci/dc21040reg.h b/sys/pci/dc21040reg.h
new file mode 100644
index 0000000..c0ff191
--- /dev/null
+++ b/sys/pci/dc21040reg.h
@@ -0,0 +1,583 @@
+/* $NetBSD: dc21040reg.h,v 1.15 1998/05/22 18:50:59 matt Exp $ */
+
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994, 1995, 1996 Matt Thomas <matt@3am-software.com>
+ * 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. 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Id: dc21040reg.h,v 1.24 1997/05/16 19:47:09 thomas Exp
+ */
+
+#if !defined(_DC21040_H)
+#define _DC21040_H
+
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+#define TULIP_BITFIELD2(a, b) b, a
+#define TULIP_BITFIELD3(a, b, c) c, b, a
+#define TULIP_BITFIELD4(a, b, c, d) d, c, b, a
+#else
+#define TULIP_BITFIELD2(a, b) a, b
+#define TULIP_BITFIELD3(a, b, c) a, b, c
+#define TULIP_BITFIELD4(a, b, c, d) a, b, c, d
+#endif
+
+typedef struct {
+ u_int32_t d_status;
+ u_int32_t TULIP_BITFIELD3(d_length1 : 11,
+ d_length2 : 11,
+ d_flag : 10);
+ u_int32_t d_addr1;
+ u_int32_t d_addr2;
+} tulip_desc_t;
+
+#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = 21040) */
+#define TULIP_DSTS_ERRSUM 0x00008000 /* Error Summary */
+/*
+ * Transmit Status
+ */
+#define TULIP_DSTS_TxBABBLE 0x00004000 /* Transmitter Babbled */
+#define TULIP_DSTS_TxCARRLOSS 0x00000800 /* Carrier Loss */
+#define TULIP_DSTS_TxNOCARR 0x00000400 /* No Carrier */
+#define TULIP_DSTS_TxLATECOLL 0x00000200 /* Late Collision */
+#define TULIP_DSTS_TxEXCCOLL 0x00000100 /* Excessive Collisions */
+#define TULIP_DSTS_TxNOHRTBT 0x00000080 /* No Heartbeat */
+#define TULIP_DSTS_TxCOLLMASK 0x00000078 /* Collision Count (mask) */
+#define TULIP_DSTS_V_TxCOLLCNT 0x00000003 /* Collision Count (bit) */
+#define TULIP_DSTS_TxLINKFAIL 0x00000004 /* Link Failure */
+#define TULIP_DSTS_TxUNDERFLOW 0x00000002 /* Underflow Error */
+#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */
+/*
+ * Receive Status
+ */
+#define TULIP_DSTS_RxBADLENGTH 0x00004000 /* Length Error */
+#define TULIP_DSTS_RxDATATYPE 0x00003000 /* Data Type */
+#define TULIP_DSTS_RxRUNT 0x00000800 /* Runt Frame */
+#define TULIP_DSTS_RxMULTICAST 0x00000400 /* Multicast Frame */
+#define TULIP_DSTS_RxFIRSTDESC 0x00000200 /* First Descriptor */
+#define TULIP_DSTS_RxLASTDESC 0x00000100 /* Last Descriptor */
+#define TULIP_DSTS_RxTOOLONG 0x00000080 /* Frame Too Long */
+#define TULIP_DSTS_RxCOLLSEEN 0x00000040 /* Collision Seen */
+#define TULIP_DSTS_RxFRAMETYPE 0x00000020 /* Frame Type */
+#define TULIP_DSTS_RxWATCHDOG 0x00000010 /* Receive Watchdog */
+#define TULIP_DSTS_RxDRBBLBIT 0x00000004 /* Dribble Bit */
+#define TULIP_DSTS_RxBADCRC 0x00000002 /* CRC Error */
+#define TULIP_DSTS_RxOVERFLOW 0x00000001 /* Overflow */
+
+
+#define TULIP_DFLAG_ENDRING 0x0008 /* End of Transmit Ring */
+#define TULIP_DFLAG_CHAIN 0x0004 /* Chain using d_addr2 */
+
+#define TULIP_DFLAG_TxWANTINTR 0x0200 /* Signal Interrupt on Completion */
+#define TULIP_DFLAG_TxLASTSEG 0x0100 /* Last Segment */
+#define TULIP_DFLAG_TxFIRSTSEG 0x0080 /* First Segment */
+#define TULIP_DFLAG_TxINVRSFILT 0x0040 /* Inverse Filtering */
+#define TULIP_DFLAG_TxSETUPPKT 0x0020 /* Setup Packet */
+#define TULIP_DFLAG_TxHASCRC 0x0010 /* Don't Append the CRC */
+#define TULIP_DFLAG_TxNOPADDING 0x0002 /* Don't AutoPad */
+#define TULIP_DFLAG_TxHASHFILT 0x0001 /* Hash/Perfect Filtering */
+
+/*
+ * The 21040 Registers (IO Space Addresses)
+ */
+#define TULIP_REG_BUSMODE 0x00 /* CSR0 -- Bus Mode */
+#define TULIP_REG_TXPOLL 0x08 /* CSR1 -- Transmit Poll Demand */
+#define TULIP_REG_RXPOLL 0x10 /* CSR2 -- Receive Poll Demand */
+#define TULIP_REG_RXLIST 0x18 /* CSR3 -- Receive List Base Addr */
+#define TULIP_REG_TXLIST 0x20 /* CSR4 -- Transmit List Base Addr */
+#define TULIP_REG_STATUS 0x28 /* CSR5 -- Status */
+#define TULIP_REG_CMD 0x30 /* CSR6 -- Command */
+#define TULIP_REG_INTR 0x38 /* CSR7 -- Interrupt Control */
+#define TULIP_REG_MISSES 0x40 /* CSR8 -- Missed Frame Counter */
+#define TULIP_REG_ADDRROM 0x48 /* CSR9 -- ENET ROM Register */
+#define TULIP_REG_RSRVD 0x50 /* CSR10 -- Reserved */
+#define TULIP_REG_FULL_DUPLEX 0x58 /* CSR11 -- Full Duplex */
+#define TULIP_REG_SIA_STATUS 0x60 /* CSR12 -- SIA Status */
+#define TULIP_REG_SIA_CONN 0x68 /* CSR13 -- SIA Connectivity */
+#define TULIP_REG_SIA_TXRX 0x70 /* CSR14 -- SIA Tx Rx */
+#define TULIP_REG_SIA_GEN 0x78 /* CSR15 -- SIA General */
+
+/*
+ * CSR5 -- Status Register
+ * CSR7 -- Interrupt Control
+ */
+#define TULIP_STS_ERRORMASK 0x03800000L /* ( R) Error Bits (Valid when SYSERROR is set) */
+#define TULIP_STS_ERR_PARITY 0x00000000L /* 000 - Parity Error (Perform Reset) */
+#define TULIP_STS_ERR_MASTER 0x00800000L /* 001 - Master Abort */
+#define TULIP_STS_ERR_TARGET 0x01000000L /* 010 - Target Abort */
+#define TULIP_STS_ERR_SHIFT 23
+#define TULIP_STS_TXSTATEMASK 0x00700000L /* ( R) Transmission Process State */
+#define TULIP_STS_TXS_RESET 0x00000000L /* 000 - Rset or transmit jabber expired */
+#define TULIP_STS_TXS_FETCH 0x00100000L /* 001 - Fetching transmit descriptor */
+#define TULIP_STS_TXS_WAITEND 0x00200000L /* 010 - Wait for end of transmission */
+#define TULIP_STS_TXS_READING 0x00300000L /* 011 - Read buffer and enqueue data */
+#define TULIP_STS_TXS_RSRVD 0x00400000L /* 100 - Reserved */
+#define TULIP_STS_TXS_SETUP 0x00500000L /* 101 - Setup Packet */
+#define TULIP_STS_TXS_SUSPEND 0x00600000L /* 110 - Transmit FIFO underflow or an
+ unavailable transmit descriptor */
+#define TULIP_STS_TXS_CLOSE 0x00700000L /* 111 - Close transmit descriptor */
+#define TULIP_STS_RXSTATEMASK 0x000E0000L /* ( R) Receive Process State*/
+#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */
+#define TULIP_STS_RXS_FETCH 0x00020000L /* 001 - Running -- Fetch receive descriptor */
+#define TULIP_STS_RXS_ENDCHECK 0x00040000L /* 010 - Running -- Check for end of receive
+ packet before prefetch of next descriptor */
+#define TULIP_STS_RXS_WAIT 0x00060000L /* 011 - Running -- Wait for receive packet */
+#define TULIP_STS_RXS_SUSPEND 0x00080000L /* 100 - Suspended -- As a result of
+ unavailable receive buffers */
+#define TULIP_STS_RXS_CLOSE 0x000A0000L /* 101 - Running -- Close receive descriptor */
+#define TULIP_STS_RXS_FLUSH 0x000C0000L /* 110 - Running -- Flush the current frame
+ from the receive FIFO as a result of
+ an unavailable receive buffer */
+#define TULIP_STS_RXS_DEQUEUE 0x000E0000L /* 111 - Running -- Dequeue the receive frame
+ from the receive FIFO into the receive
+ buffer. */
+#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */
+#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */
+#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */
+#define TULIP_STS_LINKFAIL 0x00001000L /* (RW) Link Failure (21040) */
+#define TULIP_STS_FULDPLXSHRT 0x00000800L /* (RW) Full Duplex Short Fram Rcvd (21040) */
+#define TULIP_STS_GPTIMEOUT 0x00000800L /* (RW) General Purpose Timeout (21140) */
+#define TULIP_STS_AUI 0x00000400L /* (RW) AUI/TP Switch (21040) */
+#define TULIP_STS_RXTIMEOUT 0x00000200L /* (RW) Receive Watchbog Timeout */
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buffer Unavailable */
+#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */
+#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */
+#define TULIP_STS_LINKPASS 0x00000010L /* (RW) LinkPass (21041) */
+#define TULIP_STS_TXBABBLE 0x00000008L /* (RW) Transmit Jabber Timeout */
+#define TULIP_STS_TXNOBUF 0x00000004L /* (RW) Transmit Buffer Unavailable */
+#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */
+#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */
+
+/*
+ * CSR6 -- Command (Operation Mode) Register
+ */
+#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */
+#define TULIP_CMD_SCRAMBLER 0x01000000L /* (RW) Scrambler Mode (21140) */
+#define TULIP_CMD_PCSFUNCTION 0x00800000L /* (RW) PCS Function (21140) */
+#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */
+#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */
+#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */
+#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */
+#define TULIP_CMD_ENHCAPTEFFCT 0x00040000L /* (RW) Enhanced Capture Effecty (21041) */
+#define TULIP_CMD_CAPTREFFCT 0x00020000L /* (RW) Capture Effect (!802.3) */
+#define TULIP_CMD_BACKPRESSURE 0x00010000L /* (RW) Back Pressure (!802.3) (21040) */
+#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */
+#define TULIP_CMD_THRSHLD72 0x00000000L /* 00 - 72 Bytes */
+#define TULIP_CMD_THRSHLD96 0x00004000L /* 01 - 96 Bytes */
+#define TULIP_CMD_THRSHLD128 0x00008000L /* 10 - 128 bytes */
+#define TULIP_CMD_THRSHLD160 0x0000C000L /* 11 - 160 Bytes */
+#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */
+#define TULIP_CMD_FORCECOLL 0x00001000L /* (RW) Force Collisions */
+#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */
+#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */
+#define TULIP_CMD_FLAKYOSCDIS 0x00000100L /* (RW) Flakey Oscillator Disable */
+#define TULIP_CMD_ALLMULTI 0x00000080L /* (RW) Pass All Multicasts */
+#define TULIP_CMD_PROMISCUOUS 0x00000040L /* (RW) Promiscuous Mode */
+#define TULIP_CMD_BACKOFFCTR 0x00000020L /* (RW) Start/Stop Backoff Counter (!802.3) */
+#define TULIP_CMD_INVFILTER 0x00000010L /* (R ) Inverse Filtering */
+#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */
+#define TULIP_CMD_HASHONLYFLTR 0x00000004L /* (R ) Hash Only Filtering */
+#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */
+#define TULIP_CMD_HASHPRFCTFLTR 0x00000001L /* (R ) Hash/Perfect Receive Filtering */
+
+#define TULIP_SIASTS_OTHERRXACTIVITY 0x00000200L
+#define TULIP_SIASTS_RXACTIVITY 0x00000100L
+#define TULIP_SIASTS_LINKFAIL 0x00000004L
+#define TULIP_SIASTS_LINK100FAIL 0x00000002L
+#define TULIP_SIACONN_RESET 0x00000000L
+
+/*
+ * 21040 SIA definitions
+ */
+#define TULIP_21040_PROBE_10BASET_TIMEOUT 2500
+#define TULIP_21040_PROBE_AUIBNC_TIMEOUT 300
+#define TULIP_21040_PROBE_EXTSIA_TIMEOUT 300
+
+#define TULIP_21040_SIACONN_10BASET 0x0000EF01L
+#define TULIP_21040_SIATXRX_10BASET 0x0000FFFFL
+#define TULIP_21040_SIAGEN_10BASET 0x00000000L
+
+#define TULIP_21040_SIACONN_10BASET_FD 0x0000EF01L
+#define TULIP_21040_SIATXRX_10BASET_FD 0x0000FFFDL
+#define TULIP_21040_SIAGEN_10BASET_FD 0x00000000L
+
+#define TULIP_21040_SIACONN_AUIBNC 0x0000EF09L
+#define TULIP_21040_SIATXRX_AUIBNC 0x00000705L
+#define TULIP_21040_SIAGEN_AUIBNC 0x00000006L
+
+#define TULIP_21040_SIACONN_EXTSIA 0x00003041L
+#define TULIP_21040_SIATXRX_EXTSIA 0x00000000L
+#define TULIP_21040_SIAGEN_EXTSIA 0x00000006L
+
+/*
+ * 21041 SIA definitions
+ */
+
+#define TULIP_21041_PROBE_10BASET_TIMEOUT 2500
+#define TULIP_21041_PROBE_AUIBNC_TIMEOUT 300
+
+#define TULIP_21041_SIACONN_10BASET 0x0000EF01L
+#define TULIP_21041_SIATXRX_10BASET 0x0000FF3FL
+#define TULIP_21041_SIAGEN_10BASET 0x00000000L
+
+#define TULIP_21041P2_SIACONN_10BASET 0x0000EF01L
+#define TULIP_21041P2_SIATXRX_10BASET 0x0000FFFFL
+#define TULIP_21041P2_SIAGEN_10BASET 0x00000000L
+
+#define TULIP_21041_SIACONN_10BASET_FD 0x0000EF01L
+#define TULIP_21041_SIATXRX_10BASET_FD 0x0000FF3DL
+#define TULIP_21041_SIAGEN_10BASET_FD 0x00000000L
+
+#define TULIP_21041P2_SIACONN_10BASET_FD 0x0000EF01L
+#define TULIP_21041P2_SIATXRX_10BASET_FD 0x0000FFFFL
+#define TULIP_21041P2_SIAGEN_10BASET_FD 0x00000000L
+
+#define TULIP_21041_SIACONN_AUI 0x0000EF09L
+#define TULIP_21041_SIATXRX_AUI 0x0000F73DL
+#define TULIP_21041_SIAGEN_AUI 0x0000000EL
+
+#define TULIP_21041P2_SIACONN_AUI 0x0000EF09L
+#define TULIP_21041P2_SIATXRX_AUI 0x0000F7FDL
+#define TULIP_21041P2_SIAGEN_AUI 0x0000000EL
+
+#define TULIP_21041_SIACONN_BNC 0x0000EF09L
+#define TULIP_21041_SIATXRX_BNC 0x0000F73DL
+#define TULIP_21041_SIAGEN_BNC 0x00000006L
+
+#define TULIP_21041P2_SIACONN_BNC 0x0000EF09L
+#define TULIP_21041P2_SIATXRX_BNC 0x0000F7FDL
+#define TULIP_21041P2_SIAGEN_BNC 0x00000006L
+
+/*
+ * 21142 SIA definitions
+ */
+
+#define TULIP_21142_PROBE_10BASET_TIMEOUT 2500
+#define TULIP_21142_PROBE_AUIBNC_TIMEOUT 300
+
+#define TULIP_21142_SIACONN_10BASET 0x00000001L
+#define TULIP_21142_SIATXRX_10BASET 0x00007F3FL
+#define TULIP_21142_SIAGEN_10BASET 0x00000008L
+
+#define TULIP_21142_SIACONN_10BASET_FD 0x00000001L
+#define TULIP_21142_SIATXRX_10BASET_FD 0x00007F3DL
+#define TULIP_21142_SIAGEN_10BASET_FD 0x00000008L
+
+#define TULIP_21142_SIACONN_AUI 0x00000009L
+#define TULIP_21142_SIATXRX_AUI 0x00000705L
+#define TULIP_21142_SIAGEN_AUI 0x0000000EL
+
+#define TULIP_21142_SIACONN_BNC 0x00000009L
+#define TULIP_21142_SIATXRX_BNC 0x00000705L
+#define TULIP_21142_SIAGEN_BNC 0x00000006L
+
+
+
+
+#define TULIP_WATCHDOG_TXDISABLE 0x00000001L
+#define TULIP_WATCHDOG_RXDISABLE 0x00000010L
+
+#define TULIP_BUSMODE_SWRESET 0x00000001L
+#define TULIP_BUSMODE_DESCSKIPLEN_MASK 0x0000007CL
+#define TULIP_BUSMODE_BIGENDIAN 0x00000080L
+#define TULIP_BUSMODE_BURSTLEN_MASK 0x00003F00L
+#define TULIP_BUSMODE_BURSTLEN_DEFAULT 0x00000000L
+#define TULIP_BUSMODE_BURSTLEN_1LW 0x00000100L
+#define TULIP_BUSMODE_BURSTLEN_2LW 0x00000200L
+#define TULIP_BUSMODE_BURSTLEN_4LW 0x00000400L
+#define TULIP_BUSMODE_BURSTLEN_8LW 0x00000800L
+#define TULIP_BUSMODE_BURSTLEN_16LW 0x00001000L
+#define TULIP_BUSMODE_BURSTLEN_32LW 0x00002000L
+#define TULIP_BUSMODE_CACHE_NOALIGN 0x00000000L
+#define TULIP_BUSMODE_CACHE_ALIGN8 0x00004000L
+#define TULIP_BUSMODE_CACHE_ALIGN16 0x00008000L
+#define TULIP_BUSMODE_CACHE_ALIGN32 0x0000C000L
+#define TULIP_BUSMODE_TXPOLL_NEVER 0x00000000L
+#define TULIP_BUSMODE_TXPOLL_200000ns 0x00020000L
+#define TULIP_BUSMODE_TXPOLL_800000ns 0x00040000L
+#define TULIP_BUSMODE_TXPOLL_1600000ns 0x00060000L
+#define TULIP_BUSMODE_TXPOLL_12800ns 0x00080000L /* 21041 only */
+#define TULIP_BUSMODE_TXPOLL_25600ns 0x000A0000L /* 21041 only */
+#define TULIP_BUSMODE_TXPOLL_51200ns 0x000C0000L /* 21041 only */
+#define TULIP_BUSMODE_TXPOLL_102400ns 0x000E0000L /* 21041 only */
+#define TULIP_BUSMODE_DESC_BIGENDIAN 0x00100000L /* 21041 only */
+#define TULIP_BUSMODE_READMULTIPLE 0x00200000L /* */
+
+#define TULIP_REG_CFDA 0x40
+#define TULIP_CFDA_SLEEP 0x80000000L
+#define TULIP_CFDA_SNOOZE 0x40000000L
+
+#define TULIP_GP_PINSET 0x00000100L
+/*
+ * These are the defintitions used for the DEC 21140
+ * evaluation board.
+ */
+#define TULIP_GP_EB_PINS 0x0000001F /* General Purpose Pin directions */
+#define TULIP_GP_EB_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */
+#define TULIP_GP_EB_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */
+#define TULIP_GP_EB_INIT 0x0000000B /* No loopback --- point-to-point */
+
+/*
+ * These are the defintitions used for the SMC9332 (21140) board.
+ */
+#define TULIP_GP_SMC_9332_PINS 0x0000003F /* General Purpose Pin directions */
+#define TULIP_GP_SMC_9332_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */
+#define TULIP_GP_SMC_9332_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */
+#define TULIP_GP_SMC_9332_INIT 0x00000009 /* No loopback --- point-to-point */
+
+/*
+ * There are the definitions used for the DEC DE500
+ * 10/100 family of boards
+ */
+#define TULIP_GP_DE500_PINS 0x0000001FL
+#define TULIP_GP_DE500_LINK_PASS 0x00000080L
+#define TULIP_GP_DE500_SYM_LINK 0x00000040L
+#define TULIP_GP_DE500_SIGNAL_DETECT 0x00000020L
+#define TULIP_GP_DE500_PHY_RESET 0x00000010L
+#define TULIP_GP_DE500_HALFDUPLEX 0x00000008L
+#define TULIP_GP_DE500_PHY_LOOPBACK 0x00000004L
+#define TULIP_GP_DE500_FORCE_LED 0x00000002L
+#define TULIP_GP_DE500_FORCE_100 0x00000001L
+
+/*
+ * These are the defintitions used for the Cogent EM100
+ * 21140 board.
+ */
+#define TULIP_GP_EM100_PINS 0x0000003F /* General Purpose Pin directions */
+#define TULIP_GP_EM100_INIT 0x00000009 /* No loopback --- point-to-point */
+#define TULIP_COGENT_EM100TX_ID 0x12
+#define TULIP_COGENT_EM100FX_ID 0x15
+
+
+/*
+ * These are the defintitions used for the Znyx ZX342
+ * 10/100 board
+ */
+#define TULIP_ZNYX_ID_ZX312 0x0602
+#define TULIP_ZNYX_ID_ZX312T 0x0622
+#define TULIP_ZNYX_ID_ZX314_INTA 0x0701
+#define TULIP_ZNYX_ID_ZX314 0x0711
+#define TULIP_ZNYX_ID_ZX315_INTA 0x0801
+#define TULIP_ZNYX_ID_ZX315 0x0811
+#define TULIP_ZNYX_ID_ZX342 0x0901
+#define TULIP_ZNYX_ID_ZX342B 0x0921
+#define TULIP_ZNYX_ID_ZX342_X3 0x0902
+#define TULIP_ZNYX_ID_ZX342_X4 0x0903
+#define TULIP_ZNYX_ID_ZX344 0x0A01
+#define TULIP_ZNYX_ID_ZX351 0x0B01
+#define TULIP_ZNYX_ID_ZX345 0x0C01
+#define TULIP_ZNYX_ID_ZX311 0x0D01
+#define TULIP_ZNYX_ID_ZX346 0x0E01
+
+#define TULIP_GP_ZX34X_PINS 0x0000001F /* General Purpose Pin directions */
+#define TULIP_GP_ZX344_PINS 0x0000000B /* General Purpose Pin directions */
+#define TULIP_GP_ZX345_PINS 0x00000003 /* General Purpose Pin directions */
+#define TULIP_GP_ZX346_PINS 0x00000043 /* General Purpose Pin directions */
+#define TULIP_GP_ZX34X_LNKFAIL 0x00000080 /* 10Mb/s Link Failure */
+#define TULIP_GP_ZX34X_SYMDET 0x00000040 /* 100Mb/s Symbol Detect */
+#define TULIP_GP_ZX345_PHYACT 0x00000040 /* PHY Activity */
+#define TULIP_GP_ZX34X_SIGDET 0x00000020 /* 100Mb/s Signal Detect */
+#define TULIP_GP_ZX346_AUTONEG_ENABLED 0x00000020 /* 802.3u autoneg enabled */
+#define TULIP_GP_ZX342_COLENA 0x00000008 /* 10t Ext LB */
+#define TULIP_GP_ZX344_ROTINT 0x00000008 /* PPB IRQ rotation */
+#define TULIP_GP_ZX345_SPEED10 0x00000008 /* 10Mb speed detect */
+#define TULIP_GP_ZX346_SPEED100 0x00000008 /* 100Mb speed detect */
+#define TULIP_GP_ZX34X_NCOLENA 0x00000004 /* 10t Int LB */
+#define TULIP_GP_ZX34X_RXMATCH 0x00000004 /* RX Match */
+#define TULIP_GP_ZX346_FULLDUPLEX 0x00000004 /* Full Duplex Sensed */
+#define TULIP_GP_ZX34X_LB102 0x00000002 /* 100tx twister LB */
+#define TULIP_GP_ZX34X_NLB101 0x00000001 /* PDT/PDR LB */
+#define TULIP_GP_ZX34X_INIT 0x00000009
+
+/*
+ * Asante's stuff...
+ */
+#define TULIP_GP_ASANTE_PINS 0x000000bf /* GP pin config */
+#define TULIP_GP_ASANTE_PHYRESET 0x00000008 /* Reset PHY */
+
+/*
+ * ACCTON EN1207 specialties
+ */
+
+#define TULIP_CSR8_EN1207 0x08
+#define TULIP_CSR9_EN1207 0x00
+#define TULIP_CSR10_EN1207 0x03
+#define TULIP_CSR11_EN1207 0x1F
+
+#define TULIP_GP_EN1207_BNC_INIT 0x0000011B
+#define TULIP_GP_EN1207_UTP_INIT 0x9E00000B
+#define TULIP_GP_EN1207_100_INIT 0x6D00031B
+
+/*
+ * SROM definitions for the 21140 and 21041.
+ */
+#define SROMXREG 0x0400
+#define SROMSEL 0x0800
+#define SROMRD 0x4000
+#define SROMWR 0x2000
+#define SROMDIN 0x0008
+#define SROMDOUT 0x0004
+#define SROMDOUTON 0x0004
+#define SROMDOUTOFF 0x0004
+#define SROMCLKON 0x0002
+#define SROMCLKOFF 0x0002
+#define SROMCSON 0x0001
+#define SROMCSOFF 0x0001
+#define SROMCS 0x0001
+
+#define SROMCMD_MODE 4
+#define SROMCMD_WR 5
+#define SROMCMD_RD 6
+
+#define SROM_BITWIDTH 6
+
+/*
+ * MII Definitions for the 21041 and 21140/21140A/21142
+ */
+#define MII_PREAMBLE (~0)
+#define MII_TEST 0xAAAAAAAA
+#define MII_RDCMD 0xF6 /* 1111.0110 */
+#define MII_WRCMD 0xF5 /* 1111.0101 */
+#define MII_DIN 0x00080000
+#define MII_RD 0x00040000
+#define MII_WR 0x00000000
+#define MII_DOUT 0x00020000
+#define MII_CLK 0x00010000
+#define MII_CLKON MII_CLK
+#define MII_CLKOFF MII_CLK
+
+#define PHYREG_CONTROL 0
+#define PHYREG_STATUS 1
+#define PHYREG_IDLOW 2
+#define PHYREG_IDHIGH 3
+#define PHYREG_AUTONEG_ADVERTISEMENT 4
+#define PHYREG_AUTONEG_ABILITIES 5
+#define PHYREG_AUTONEG_EXPANSION 6
+#define PHYREG_AUTONEG_NEXTPAGE 7
+
+#define PHYSTS_100BASET4 0x8000
+#define PHYSTS_100BASETX_FD 0x4000
+#define PHYSTS_100BASETX 0x2000
+#define PHYSTS_10BASET_FD 0x1000
+#define PHYSTS_10BASET 0x0800
+#define PHYSTS_AUTONEG_DONE 0x0020
+#define PHYSTS_REMOTE_FAULT 0x0010
+#define PHYSTS_CAN_AUTONEG 0x0008
+#define PHYSTS_LINK_UP 0x0004
+#define PHYSTS_JABBER_DETECT 0x0002
+#define PHYSTS_EXTENDED_REGS 0x0001
+
+#define PHYCTL_RESET 0x8000
+#define PHYCTL_SELECT_100MB 0x2000
+#define PHYCTL_AUTONEG_ENABLE 0x1000
+#define PHYCTL_ISOLATE 0x0400
+#define PHYCTL_AUTONEG_RESTART 0x0200
+#define PHYCTL_FULL_DUPLEX 0x0100
+
+/*
+ * Definitions for the DE425.
+ */
+#define DE425_CFID 0x08 /* Configuration Id */
+#define DE425_CFCS 0x0C /* Configuration Command-Status */
+#define DE425_CFRV 0x18 /* Configuration Revision */
+#define DE425_CFLT 0x1C /* Configuration Latency Timer */
+#define DE425_CBIO 0x28 /* Configuration Base IO Address */
+#define DE425_CFDA 0x2C /* Configuration Driver Area */
+#define DE425_ENETROM_OFFSET 0xC90 /* Offset in I/O space for ENETROM */
+#define DE425_CFG0 0xC88 /* IRQ register */
+#define DE425_EISAID 0x10a34250 /* EISA device id */
+#define DE425_EISA_IOSIZE 0x100
+
+#define DEC_VENDORID 0x1011
+#define CHIPID_21040 0x0002
+#define CHIPID_21140 0x0009
+#define CHIPID_21041 0x0014
+#define CHIPID_21142 0x0019
+#define PCI_VENDORID(x) ((x) & 0xFFFF)
+#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
+
+/*
+ * Generic SROM Format
+ *
+ *
+ */
+
+typedef struct {
+ u_int8_t sh_idbuf[18];
+ u_int8_t sh_version;
+ u_int8_t sh_adapter_count;
+ u_int8_t sh_ieee802_address[6];
+} tulip_srom_header_t;
+
+typedef struct {
+ u_int8_t sai_device;
+ u_int8_t sai_leaf_offset_lowbyte;
+ u_int8_t sai_leaf_offset_highbyte;
+} tulip_srom_adapter_info_t;
+
+typedef enum {
+ TULIP_SROM_CONNTYPE_10BASET =0x0000,
+ TULIP_SROM_CONNTYPE_BNC =0x0001,
+ TULIP_SROM_CONNTYPE_AUI =0x0002,
+ TULIP_SROM_CONNTYPE_100BASETX =0x0003,
+ TULIP_SROM_CONNTYPE_100BASET4 =0x0006,
+ TULIP_SROM_CONNTYPE_100BASEFX =0x0007,
+ TULIP_SROM_CONNTYPE_MII_10BASET =0x0009,
+ TULIP_SROM_CONNTYPE_MII_100BASETX =0x000D,
+ TULIP_SROM_CONNTYPE_MII_100BASET4 =0x000F,
+ TULIP_SROM_CONNTYPE_MII_100BASEFX =0x0010,
+ TULIP_SROM_CONNTYPE_10BASET_NWAY =0x0100,
+ TULIP_SROM_CONNTYPE_10BASET_FD =0x0204,
+ TULIP_SROM_CONNTYPE_MII_10BASET_FD =0x020A,
+ TULIP_SROM_CONNTYPE_100BASETX_FD =0x020E,
+ TULIP_SROM_CONNTYPE_MII_100BASETX_FD =0x0211,
+ TULIP_SROM_CONNTYPE_10BASET_NOLINKPASS =0x0400,
+ TULIP_SROM_CONNTYPE_AUTOSENSE =0x0800,
+ TULIP_SROM_CONNTYPE_AUTOSENSE_POWERUP =0x8800,
+ TULIP_SROM_CONNTYPE_AUTOSENSE_NWAY =0x9000,
+ TULIP_SROM_CONNTYPE_NOT_USED =0xFFFF
+} tulip_srom_connection_t;
+
+typedef enum {
+ TULIP_SROM_MEDIA_10BASET =0x0000,
+ TULIP_SROM_MEDIA_BNC =0x0001,
+ TULIP_SROM_MEDIA_AUI =0x0002,
+ TULIP_SROM_MEDIA_100BASETX =0x0003,
+ TULIP_SROM_MEDIA_10BASET_FD =0x0004,
+ TULIP_SROM_MEDIA_100BASETX_FD =0x0005,
+ TULIP_SROM_MEDIA_100BASET4 =0x0006,
+ TULIP_SROM_MEDIA_100BASEFX =0x0007,
+ TULIP_SROM_MEDIA_100BASEFX_FD =0x0008
+} tulip_srom_media_t;
+
+#define TULIP_SROM_21041_EXTENDED 0x40
+
+#define TULIP_SROM_2114X_NOINDICATOR 0x8000
+#define TULIP_SROM_2114X_DEFAULT 0x4000
+#define TULIP_SROM_2114X_POLARITY 0x0080
+#define TULIP_SROM_2114X_CMDBITS(n) (((n) & 0x0071) << 18)
+#define TULIP_SROM_2114X_BITPOS(b) (1 << (((b) & 0x0E) >> 1))
+
+
+
+#endif /* !defined(_DC21040_H) */
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
new file mode 100644
index 0000000..189835c
--- /dev/null
+++ b/sys/pci/if_dc.c
@@ -0,0 +1,3619 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143
+ * series chips and several workalikes including the following:
+ *
+ * Macronix 98713/98715/98725/98727/98732 PMAC (www.macronix.com)
+ * Macronix/Lite-On 82c115 PNIC II (www.macronix.com)
+ * Lite-On 82c168/82c169 PNIC (www.litecom.com)
+ * ASIX Electronics AX88140A (www.asix.com.tw)
+ * ASIX Electronics AX88141 (www.asix.com.tw)
+ * ADMtek AL981 (www.admtek.com.tw)
+ * ADMtek AN985 (www.admtek.com.tw)
+ * Davicom DM9100, DM9102, DM9102A (www.davicom8.com)
+ * Accton EN1217 (www.accton.com)
+ * Xircom X3201 (www.xircom.com)
+ * Abocom FE2500
+ * Conexant LANfinity (www.conexant.com)
+ *
+ * Datasheets for the 21143 are available at developer.intel.com.
+ * Datasheets for the clone parts can be found at their respective sites.
+ * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.)
+ * The PNIC II is essentially a Macronix 98715A chip; the only difference
+ * worth noting is that its multicast hash table is only 128 bits wide
+ * instead of 512.
+ *
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The Intel 21143 is the successor to the DEC 21140. It is basically
+ * the same as the 21140 but with a few new features. The 21143 supports
+ * three kinds of media attachments:
+ *
+ * o MII port, for 10Mbps and 100Mbps support and NWAY
+ * autonegotiation provided by an external PHY.
+ * o SYM port, for symbol mode 100Mbps support.
+ * o 10baseT port.
+ * o AUI/BNC port.
+ *
+ * The 100Mbps SYM port and 10baseT port can be used together in
+ * combination with the internal NWAY support to create a 10/100
+ * autosensing configuration.
+ *
+ * Note that not all tulip workalikes are handled in this driver: we only
+ * deal with those which are relatively well behaved. The Winbond is
+ * handled separately due to its different register offsets and the
+ * special handling needed for its various bugs. The PNIC is handled
+ * here, but I'm not thrilled about it.
+ *
+ * All of the workalike chips use some form of MII transceiver support
+ * with the exception of the Macronix chips, which also have a SYM port.
+ * The ASIX AX88140A is also documented to have a SYM port, but all
+ * the cards I've seen use an MII transceiver, probably because the
+ * AX88140A doesn't support internal NWAY.
+ */
+
+#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/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define DC_USEIOSPACE
+#ifdef __alpha__
+#define SRM_MEDIA
+#endif
+
+#include <pci/if_dcreg.h>
+
+MODULE_DEPEND(dc, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct dc_type dc_devs[] = {
+ { DC_VENDORID_DEC, DC_DEVICEID_21143,
+ "Intel 21143 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100,
+ "Davicom DM9100 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102,
+ "Davicom DM9102 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102,
+ "Davicom DM9102A 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AL981,
+ "ADMtek AL981 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AN985,
+ "ADMtek AN985 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88140A 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88141 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713A 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98715/98715A 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98715AEC-C 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98725 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98727,
+ "Macronix 98727/98732 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C115,
+ "LC82C115 PNIC II 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c168 PNIC 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c169 PNIC 10/100BaseTX" },
+ { DC_VENDORID_ACCTON, DC_DEVICEID_EN1217,
+ "Accton EN1217 10/100BaseTX" },
+ { DC_VENDORID_ACCTON, DC_DEVICEID_EN2242,
+ "Accton EN2242 MiniPCI 10/100BaseTX" },
+ { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201,
+ "Xircom X3201 10/100BaseTX" },
+ { DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500,
+ "Abocom FE2500 10/100BaseTX" },
+ { DC_VENDORID_CONEXANT, DC_DEVICEID_RS7112,
+ "Conexant LANfinity MiniPCI 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int dc_probe (device_t);
+static int dc_attach (device_t);
+static int dc_detach (device_t);
+static int dc_suspend (device_t);
+static int dc_resume (device_t);
+static void dc_acpi (device_t);
+static struct dc_type *dc_devtype (device_t);
+static int dc_newbuf (struct dc_softc *, int, struct mbuf *);
+static int dc_encap (struct dc_softc *, struct mbuf *, u_int32_t *);
+static int dc_coal (struct dc_softc *, struct mbuf **);
+static void dc_pnic_rx_bug_war (struct dc_softc *, int);
+static int dc_rx_resync (struct dc_softc *);
+static void dc_rxeof (struct dc_softc *);
+static void dc_txeof (struct dc_softc *);
+static void dc_tick (void *);
+static void dc_tx_underrun (struct dc_softc *);
+static void dc_intr (void *);
+static void dc_start (struct ifnet *);
+static int dc_ioctl (struct ifnet *, u_long, caddr_t);
+static void dc_init (void *);
+static void dc_stop (struct dc_softc *);
+static void dc_watchdog (struct ifnet *);
+static void dc_shutdown (device_t);
+static int dc_ifmedia_upd (struct ifnet *);
+static void dc_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void dc_delay (struct dc_softc *);
+static void dc_eeprom_idle (struct dc_softc *);
+static void dc_eeprom_putbyte (struct dc_softc *, int);
+static void dc_eeprom_getword (struct dc_softc *, int, u_int16_t *);
+static void dc_eeprom_getword_pnic
+ (struct dc_softc *, int, u_int16_t *);
+static void dc_eeprom_getword_xircom
+ (struct dc_softc *, int, u_int16_t *);
+static void dc_read_eeprom (struct dc_softc *, caddr_t, int, int, int);
+
+static void dc_mii_writebit (struct dc_softc *, int);
+static int dc_mii_readbit (struct dc_softc *);
+static void dc_mii_sync (struct dc_softc *);
+static void dc_mii_send (struct dc_softc *, u_int32_t, int);
+static int dc_mii_readreg (struct dc_softc *, struct dc_mii_frame *);
+static int dc_mii_writereg (struct dc_softc *, struct dc_mii_frame *);
+static int dc_miibus_readreg (device_t, int, int);
+static int dc_miibus_writereg (device_t, int, int, int);
+static void dc_miibus_statchg (device_t);
+static void dc_miibus_mediainit (device_t);
+
+static void dc_setcfg (struct dc_softc *, int);
+static u_int32_t dc_crc_le (struct dc_softc *, caddr_t);
+static u_int32_t dc_crc_be (caddr_t);
+static void dc_setfilt_21143 (struct dc_softc *);
+static void dc_setfilt_asix (struct dc_softc *);
+static void dc_setfilt_admtek (struct dc_softc *);
+static void dc_setfilt_xircom (struct dc_softc *);
+
+static void dc_setfilt (struct dc_softc *);
+
+static void dc_reset (struct dc_softc *);
+static int dc_list_rx_init (struct dc_softc *);
+static int dc_list_tx_init (struct dc_softc *);
+
+static void dc_parse_21143_srom (struct dc_softc *);
+static void dc_decode_leaf_sia (struct dc_softc *, struct dc_eblock_sia *);
+static void dc_decode_leaf_mii (struct dc_softc *, struct dc_eblock_mii *);
+static void dc_decode_leaf_sym (struct dc_softc *, struct dc_eblock_sym *);
+static void dc_apply_fixup (struct dc_softc *, int);
+
+#ifdef DC_USEIOSPACE
+#define DC_RES SYS_RES_IOPORT
+#define DC_RID DC_PCI_CFBIO
+#else
+#define DC_RES SYS_RES_MEMORY
+#define DC_RID DC_PCI_CFBMA
+#endif
+
+static device_method_t dc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dc_probe),
+ DEVMETHOD(device_attach, dc_attach),
+ DEVMETHOD(device_detach, dc_detach),
+ DEVMETHOD(device_suspend, dc_suspend),
+ DEVMETHOD(device_resume, dc_resume),
+ DEVMETHOD(device_shutdown, dc_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, dc_miibus_readreg),
+ DEVMETHOD(miibus_writereg, dc_miibus_writereg),
+ DEVMETHOD(miibus_statchg, dc_miibus_statchg),
+ DEVMETHOD(miibus_mediainit, dc_miibus_mediainit),
+
+ { 0, 0 }
+};
+
+static driver_t dc_driver = {
+ "dc",
+ dc_methods,
+ sizeof(struct dc_softc)
+};
+
+static devclass_t dc_devclass;
+#ifdef __i386__
+static int dc_quick=1;
+SYSCTL_INT(_hw, OID_AUTO, dc_quick, CTLFLAG_RW,
+ &dc_quick,0,"do not mdevget in dc driver");
+#endif
+
+DRIVER_MODULE(if_dc, cardbus, dc_driver, dc_devclass, 0, 0);
+DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0);
+DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0);
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x))
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x))
+
+#define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x))
+#define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x))
+
+#define IS_MPSAFE 0
+
+static void dc_delay(sc)
+ struct dc_softc *sc;
+{
+ int idx;
+
+ for (idx = (300 / 33) + 1; idx > 0; idx--)
+ CSR_READ_4(sc, DC_BUSCTL);
+}
+
+static void dc_eeprom_idle(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ for (i = 0; i < 25; i++) {
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+ CSR_WRITE_4(sc, DC_SIO, 0x00000000);
+
+ return;
+}
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void dc_eeprom_putbyte(sc, addr)
+ struct dc_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ /*
+ * The AN985 has a 93C66 EEPROM on it instead of
+ * a 93C46. It uses a different bit sequence for
+ * specifying the "read" opcode.
+ */
+ if (DC_IS_CENTAUR(sc) || DC_IS_CONEXANT(sc))
+ d = addr | (DC_EECMD_READ << 2);
+ else
+ d = addr | DC_EECMD_READ;
+
+ /*
+ * Feed in each bit and strobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ SIO_SET(DC_SIO_EE_DATAIN);
+ } else {
+ SIO_CLR(DC_SIO_EE_DATAIN);
+ }
+ dc_delay(sc);
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ * The PNIC 82c168/82c169 has its own non-standard way to read
+ * the EEPROM.
+ */
+static void dc_eeprom_getword_pnic(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int32_t r;
+
+ CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ|addr);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ r = CSR_READ_4(sc, DC_SIO);
+ if (!(r & DC_PN_SIOCTL_BUSY)) {
+ *dest = (u_int16_t)(r & 0xFFFF);
+ return;
+ }
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ * The Xircom X3201 has its own non-standard way to read
+ * the EEPROM, too.
+ */
+static void dc_eeprom_getword_xircom(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ SIO_SET(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ);
+
+ addr *= 2;
+ CSR_WRITE_4(sc, DC_ROM, addr | 0x160);
+ *dest = (u_int16_t)CSR_READ_4(sc, DC_SIO)&0xff;
+ addr += 1;
+ CSR_WRITE_4(sc, DC_ROM, addr | 0x160);
+ *dest |= ((u_int16_t)CSR_READ_4(sc, DC_SIO)&0xff) << 8;
+
+ SIO_CLR(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ);
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void dc_eeprom_getword(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Force EEPROM to idle state. */
+ dc_eeprom_idle(sc);
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ /*
+ * Send address of word we want to read.
+ */
+ dc_eeprom_putbyte(sc, addr);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)
+ word |= i;
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ /* Turn off EEPROM access mode. */
+ dc_eeprom_idle(sc);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void dc_read_eeprom(sc, dest, off, cnt, swap)
+ struct dc_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ if (DC_IS_PNIC(sc))
+ dc_eeprom_getword_pnic(sc, off + i, &word);
+ else if (DC_IS_XIRCOM(sc))
+ dc_eeprom_getword_xircom(sc, off + i, &word);
+ else
+ dc_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+/*
+ * The following two routines are taken from the Macronix 98713
+ * Application Notes pp.19-21.
+ */
+/*
+ * Write a bit to the MII bus.
+ */
+static void dc_mii_writebit(sc, bit)
+ struct dc_softc *sc;
+ int bit;
+{
+ if (bit)
+ CSR_WRITE_4(sc, DC_SIO,
+ DC_SIO_ROMCTL_WRITE|DC_SIO_MII_DATAOUT);
+ else
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+
+ return;
+}
+
+/*
+ * Read a bit from the MII bus.
+ */
+static int dc_mii_readbit(sc)
+ struct dc_softc *sc;
+{
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ|DC_SIO_MII_DIR);
+ CSR_READ_4(sc, DC_SIO);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN)
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void dc_mii_sync(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ for (i = 0; i < 32; i++)
+ dc_mii_writebit(sc, 1);
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void dc_mii_send(sc, bits, cnt)
+ struct dc_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1)
+ dc_mii_writebit(sc, bits & i);
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int dc_mii_readreg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ int i, ack;
+
+ DC_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+
+#ifdef notdef
+ /* Idle bit */
+ dc_mii_writebit(sc, 1);
+ dc_mii_writebit(sc, 0);
+#endif
+
+ /* Check for ack */
+ ack = dc_mii_readbit(sc);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ dc_mii_readbit(sc);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ if (!ack) {
+ if (dc_mii_readbit(sc))
+ frame->mii_data |= i;
+ }
+ }
+
+fail:
+
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ DC_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int dc_mii_writereg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ DC_LOCK(sc);
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_WRITEOP;
+ frame->mii_turnaround = DC_MII_TURNAROUND;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+ dc_mii_send(sc, frame->mii_turnaround, 2);
+ dc_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ DC_UNLOCK(sc);
+
+ return(0);
+}
+
+static int dc_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct dc_mii_frame frame;
+ struct dc_softc *sc;
+ int i, rval, phy_reg = 0;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ /*
+ * Note: both the AL981 and AN985 have internal PHYs,
+ * however the AL981 provides direct access to the PHY
+ * registers while the AN985 uses a serial MII interface.
+ * The AN985's MII interface is also buggy in that you
+ * can read from any MII address (0 to 31), but only address 1
+ * behaves normally. To deal with both cases, we pretend
+ * that the PHY is at MII address 1.
+ */
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ /*
+ * Note: the ukphy probes of the RS7112 report a PHY at
+ * MII address 0 (possibly HomePNA?) and 1 (ethernet)
+ * so we only respond to correct one.
+ */
+ if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR)
+ return(0);
+
+ if (sc->dc_pmode != DC_PMODE_MII) {
+ if (phy == (MII_NPHY - 1)) {
+ switch(reg) {
+ case MII_BMSR:
+ /*
+ * Fake something to make the probe
+ * code think there's a PHY here.
+ */
+ return(BMSR_MEDIAMASK);
+ break;
+ case MII_PHYIDR1:
+ if (DC_IS_PNIC(sc))
+ return(DC_VENDORID_LO);
+ return(DC_VENDORID_DEC);
+ break;
+ case MII_PHYIDR2:
+ if (DC_IS_PNIC(sc))
+ return(DC_DEVICEID_82C168);
+ return(DC_DEVICEID_21143);
+ break;
+ default:
+ return(0);
+ break;
+ }
+ } else
+ return(0);
+ }
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_READ |
+ (phy << 23) | (reg << 18));
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ rval = CSR_READ_4(sc, DC_PN_MII);
+ if (!(rval & DC_PN_MII_BUSY)) {
+ rval &= 0xFFFF;
+ return(rval == 0xFFFF ? 0 : rval);
+ }
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_read: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF;
+
+ if (rval == 0xFFFF)
+ return(0);
+ return(rval);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ if (sc->dc_type == DC_TYPE_98713) {
+ phy_reg = CSR_READ_4(sc, DC_NETCFG);
+ CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL);
+ }
+ dc_mii_readreg(sc, &frame);
+ if (sc->dc_type == DC_TYPE_98713)
+ CSR_WRITE_4(sc, DC_NETCFG, phy_reg);
+
+ return(frame.mii_data);
+}
+
+static int dc_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct dc_softc *sc;
+ struct dc_mii_frame frame;
+ int i, phy_reg = 0;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR)
+ return(0);
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE |
+ (phy << 23) | (reg << 10) | data);
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, DC_PN_MII) & DC_PN_MII_BUSY))
+ break;
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_write: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ CSR_WRITE_4(sc, phy_reg, data);
+ return(0);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ if (sc->dc_type == DC_TYPE_98713) {
+ phy_reg = CSR_READ_4(sc, DC_NETCFG);
+ CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL);
+ }
+ dc_mii_writereg(sc, &frame);
+ if (sc->dc_type == DC_TYPE_98713)
+ CSR_WRITE_4(sc, DC_NETCFG, phy_reg);
+
+ return(0);
+}
+
+static void dc_miibus_statchg(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifmedia *ifm;
+
+ sc = device_get_softc(dev);
+ if (DC_IS_ADMTEK(sc))
+ return;
+
+ mii = device_get_softc(sc->dc_miibus);
+ ifm = &mii->mii_media;
+ if (DC_IS_DAVICOM(sc) &&
+ IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) {
+ dc_setcfg(sc, ifm->ifm_media);
+ sc->dc_if_media = ifm->ifm_media;
+ } else {
+ dc_setcfg(sc, mii->mii_media_active);
+ sc->dc_if_media = mii->mii_media_active;
+ }
+
+ return;
+}
+
+/*
+ * Special support for DM9102A cards with HomePNA PHYs. Note:
+ * with the Davicom DM9102A/DM9801 eval board that I have, it seems
+ * to be impossible to talk to the management interface of the DM9801
+ * PHY (its MDIO pin is not connected to anything). Consequently,
+ * the driver has to just 'know' about the additional mode and deal
+ * with it itself. *sigh*
+ */
+static void dc_miibus_mediainit(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifmedia *ifm;
+ int rev;
+
+ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->dc_miibus);
+ ifm = &mii->mii_media;
+
+ if (DC_IS_DAVICOM(sc) && rev >= DC_REVISION_DM9102A)
+ ifmedia_add(ifm, IFM_ETHER|IFM_HPNA_1, 0, NULL);
+
+ return;
+}
+
+#define DC_POLY 0xEDB88320
+#define DC_BITS_512 9
+#define DC_BITS_128 7
+#define DC_BITS_64 6
+
+static u_int32_t dc_crc_le(sc, addr)
+ struct dc_softc *sc;
+ caddr_t addr;
+{
+ u_int32_t idx, bit, data, crc;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0);
+ }
+
+ /*
+ * The hash table on the PNIC II and the MX98715AEC-C/D/E
+ * chips is only 128 bits wide.
+ */
+ if (sc->dc_flags & DC_128BIT_HASH)
+ return (crc & ((1 << DC_BITS_128) - 1));
+
+ /* The hash table on the MX98715BEC is only 64 bits wide. */
+ if (sc->dc_flags & DC_64BIT_HASH)
+ return (crc & ((1 << DC_BITS_64) - 1));
+
+ /* Xircom's hash filtering table is different (read: weird) */
+ /* Xircom uses the LEAST significant bits */
+ if (DC_IS_XIRCOM(sc)) {
+ if ((crc & 0x180) == 0x180)
+ return (crc & 0x0F) + (crc & 0x70)*3 + (14 << 4);
+ else
+ return (crc & 0x1F) + ((crc>>1) & 0xF0)*3 + (12 << 4);
+ }
+
+ return (crc & ((1 << DC_BITS_512) - 1));
+}
+
+/*
+ * Calculate CRC of a multicast group address, return the lower 6 bits.
+ */
+static u_int32_t dc_crc_be(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return((crc >> 26) & 0x0000003F);
+}
+
+/*
+ * 21143-style RX filter setup routine. Filter programming is done by
+ * downloading a special setup frame into the TX engine. 21143, Macronix,
+ * PNIC, PNIC II and Davicom chips are programmed this way.
+ *
+ * We always program the chip using 'hash perfect' mode, i.e. one perfect
+ * address (our node address) and a 512-bit hash filter for multicast
+ * frames. We also sneak the broadcast address into the hash filter since
+ * we need that too.
+ */
+void dc_setfilt_21143(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *sframe;
+ u_int32_t h, *sp;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+
+ i = sc->dc_cdata.dc_tx_prod;
+ DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
+ sc->dc_cdata.dc_tx_cnt++;
+ sframe = &sc->dc_ldata->dc_tx_list[i];
+ sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf;
+ bzero((char *)sp, DC_SFRAME_LEN);
+
+ sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf);
+ sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK |
+ DC_FILTER_HASHPERF | DC_TXCTL_FINT;
+
+ sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_le(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ h = dc_crc_le(sc, (caddr_t)&etherbroadcastaddr);
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ /* Set our MAC address */
+ sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
+ sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
+ sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
+
+ sframe->dc_status = DC_TXSTAT_OWN;
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * The PNIC takes an exceedingly long time to process its
+ * setup frame; wait 10ms after posting the setup frame
+ * before proceeding, just so it has time to swallow its
+ * medicine.
+ */
+ DELAY(10000);
+
+ ifp->if_timer = 5;
+
+ return;
+}
+
+void dc_setfilt_admtek(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AL_MAR0, 0);
+ CSR_WRITE_4(sc, DC_AL_MAR1, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]);
+
+ return;
+}
+
+void dc_setfilt_asix(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /*
+ * The ASIX chip has a special bit to enable reception
+ * of broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST)
+ DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]);
+
+ return;
+}
+
+void dc_setfilt_xircom(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *sframe;
+ u_int32_t h, *sp;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON));
+
+ i = sc->dc_cdata.dc_tx_prod;
+ DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
+ sc->dc_cdata.dc_tx_cnt++;
+ sframe = &sc->dc_ldata->dc_tx_list[i];
+ sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf;
+ bzero((char *)sp, DC_SFRAME_LEN);
+
+ sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf);
+ sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK |
+ DC_FILTER_HASHPERF | DC_TXCTL_FINT;
+
+ sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_le(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ h = dc_crc_le(sc, (caddr_t)&etherbroadcastaddr);
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ /* Set our MAC address */
+ sp[0] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
+ sp[1] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
+ sp[2] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
+
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
+ ifp->if_flags |= IFF_RUNNING;
+ sframe->dc_status = DC_TXSTAT_OWN;
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * wait some time...
+ */
+ DELAY(1000);
+
+ ifp->if_timer = 5;
+
+ return;
+}
+
+static void dc_setfilt(sc)
+ struct dc_softc *sc;
+{
+ if (DC_IS_INTEL(sc) || DC_IS_MACRONIX(sc) || DC_IS_PNIC(sc) ||
+ DC_IS_PNICII(sc) || DC_IS_DAVICOM(sc) || DC_IS_CONEXANT(sc))
+ dc_setfilt_21143(sc);
+
+ if (DC_IS_ASIX(sc))
+ dc_setfilt_asix(sc);
+
+ if (DC_IS_ADMTEK(sc))
+ dc_setfilt_admtek(sc);
+
+ if (DC_IS_XIRCOM(sc))
+ dc_setfilt_xircom(sc);
+
+ return;
+}
+
+/*
+ * In order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void dc_setcfg(sc, media)
+ struct dc_softc *sc;
+ int media;
+{
+ int i, restart = 0;
+ u_int32_t isr;
+
+ if (IFM_SUBTYPE(media) == IFM_NONE)
+ return;
+
+ if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)) {
+ restart = 1;
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON));
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ isr = CSR_READ_4(sc, DC_ISR);
+ if (isr & DC_ISR_TX_IDLE &&
+ (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED)
+ break;
+ DELAY(10);
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: failed to force tx and "
+ "rx to idle state\n", sc->dc_unit);
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_100_TX) {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ int watchdogreg;
+
+ if (DC_IS_INTEL(sc)) {
+ /* there's a write enable bit here that reads as 1 */
+ watchdogreg = CSR_READ_4(sc, DC_WATCHDOG);
+ watchdogreg &= ~DC_WDOG_CTLWREN;
+ watchdogreg |= DC_WDOG_JABBERDIS;
+ CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg);
+ } else {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ }
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER));
+ if (!DC_IS_DAVICOM(sc))
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ if (DC_IS_INTEL(sc))
+ dc_apply_fixup(sc, IFM_AUTO);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER);
+ if (DC_IS_INTEL(sc))
+ dc_apply_fixup(sc,
+ (media & IFM_GMASK) == IFM_FDX ?
+ IFM_100_TX|IFM_FDX : IFM_100_TX);
+ }
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ int watchdogreg;
+
+ /* there's a write enable bit here that reads as 1 */
+ if (DC_IS_INTEL(sc)) {
+ watchdogreg = CSR_READ_4(sc, DC_WATCHDOG);
+ watchdogreg &= ~DC_WDOG_CTLWREN;
+ watchdogreg |= DC_WDOG_JABBERDIS;
+ CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg);
+ } else {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ }
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ if (!DC_IS_DAVICOM(sc))
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ if (DC_IS_INTEL(sc))
+ dc_apply_fixup(sc, IFM_AUTO);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER);
+ if (DC_IS_INTEL(sc)) {
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ if ((media & IFM_GMASK) == IFM_FDX)
+ DC_SETBIT(sc, DC_10BTCTRL, 0x7F3D);
+ else
+ DC_SETBIT(sc, DC_10BTCTRL, 0x7F3F);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(sc, DC_10BTCTRL,
+ DC_TCTL_AUTONEGENBL);
+ dc_apply_fixup(sc,
+ (media & IFM_GMASK) == IFM_FDX ?
+ IFM_10_T|IFM_FDX : IFM_10_T);
+ DELAY(20000);
+ }
+ }
+ }
+
+ /*
+ * If this is a Davicom DM9102A card with a DM9801 HomePNA
+ * PHY and we want HomePNA mode, set the portsel bit to turn
+ * on the external MII port.
+ */
+ if (DC_IS_DAVICOM(sc)) {
+ if (IFM_SUBTYPE(media) == IFM_HPNA_1) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ sc->dc_link = 1;
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ }
+
+ if (restart)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON|DC_NETCFG_RX_ON);
+
+ return;
+}
+
+static void dc_reset(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, DC_BUSCTL) & DC_BUSCTL_RESET))
+ break;
+ }
+
+ if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_CONEXANT(sc) ||
+ DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) {
+ DELAY(10000);
+ DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+ i = 0;
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: reset never completed!\n", sc->dc_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_BUSCTL, 0x00000000);
+ CSR_WRITE_4(sc, DC_NETCFG, 0x00000000);
+
+ /*
+ * Bring the SIA out of reset. In some cases, it looks
+ * like failing to unreset the SIA soon enough gets it
+ * into a state where it will never come out of reset
+ * until we reset the whole chip again.
+ */
+ if (DC_IS_INTEL(sc)) {
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ CSR_WRITE_4(sc, DC_10BTCTRL, 0);
+ CSR_WRITE_4(sc, DC_WATCHDOG, 0);
+ }
+
+ return;
+}
+
+static struct dc_type *dc_devtype(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+ u_int32_t rev;
+
+ t = dc_devs;
+
+ while(t->dc_name != NULL) {
+ if ((pci_get_vendor(dev) == t->dc_vid) &&
+ (pci_get_device(dev) == t->dc_did)) {
+ /* Check the PCI revision */
+ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF;
+ if (t->dc_did == DC_DEVICEID_98713 &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_98713_CP &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_987x5 &&
+ rev >= DC_REVISION_98715AEC_C)
+ t++;
+ if (t->dc_did == DC_DEVICEID_987x5 &&
+ rev >= DC_REVISION_98725)
+ t++;
+ if (t->dc_did == DC_DEVICEID_AX88140A &&
+ rev >= DC_REVISION_88141)
+ t++;
+ if (t->dc_did == DC_DEVICEID_82C168 &&
+ rev >= DC_REVISION_82C169)
+ t++;
+ if (t->dc_did == DC_DEVICEID_DM9102 &&
+ rev >= DC_REVISION_DM9102A)
+ t++;
+ return(t);
+ }
+ t++;
+ }
+
+ return(NULL);
+}
+
+/*
+ * Probe for a 21143 or clone chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ * We do a little bit of extra work to identify the exact type of
+ * chip. The MX98713 and MX98713A have the same PCI vendor/device ID,
+ * but different revision IDs. The same is true for 98715/98715A
+ * chips and the 98725, as well as the ASIX and ADMtek chips. In some
+ * cases, the exact chip revision affects driver behavior.
+ */
+static int dc_probe(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+
+ t = dc_devtype(dev);
+
+ if (t != NULL) {
+ device_set_desc(dev, t->dc_name);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static void dc_acpi(dev)
+ device_t dev;
+{
+ int unit;
+
+ unit = device_get_unit(dev);
+
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, DC_PCI_CFBIO, 4);
+ membase = pci_read_config(dev, DC_PCI_CFBMA, 4);
+ irq = pci_read_config(dev, DC_PCI_CFIT, 4);
+
+ /* Reset the power state. */
+ printf("dc%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, DC_PCI_CFBIO, iobase, 4);
+ pci_write_config(dev, DC_PCI_CFBMA, membase, 4);
+ pci_write_config(dev, DC_PCI_CFIT, irq, 4);
+ }
+
+ return;
+}
+
+static void dc_apply_fixup(sc, media)
+ struct dc_softc *sc;
+ int media;
+{
+ struct dc_mediainfo *m;
+ u_int8_t *p;
+ int i;
+ u_int32_t reg;
+
+ m = sc->dc_mi;
+
+ while (m != NULL) {
+ if (m->dc_media == media)
+ break;
+ m = m->dc_next;
+ }
+
+ if (m == NULL)
+ return;
+
+ for (i = 0, p = m->dc_reset_ptr; i < m->dc_reset_len; i++, p += 2) {
+ reg = (p[0] | (p[1] << 8)) << 16;
+ CSR_WRITE_4(sc, DC_WATCHDOG, reg);
+ }
+
+ for (i = 0, p = m->dc_gp_ptr; i < m->dc_gp_len; i++, p += 2) {
+ reg = (p[0] | (p[1] << 8)) << 16;
+ CSR_WRITE_4(sc, DC_WATCHDOG, reg);
+ }
+
+ return;
+}
+
+static void dc_decode_leaf_sia(sc, l)
+ struct dc_softc *sc;
+ struct dc_eblock_sia *l;
+{
+ struct dc_mediainfo *m;
+
+ m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT);
+ bzero(m, sizeof(struct dc_mediainfo));
+ if (l->dc_sia_code == DC_SIA_CODE_10BT)
+ m->dc_media = IFM_10_T;
+
+ if (l->dc_sia_code == DC_SIA_CODE_10BT_FDX)
+ m->dc_media = IFM_10_T|IFM_FDX;
+
+ if (l->dc_sia_code == DC_SIA_CODE_10B2)
+ m->dc_media = IFM_10_2;
+
+ if (l->dc_sia_code == DC_SIA_CODE_10B5)
+ m->dc_media = IFM_10_5;
+
+ m->dc_gp_len = 2;
+ m->dc_gp_ptr = (u_int8_t *)&l->dc_sia_gpio_ctl;
+
+ m->dc_next = sc->dc_mi;
+ sc->dc_mi = m;
+
+ sc->dc_pmode = DC_PMODE_SIA;
+
+ return;
+}
+
+static void dc_decode_leaf_sym(sc, l)
+ struct dc_softc *sc;
+ struct dc_eblock_sym *l;
+{
+ struct dc_mediainfo *m;
+
+ m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT);
+ bzero(m, sizeof(struct dc_mediainfo));
+ if (l->dc_sym_code == DC_SYM_CODE_100BT)
+ m->dc_media = IFM_100_TX;
+
+ if (l->dc_sym_code == DC_SYM_CODE_100BT_FDX)
+ m->dc_media = IFM_100_TX|IFM_FDX;
+
+ m->dc_gp_len = 2;
+ m->dc_gp_ptr = (u_int8_t *)&l->dc_sym_gpio_ctl;
+
+ m->dc_next = sc->dc_mi;
+ sc->dc_mi = m;
+
+ sc->dc_pmode = DC_PMODE_SYM;
+
+ return;
+}
+
+static void dc_decode_leaf_mii(sc, l)
+ struct dc_softc *sc;
+ struct dc_eblock_mii *l;
+{
+ u_int8_t *p;
+ struct dc_mediainfo *m;
+
+ m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT);
+ bzero(m, sizeof(struct dc_mediainfo));
+ /* We abuse IFM_AUTO to represent MII. */
+ m->dc_media = IFM_AUTO;
+ m->dc_gp_len = l->dc_gpr_len;
+
+ p = (u_int8_t *)l;
+ p += sizeof(struct dc_eblock_mii);
+ m->dc_gp_ptr = p;
+ p += 2 * l->dc_gpr_len;
+ m->dc_reset_len = *p;
+ p++;
+ m->dc_reset_ptr = p;
+
+ m->dc_next = sc->dc_mi;
+ sc->dc_mi = m;
+
+ return;
+}
+
+static void dc_parse_21143_srom(sc)
+ struct dc_softc *sc;
+{
+ struct dc_leaf_hdr *lhdr;
+ struct dc_eblock_hdr *hdr;
+ int i, loff;
+ char *ptr;
+
+ loff = sc->dc_srom[27];
+ lhdr = (struct dc_leaf_hdr *)&(sc->dc_srom[loff]);
+
+ ptr = (char *)lhdr;
+ ptr += sizeof(struct dc_leaf_hdr) - 1;
+ for (i = 0; i < lhdr->dc_mcnt; i++) {
+ hdr = (struct dc_eblock_hdr *)ptr;
+ switch(hdr->dc_type) {
+ case DC_EBLOCK_MII:
+ dc_decode_leaf_mii(sc, (struct dc_eblock_mii *)hdr);
+ break;
+ case DC_EBLOCK_SIA:
+ dc_decode_leaf_sia(sc, (struct dc_eblock_sia *)hdr);
+ break;
+ case DC_EBLOCK_SYM:
+ dc_decode_leaf_sym(sc, (struct dc_eblock_sym *)hdr);
+ break;
+ default:
+ /* Don't care. Yet. */
+ break;
+ }
+ ptr += (hdr->dc_len & 0x7F);
+ ptr++;
+ }
+
+ return;
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int dc_attach(dev)
+ device_t dev;
+{
+ int tmp = 0;
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t revision;
+ int unit, error = 0, rid, mac_offset;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct dc_softc));
+
+ mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+
+ /*
+ * Handle power management nonsense.
+ */
+ dc_acpi(dev);
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef DC_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("dc%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail_nolock;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("dc%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail_nolock;
+ }
+#endif
+
+ rid = DC_RID;
+ sc->dc_res = bus_alloc_resource(dev, DC_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->dc_res == NULL) {
+ printf("dc%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail_nolock;
+ }
+
+ sc->dc_btag = rman_get_bustag(sc->dc_res);
+ sc->dc_bhandle = rman_get_bushandle(sc->dc_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->dc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->dc_irq == NULL) {
+ printf("dc%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail_nolock;
+ }
+
+ error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET |
+ (IS_MPSAFE ? INTR_MPSAFE : 0),
+ dc_intr, sc, &sc->dc_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ printf("dc%d: couldn't set up irq\n", unit);
+ goto fail_nolock;
+ }
+ DC_LOCK(sc);
+
+ /* Need this info to decide on a chip type. */
+ sc->dc_info = dc_devtype(dev);
+ revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF;
+
+ switch(sc->dc_info->dc_did) {
+ case DC_DEVICEID_21143:
+ sc->dc_type = DC_TYPE_21143;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ /* Save EEPROM contents so we can parse them later. */
+ dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 512, 0);
+ break;
+ case DC_DEVICEID_DM9100:
+ case DC_DEVICEID_DM9102:
+ sc->dc_type = DC_TYPE_DM9102;
+ sc->dc_flags |= DC_TX_COALESCE|DC_TX_INTR_ALWAYS;
+ sc->dc_flags |= DC_REDUCED_MII_POLL|DC_TX_STORENFWD;
+ sc->dc_pmode = DC_PMODE_MII;
+ /* Increase the latency timer value. */
+ command = pci_read_config(dev, DC_PCI_CFLT, 4);
+ command &= 0xFFFF00FF;
+ command |= 0x00008000;
+ pci_write_config(dev, DC_PCI_CFLT, command, 4);
+ break;
+ case DC_DEVICEID_AL981:
+ sc->dc_type = DC_TYPE_AL981;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_AN985:
+ case DC_DEVICEID_FE2500:
+ case DC_DEVICEID_EN2242:
+ sc->dc_type = DC_TYPE_AN985;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_98713:
+ case DC_DEVICEID_98713_CP:
+ if (revision < DC_REVISION_98713A) {
+ sc->dc_type = DC_TYPE_98713;
+ }
+ if (revision >= DC_REVISION_98713A) {
+ sc->dc_type = DC_TYPE_98713A;
+ sc->dc_flags |= DC_21143_NWAY;
+ }
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_987x5:
+ case DC_DEVICEID_EN1217:
+ /*
+ * Macronix MX98715AEC-C/D/E parts have only a
+ * 128-bit hash table. We need to deal with these
+ * in the same manner as the PNIC II so that we
+ * get the right number of bits out of the
+ * CRC routine.
+ */
+ if (revision >= DC_REVISION_98715AEC_C &&
+ revision < DC_REVISION_98725)
+ sc->dc_flags |= DC_128BIT_HASH;
+ sc->dc_type = DC_TYPE_987x5;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL|DC_21143_NWAY;
+ break;
+ case DC_DEVICEID_98727:
+ sc->dc_type = DC_TYPE_987x5;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL|DC_21143_NWAY;
+ break;
+ case DC_DEVICEID_82C115:
+ sc->dc_type = DC_TYPE_PNICII;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR|DC_128BIT_HASH;
+ sc->dc_flags |= DC_REDUCED_MII_POLL|DC_21143_NWAY;
+ break;
+ case DC_DEVICEID_82C168:
+ sc->dc_type = DC_TYPE_PNIC;
+ sc->dc_flags |= DC_TX_STORENFWD|DC_TX_INTR_ALWAYS;
+ sc->dc_flags |= DC_PNIC_RX_BUG_WAR;
+ sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT);
+ if (revision < DC_REVISION_82C169)
+ sc->dc_pmode = DC_PMODE_SYM;
+ break;
+ case DC_DEVICEID_AX88140A:
+ sc->dc_type = DC_TYPE_ASIX;
+ sc->dc_flags |= DC_TX_USE_TX_INTR|DC_TX_INTR_FIRSTFRAG;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_X3201:
+ sc->dc_type = DC_TYPE_XIRCOM;
+ sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE |
+ DC_TX_ALIGN;
+ /*
+ * We don't actually need to coalesce, but we're doing
+ * it to obtain a double word aligned buffer.
+ * The DC_TX_COALESCE flag is required.
+ */
+ break;
+ case DC_DEVICEID_RS7112:
+ sc->dc_type = DC_TYPE_CONEXANT;
+ sc->dc_flags |= DC_TX_INTR_ALWAYS;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 256, 0);
+ break;
+ default:
+ printf("dc%d: unknown device: %x\n", sc->dc_unit,
+ sc->dc_info->dc_did);
+ break;
+ }
+
+ /* Save the cache line size. */
+ if (DC_IS_DAVICOM(sc))
+ sc->dc_cachesize = 0;
+ else
+ sc->dc_cachesize = pci_read_config(dev,
+ DC_PCI_CFLT, 4) & 0xFF;
+
+ /* Reset the adapter. */
+ dc_reset(sc);
+
+ /* Take 21143 out of snooze mode */
+ if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) {
+ command = pci_read_config(dev, DC_PCI_CFDD, 4);
+ command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE);
+ pci_write_config(dev, DC_PCI_CFDD, command, 4);
+ }
+
+ /*
+ * Try to learn something about the supported media.
+ * We know that ASIX and ADMtek and Davicom devices
+ * will *always* be using MII media, so that's a no-brainer.
+ * The tricky ones are the Macronix/PNIC II and the
+ * Intel 21143.
+ */
+ if (DC_IS_INTEL(sc))
+ dc_parse_21143_srom(sc);
+ else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ if (sc->dc_type == DC_TYPE_98713)
+ sc->dc_pmode = DC_PMODE_MII;
+ else
+ sc->dc_pmode = DC_PMODE_SYM;
+ } else if (!sc->dc_pmode)
+ sc->dc_pmode = DC_PMODE_MII;
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ switch(sc->dc_type) {
+ case DC_TYPE_98713:
+ case DC_TYPE_98713A:
+ case DC_TYPE_987x5:
+ case DC_TYPE_PNICII:
+ dc_read_eeprom(sc, (caddr_t)&mac_offset,
+ (DC_EE_NODEADDR_OFFSET / 2), 1, 0);
+ dc_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0);
+ break;
+ case DC_TYPE_PNIC:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1);
+ break;
+ case DC_TYPE_DM9102:
+ case DC_TYPE_21143:
+ case DC_TYPE_ASIX:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ case DC_TYPE_AL981:
+ case DC_TYPE_AN985:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
+ break;
+ case DC_TYPE_CONEXANT:
+ bcopy(sc->dc_srom + DC_CONEXANT_EE_NODEADDR, &eaddr, 6);
+ break;
+ case DC_TYPE_XIRCOM:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, 3, 3, 0);
+ break;
+ default:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ }
+
+ /*
+ * A 21143 or clone chip was detected. Inform the world.
+ */
+ printf("dc%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->dc_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->dc_ldata = contigmalloc(sizeof(struct dc_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->dc_ldata == NULL) {
+ printf("dc%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->dc_ldata, sizeof(struct dc_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "dc";
+ /* XXX: bleah, MTU gets overwritten in ether_ifattach() */
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = dc_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = dc_start;
+ ifp->if_watchdog = dc_watchdog;
+ ifp->if_init = dc_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup. If this is a 21143, check for a PHY on the
+ * MII bus after applying any necessary fixups to twiddle the
+ * GPIO bits. If we don't end up finding a PHY, restore the
+ * old selection (SIA only or SIA/SYM) and attach the dcphy
+ * driver instead.
+ */
+ if (DC_IS_INTEL(sc)) {
+ dc_apply_fixup(sc, IFM_AUTO);
+ tmp = sc->dc_pmode;
+ sc->dc_pmode = DC_PMODE_MII;
+ }
+
+ error = mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+
+ if (error && DC_IS_INTEL(sc)) {
+ sc->dc_pmode = tmp;
+ if (sc->dc_pmode != DC_PMODE_SIA)
+ sc->dc_pmode = DC_PMODE_SYM;
+ sc->dc_flags |= DC_21143_NWAY;
+ mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+ /*
+ * For non-MII cards, we need to have the 21143
+ * drive the LEDs. Except there are some systems
+ * like the NEC VersaPro NoteBook PC which have no
+ * LEDs, and twiddling these bits has adverse effects
+ * on them. (I.e. you suddenly can't get a link.)
+ */
+ if (pci_read_config(dev, DC_PCI_CSID, 4) != 0x80281033)
+ sc->dc_flags |= DC_TULIP_LEDS;
+ error = 0;
+ }
+
+ if (error) {
+ printf("dc%d: MII without any PHY!\n", sc->dc_unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ if (DC_IS_XIRCOM(sc)) {
+ /*
+ * setup General Purpose Port mode and data so the tulip
+ * can talk to the MII.
+ */
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+
+ /*
+ * Tell the upper layer(s) we support long frames.
+ */
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+
+ callout_init(&sc->dc_stat_ch, IS_MPSAFE);
+
+#ifdef SRM_MEDIA
+ sc->dc_srm_media = 0;
+
+ /* Remember the SRM console media setting */
+ if (DC_IS_INTEL(sc)) {
+ command = pci_read_config(dev, DC_PCI_CFDD, 4);
+ command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE);
+ switch ((command >> 8) & 0xff) {
+ case 3:
+ sc->dc_srm_media = IFM_10_T;
+ break;
+ case 4:
+ sc->dc_srm_media = IFM_10_T | IFM_FDX;
+ break;
+ case 5:
+ sc->dc_srm_media = IFM_100_TX;
+ break;
+ case 6:
+ sc->dc_srm_media = IFM_100_TX | IFM_FDX;
+ break;
+ }
+ if (sc->dc_srm_media)
+ sc->dc_srm_media |= IFM_ACTIVE | IFM_ETHER;
+ }
+#endif
+
+ DC_UNLOCK(sc);
+ return(0);
+
+fail:
+ DC_UNLOCK(sc);
+fail_nolock:
+ mtx_destroy(&sc->dc_mtx);
+ return(error);
+}
+
+static int dc_detach(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ struct dc_mediainfo *m;
+
+ sc = device_get_softc(dev);
+
+ DC_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ dc_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->dc_miibus);
+
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+
+ contigfree(sc->dc_ldata, sizeof(struct dc_list_data), M_DEVBUF);
+ if (sc->dc_pnic_rx_buf != NULL)
+ free(sc->dc_pnic_rx_buf, M_DEVBUF);
+
+ while(sc->dc_mi != NULL) {
+ m = sc->dc_mi->dc_next;
+ free(sc->dc_mi, M_DEVBUF);
+ sc->dc_mi = m;
+ }
+
+ DC_UNLOCK(sc);
+ mtx_destroy(&sc->dc_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int dc_list_tx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i, nexti;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ nexti = (i == (DC_TX_LIST_CNT - 1)) ? 0 : i+1;
+ ld->dc_tx_list[i].dc_next = vtophys(&ld->dc_tx_list[nexti]);
+ cd->dc_tx_chain[i] = NULL;
+ ld->dc_tx_list[i].dc_data = 0;
+ ld->dc_tx_list[i].dc_ctl = 0;
+ }
+
+ cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int dc_list_rx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i, nexti;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (dc_newbuf(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ nexti = (i == (DC_RX_LIST_CNT - 1)) ? 0 : i+1;
+ ld->dc_rx_list[i].dc_next = vtophys(&ld->dc_rx_list[nexti]);
+ }
+
+ cd->dc_rx_prod = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int dc_newbuf(sc, i, m)
+ struct dc_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct dc_desc *c;
+
+ c = &sc->dc_ldata->dc_rx_list[i];
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ /*
+ * If this is a PNIC chip, zero the buffer. This is part
+ * of the workaround for the receive bug in the 82c168 and
+ * 82c169 chips.
+ */
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR)
+ bzero((char *)mtod(m_new, char *), m_new->m_len);
+
+ sc->dc_cdata.dc_rx_chain[i] = m_new;
+ c->dc_data = vtophys(mtod(m_new, caddr_t));
+ c->dc_ctl = DC_RXCTL_RLINK | DC_RXLEN;
+ c->dc_status = DC_RXSTAT_OWN;
+
+ return(0);
+}
+
+/*
+ * Grrrrr.
+ * The PNIC chip has a terrible bug in it that manifests itself during
+ * periods of heavy activity. The exact mode of failure if difficult to
+ * pinpoint: sometimes it only happens in promiscuous mode, sometimes it
+ * will happen on slow machines. The bug is that sometimes instead of
+ * uploading one complete frame during reception, it uploads what looks
+ * like the entire contents of its FIFO memory. The frame we want is at
+ * the end of the whole mess, but we never know exactly how much data has
+ * been uploaded, so salvaging the frame is hard.
+ *
+ * There is only one way to do it reliably, and it's disgusting.
+ * Here's what we know:
+ *
+ * - We know there will always be somewhere between one and three extra
+ * descriptors uploaded.
+ *
+ * - We know the desired received frame will always be at the end of the
+ * total data upload.
+ *
+ * - We know the size of the desired received frame because it will be
+ * provided in the length field of the status word in the last descriptor.
+ *
+ * Here's what we do:
+ *
+ * - When we allocate buffers for the receive ring, we bzero() them.
+ * This means that we know that the buffer contents should be all
+ * zeros, except for data uploaded by the chip.
+ *
+ * - We also force the PNIC chip to upload frames that include the
+ * ethernet CRC at the end.
+ *
+ * - We gather all of the bogus frame data into a single buffer.
+ *
+ * - We then position a pointer at the end of this buffer and scan
+ * backwards until we encounter the first non-zero byte of data.
+ * This is the end of the received frame. We know we will encounter
+ * some data at the end of the frame because the CRC will always be
+ * there, so even if the sender transmits a packet of all zeros,
+ * we won't be fooled.
+ *
+ * - We know the size of the actual received frame, so we subtract
+ * that value from the current pointer location. This brings us
+ * to the start of the actual received packet.
+ *
+ * - We copy this into an mbuf and pass it on, along with the actual
+ * frame length.
+ *
+ * The performance hit is tremendous, but it beats dropping frames all
+ * the time.
+ */
+
+#define DC_WHOLEFRAME (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG)
+static void dc_pnic_rx_bug_war(sc, idx)
+ struct dc_softc *sc;
+ int idx;
+{
+ struct dc_desc *cur_rx;
+ struct dc_desc *c = NULL;
+ struct mbuf *m = NULL;
+ unsigned char *ptr;
+ int i, total_len;
+ u_int32_t rxstat = 0;
+
+ i = sc->dc_pnic_rx_bug_save;
+ cur_rx = &sc->dc_ldata->dc_rx_list[idx];
+ ptr = sc->dc_pnic_rx_buf;
+ bzero(ptr, sizeof(DC_RXLEN * 5));
+
+ /* Copy all the bytes from the bogus buffers. */
+ while (1) {
+ c = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = c->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ bcopy(mtod(m, char *), ptr, DC_RXLEN);
+ ptr += DC_RXLEN;
+ /* If this is the last buffer, break out. */
+ if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
+ break;
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ }
+
+ /* Find the length of the actual receive frame. */
+ total_len = DC_RXBYTES(rxstat);
+
+ /* Scan backwards until we hit a non-zero byte. */
+ while(*ptr == 0x00)
+ ptr--;
+
+ /* Round off. */
+ if ((uintptr_t)(ptr) & 0x3)
+ ptr -= 1;
+
+ /* Now find the start of the frame. */
+ ptr -= total_len;
+ if (ptr < sc->dc_pnic_rx_buf)
+ ptr = sc->dc_pnic_rx_buf;
+
+ /*
+ * Now copy the salvaged frame to the last mbuf and fake up
+ * the status word to make it look like a successful
+ * frame reception.
+ */
+ dc_newbuf(sc, i, m);
+ bcopy(ptr, mtod(m, char *), total_len);
+ cur_rx->dc_status = rxstat | DC_RXSTAT_FIRSTFRAG;
+
+ return;
+}
+
+/*
+ * This routine searches the RX ring for dirty descriptors in the
+ * event that the rxeof routine falls out of sync with the chip's
+ * current descriptor pointer. This may happen sometimes as a result
+ * of a "no RX buffer available" condition that happens when the chip
+ * consumes all of the RX buffers before the driver has a chance to
+ * process the RX ring. This routine may need to be called more than
+ * once to bring the driver back in sync with the chip, however we
+ * should still be getting RX DONE interrupts to drive the search
+ * for new packets in the RX ring, so we should catch up eventually.
+ */
+static int dc_rx_resync(sc)
+ struct dc_softc *sc;
+{
+ int i, pos;
+ struct dc_desc *cur_rx;
+
+ pos = sc->dc_cdata.dc_rx_prod;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ cur_rx = &sc->dc_ldata->dc_rx_list[pos];
+ if (!(cur_rx->dc_status & DC_RXSTAT_OWN))
+ break;
+ DC_INC(pos, DC_RX_LIST_CNT);
+ }
+
+ /* If the ring really is empty, then just return. */
+ if (i == DC_RX_LIST_CNT)
+ return(0);
+
+ /* We've fallen behing the chip: catch it. */
+ sc->dc_cdata.dc_rx_prod = pos;
+
+ return(EAGAIN);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void dc_rxeof(sc)
+ struct dc_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct dc_desc *cur_rx;
+ int i, total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+ i = sc->dc_cdata.dc_rx_prod;
+
+ while(!(sc->dc_ldata->dc_rx_list[i].dc_status & DC_RXSTAT_OWN)) {
+
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif /* DEVICE_POLLING */
+ cur_rx = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = cur_rx->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ total_len = DC_RXBYTES(rxstat);
+
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) {
+ if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
+ if (rxstat & DC_RXSTAT_FIRSTFRAG)
+ sc->dc_pnic_rx_bug_save = i;
+ if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ }
+ dc_pnic_rx_bug_war(sc, i);
+ rxstat = cur_rx->dc_status;
+ total_len = DC_RXBYTES(rxstat);
+ }
+ }
+
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring. However, don't report long
+ * frames as errors since they could be vlans
+ */
+ if ((rxstat & DC_RXSTAT_RXERR)){
+ if (!(rxstat & DC_RXSTAT_GIANT) ||
+ (rxstat & (DC_RXSTAT_CRCERR | DC_RXSTAT_DRIBBLE |
+ DC_RXSTAT_MIIERE | DC_RXSTAT_COLLSEEN |
+ DC_RXSTAT_RUNT | DC_RXSTAT_DE))) {
+ ifp->if_ierrors++;
+ if (rxstat & DC_RXSTAT_COLLSEEN)
+ ifp->if_collisions++;
+ dc_newbuf(sc, i, m);
+ if (rxstat & DC_RXSTAT_CRCERR) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ } else {
+ dc_init(sc);
+ return;
+ }
+ }
+ }
+
+ /* No errors; receive the packet. */
+ total_len -= ETHER_CRC_LEN;
+#ifdef __i386__
+ /*
+ * On the x86 we do not have alignment problems, so try to
+ * allocate a new buffer for the receive ring, and pass up
+ * the one where the packet is already, saving the expensive
+ * copy done in m_devget().
+ * If we are on an architecture with alignment problems, or
+ * if the allocation fails, then use m_devget and leave the
+ * existing buffer in the receive ring.
+ */
+ if (dc_quick && dc_newbuf(sc, i, NULL) == 0) {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+ DC_INC(i, DC_RX_LIST_CNT);
+ } else
+#endif
+ {
+ struct mbuf *m0;
+
+ m0 = m_devget(mtod(m, char *), total_len,
+ ETHER_ALIGN, ifp, NULL);
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc->dc_cdata.dc_rx_prod = i;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void dc_txeof(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ idx = sc->dc_cdata.dc_tx_cons;
+ while(idx != sc->dc_cdata.dc_tx_prod) {
+ u_int32_t txstat;
+
+ cur_tx = &sc->dc_ldata->dc_tx_list[idx];
+ txstat = cur_tx->dc_status;
+
+ if (txstat & DC_TXSTAT_OWN)
+ break;
+
+ if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) ||
+ cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_cnt--;
+ if (cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ /*
+ * Yes, the PNIC is so brain damaged
+ * that it will sometimes generate a TX
+ * underrun error while DMAing the RX
+ * filter setup frame. If we detect this,
+ * we have to send the setup frame again,
+ * or else the filter won't be programmed
+ * correctly.
+ */
+ if (DC_IS_PNIC(sc)) {
+ if (txstat & DC_TXSTAT_ERRSUM)
+ dc_setfilt(sc);
+ }
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+ DC_INC(idx, DC_TX_LIST_CNT);
+ continue;
+ }
+
+ if (DC_IS_XIRCOM(sc) || DC_IS_CONEXANT(sc)) {
+ /*
+ * XXX: Why does my Xircom taunt me so?
+ * For some reason it likes setting the CARRLOST flag
+ * even when the carrier is there. wtf?!?
+ * Who knows, but Conexant chips have the
+ * same problem. Maybe they took lessons
+ * from Xircom.
+ */
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+ } else {
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+ }
+
+ if (txstat & DC_TXSTAT_ERRSUM) {
+ ifp->if_oerrors++;
+ if (txstat & DC_TXSTAT_EXCESSCOLL)
+ ifp->if_collisions++;
+ if (txstat & DC_TXSTAT_LATECOLL)
+ ifp->if_collisions++;
+ if (!(txstat & DC_TXSTAT_UNDERRUN)) {
+ dc_init(sc);
+ return;
+ }
+ }
+
+ ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3;
+
+ ifp->if_opackets++;
+ if (sc->dc_cdata.dc_tx_chain[idx] != NULL) {
+ m_freem(sc->dc_cdata.dc_tx_chain[idx]);
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+
+ sc->dc_cdata.dc_tx_cnt--;
+ DC_INC(idx, DC_TX_LIST_CNT);
+ }
+
+ sc->dc_cdata.dc_tx_cons = idx;
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void dc_tick(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ u_int32_t r;
+
+ sc = xsc;
+ DC_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->dc_miibus);
+
+ if (sc->dc_flags & DC_REDUCED_MII_POLL) {
+ if (sc->dc_flags & DC_21143_NWAY) {
+ r = CSR_READ_4(sc, DC_10BTSTAT);
+ if (IFM_SUBTYPE(mii->mii_media_active) ==
+ IFM_100_TX && (r & DC_TSTAT_LS100)) {
+ sc->dc_link = 0;
+ mii_mediachg(mii);
+ }
+ if (IFM_SUBTYPE(mii->mii_media_active) ==
+ IFM_10_T && (r & DC_TSTAT_LS10)) {
+ sc->dc_link = 0;
+ mii_mediachg(mii);
+ }
+ if (sc->dc_link == 0)
+ mii_tick(mii);
+ } else {
+ r = CSR_READ_4(sc, DC_ISR);
+ if ((r & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT &&
+ sc->dc_cdata.dc_tx_cnt == 0)
+ mii_tick(mii);
+ if (!(mii->mii_media_status & IFM_ACTIVE))
+ sc->dc_link = 0;
+ }
+ } else
+ mii_tick(mii);
+
+ /*
+ * When the init routine completes, we expect to be able to send
+ * packets right away, and in fact the network code will send a
+ * gratuitous ARP the moment the init routine marks the interface
+ * as running. However, even though the MAC may have been initialized,
+ * there may be a delay of a few seconds before the PHY completes
+ * autonegotiation and the link is brought up. Any transmissions
+ * made during that delay will be lost. Dealing with this is tricky:
+ * we can't just pause in the init routine while waiting for the
+ * PHY to come ready since that would bring the whole system to
+ * a screeching halt for several seconds.
+ *
+ * What we do here is prevent the TX start routine from sending
+ * any packets until a link has been established. After the
+ * interface has been initialized, the tick routine will poll
+ * the state of the PHY until the IFM_ACTIVE flag is set. Until
+ * that time, packets will stay in the send queue, and once the
+ * link comes up, they will be flushed out to the wire.
+ */
+ if (!sc->dc_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->dc_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+ }
+
+ if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link)
+ callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc);
+ else
+ callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc);
+
+ DC_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * A transmit underrun has occurred. Back off the transmit threshold,
+ * or switch to store and forward mode if we have to.
+ */
+static void dc_tx_underrun(sc)
+ struct dc_softc *sc;
+{
+ u_int32_t isr;
+ int i;
+
+ if (DC_IS_DAVICOM(sc))
+ dc_init(sc);
+
+ if (DC_IS_INTEL(sc)) {
+ /*
+ * The real 21143 requires that the transmitter be idle
+ * in order to change the transmit threshold or store
+ * and forward state.
+ */
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ isr = CSR_READ_4(sc, DC_ISR);
+ if (isr & DC_ISR_TX_IDLE)
+ break;
+ DELAY(10);
+ }
+ if (i == DC_TIMEOUT) {
+ printf("dc%d: failed to force tx to idle state\n",
+ sc->dc_unit);
+ dc_init(sc);
+ }
+ }
+
+ printf("dc%d: TX underrun -- ", sc->dc_unit);
+ sc->dc_txthresh += DC_TXTHRESH_INC;
+ if (sc->dc_txthresh > DC_TXTHRESH_MAX) {
+ printf("using store and forward mode\n");
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ printf("increasing TX threshold\n");
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ }
+
+ if (DC_IS_INTEL(sc))
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+
+ return;
+}
+
+#ifdef DEVICE_POLLING
+static poll_handler_t dc_poll;
+
+static void
+dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct dc_softc *sc = ifp->if_softc;
+
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+ return;
+ }
+ sc->rxcycles = count;
+ dc_rxeof(sc);
+ dc_txeof(sc);
+ if (ifp->if_snd.ifq_head != NULL && !(ifp->if_flags & IFF_OACTIVE))
+ dc_start(ifp);
+
+ if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
+ u_int32_t status;
+
+ status = CSR_READ_4(sc, DC_ISR);
+ status &= (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF|
+ DC_ISR_TX_NOBUF|DC_ISR_TX_IDLE|DC_ISR_TX_UNDERRUN|
+ DC_ISR_BUS_ERR);
+ if (!status)
+ return;
+ /* ack what we have */
+ CSR_WRITE_4(sc, DC_ISR, status);
+
+ if (status & (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF)) {
+ u_int32_t r = CSR_READ_4(sc, DC_FRAMESDISCARDED);
+ ifp->if_ierrors += (r & 0xffff) + ((r >> 17) & 0x7ff);
+
+ if (dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ /* restart transmit unit if necessary */
+ if (status & DC_ISR_TX_IDLE && sc->dc_cdata.dc_tx_cnt)
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ if (status & DC_ISR_TX_UNDERRUN)
+ dc_tx_underrun(sc);
+
+ if (status & DC_ISR_BUS_ERR) {
+ printf("dc_poll: dc%d bus error\n", sc->dc_unit);
+ dc_reset(sc);
+ dc_init(sc);
+ }
+ }
+}
+#endif /* DEVICE_POLLING */
+
+static void dc_intr(arg)
+ void *arg;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+
+ if (sc->suspended) {
+ return;
+ }
+
+ if ((CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0)
+ return;
+
+ DC_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING)
+ goto done;
+ if (ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ goto done;
+ }
+#endif /* DEVICE_POLLING */
+
+ /* Suppress unwanted interrupts */
+ if (!(ifp->if_flags & IFF_UP)) {
+ if (CSR_READ_4(sc, DC_ISR) & DC_INTRS)
+ dc_stop(sc);
+ DC_UNLOCK(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+
+ while(((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS)
+ && status != 0xFFFFFFFF) {
+
+ CSR_WRITE_4(sc, DC_ISR, status);
+
+ if (status & DC_ISR_RX_OK) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
+ dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
+
+ if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
+ dc_txeof(sc);
+
+ if (status & DC_ISR_TX_IDLE) {
+ dc_txeof(sc);
+ if (sc->dc_cdata.dc_tx_cnt) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+ }
+ }
+
+ if (status & DC_ISR_TX_UNDERRUN)
+ dc_tx_underrun(sc);
+
+ if ((status & DC_ISR_RX_WATDOGTIMEO)
+ || (status & DC_ISR_RX_NOBUF)) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
+ dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
+
+ if (status & DC_ISR_BUS_ERR) {
+ dc_reset(sc);
+ dc_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+#ifdef DEVICE_POLLING
+done:
+#endif /* DEVICE_POLLING */
+
+ DC_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int dc_encap(sc, m_head, txidx)
+ struct dc_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct dc_desc *f = NULL;
+ struct mbuf *m;
+ int frag, cur, cnt = 0;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (sc->dc_flags & DC_TX_ADMTEK_WAR) {
+ if (*txidx != sc->dc_cdata.dc_tx_prod &&
+ frag == (DC_TX_LIST_CNT - 1))
+ return(ENOBUFS);
+ }
+ if ((DC_TX_LIST_CNT -
+ (sc->dc_cdata.dc_tx_cnt + cnt)) < 5)
+ return(ENOBUFS);
+
+ f = &sc->dc_ldata->dc_tx_list[frag];
+ f->dc_ctl = DC_TXCTL_TLINK | m->m_len;
+ if (cnt == 0) {
+ f->dc_status = 0;
+ f->dc_ctl |= DC_TXCTL_FIRSTFRAG;
+ } else
+ f->dc_status = DC_TXSTAT_OWN;
+ f->dc_data = vtophys(mtod(m, vm_offset_t));
+ cur = frag;
+ DC_INC(frag, DC_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->dc_cdata.dc_tx_cnt += cnt;
+ sc->dc_cdata.dc_tx_chain[cur] = m_head;
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_LASTFRAG;
+ if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
+ sc->dc_ldata->dc_tx_list[*txidx].dc_ctl |= DC_TXCTL_FINT;
+ if (sc->dc_flags & DC_TX_INTR_ALWAYS)
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+ if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64)
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+ sc->dc_ldata->dc_tx_list[*txidx].dc_status = DC_TXSTAT_OWN;
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Coalesce an mbuf chain into a single mbuf cluster buffer.
+ * Needed for some really badly behaved chips that just can't
+ * do scatter/gather correctly.
+ */
+static int dc_coal(sc, m_head)
+ struct dc_softc *sc;
+ struct mbuf **m_head;
+{
+ struct mbuf *m_new, *m;
+
+ m = *m_head;
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+ if (m->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ }
+ m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
+ m_freem(m);
+ *m_head = m_new;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void dc_start(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mbuf *m_head = NULL;
+ int idx;
+
+ sc = ifp->if_softc;
+
+ DC_LOCK(sc);
+
+ if (!sc->dc_link && ifp->if_snd.ifq_len < 10) {
+ DC_UNLOCK(sc);
+ return;
+ }
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ DC_UNLOCK(sc);
+ return;
+ }
+
+ idx = sc->dc_cdata.dc_tx_prod;
+
+ while(sc->dc_cdata.dc_tx_chain[idx] == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (sc->dc_flags & DC_TX_COALESCE &&
+ (m_head->m_next != NULL ||
+ sc->dc_flags & DC_TX_ALIGN)) {
+ if (dc_coal(sc, &m_head)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ }
+
+ if (dc_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+
+ if (sc->dc_flags & DC_TX_ONE) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ }
+
+ /* Transmit */
+ sc->dc_cdata.dc_tx_prod = idx;
+ if (!(sc->dc_flags & DC_TX_POLL))
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ DC_UNLOCK(sc);
+
+ return;
+}
+
+static void dc_init(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+
+ DC_LOCK(sc);
+
+ mii = device_get_softc(sc->dc_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ dc_stop(sc);
+ dc_reset(sc);
+
+ /*
+ * Set cache alignment and burst length.
+ */
+ if (DC_IS_ASIX(sc) || DC_IS_DAVICOM(sc))
+ CSR_WRITE_4(sc, DC_BUSCTL, 0);
+ else
+ CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME|DC_BUSCTL_MRLE);
+ /*
+ * Evenly share the bus between receive and transmit process.
+ */
+ if (DC_IS_INTEL(sc))
+ DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_ARBITRATION);
+ if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA);
+ } else {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_16LONG);
+ }
+ if (sc->dc_flags & DC_TX_POLL)
+ DC_SETBIT(sc, DC_BUSCTL, DC_TXPOLL_1);
+ switch(sc->dc_cachesize) {
+ case 32:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_32LONG);
+ break;
+ case 16:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_16LONG);
+ break;
+ case 8:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_8LONG);
+ break;
+ case 0:
+ default:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_NONE);
+ break;
+ }
+
+ if (sc->dc_flags & DC_TX_STORENFWD)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ else {
+ if (sc->dc_txthresh > DC_TXTHRESH_MAX) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ }
+ }
+
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_NO_RXCRC);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_BACKOFF);
+
+ if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ /*
+ * The app notes for the 98713 and 98715A say that
+ * in order to have the chips operate properly, a magic
+ * number must be written to CSR16. Macronix does not
+ * document the meaning of these bits so there's no way
+ * to know exactly what they do. The 98713 has a magic
+ * number all its own; the rest all use a different one.
+ */
+ DC_CLRBIT(sc, DC_MX_MAGICPACKET, 0xFFFF0000);
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98713);
+ else
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715);
+ }
+
+ if (DC_IS_XIRCOM(sc)) {
+ /*
+ * setup General Purpose Port mode and data so the tulip
+ * can talk to the MII.
+ */
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ }
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH);
+ DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_MIN);
+
+ /* Init circular RX list. */
+ if (dc_list_rx_init(sc) == ENOBUFS) {
+ printf("dc%d: initialization failed: no "
+ "memory for rx buffers\n", sc->dc_unit);
+ dc_stop(sc);
+ DC_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ dc_list_tx_init(sc);
+
+ /*
+ * Load the address of the RX list.
+ */
+ CSR_WRITE_4(sc, DC_RXADDR, vtophys(&sc->dc_ldata->dc_rx_list[0]));
+ CSR_WRITE_4(sc, DC_TXADDR, vtophys(&sc->dc_ldata->dc_tx_list[0]));
+
+ /*
+ * Enable interrupts.
+ */
+#ifdef DEVICE_POLLING
+ /*
+ * ... but only if we are not polling, and make sure they are off in
+ * the case of polling. Some cards (e.g. fxp) turn interrupts on
+ * after a reset.
+ */
+ if (ifp->if_ipending & IFF_POLLING)
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ else
+#endif
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+ CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF);
+
+ /* Enable transmitter. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+
+ /*
+ * If this is an Intel 21143 and we're not using the
+ * MII port, program the LED control pins so we get
+ * link and activity indications.
+ */
+ if (sc->dc_flags & DC_TULIP_LEDS) {
+ CSR_WRITE_4(sc, DC_WATCHDOG,
+ DC_WDOG_CTLWREN|DC_WDOG_LINK|DC_WDOG_ACTIVITY);
+ CSR_WRITE_4(sc, DC_WATCHDOG, 0);
+ }
+
+ /*
+ * Load the RX/multicast filter. We do this sort of late
+ * because the filter programming scheme on the 21143 and
+ * some clones requires DMAing a setup frame via the TX
+ * engine, and we need the transmitter enabled for that.
+ */
+ dc_setfilt(sc);
+
+ /* Enable receiver. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF);
+
+ mii_mediachg(mii);
+ dc_setcfg(sc, sc->dc_if_media);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* Don't start the ticker if this is a homePNA link. */
+ if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_HPNA_1)
+ sc->dc_link = 1;
+ else {
+ if (sc->dc_flags & DC_21143_NWAY)
+ callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc);
+ else
+ callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc);
+ }
+
+#ifdef SRM_MEDIA
+ if(sc->dc_srm_media) {
+ struct ifreq ifr;
+
+ ifr.ifr_media = sc->dc_srm_media;
+ ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA);
+ sc->dc_srm_media = 0;
+ }
+#endif
+ DC_UNLOCK(sc);
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int dc_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifmedia *ifm;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_mediachg(mii);
+ ifm = &mii->mii_media;
+
+ if (DC_IS_DAVICOM(sc) &&
+ IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1)
+ dc_setcfg(sc, ifm->ifm_media);
+ else
+ sc->dc_link = 0;
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void dc_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifmedia *ifm;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_pollstat(mii);
+ ifm = &mii->mii_media;
+ if (DC_IS_DAVICOM(sc)) {
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) {
+ ifmr->ifm_active = ifm->ifm_media;
+ ifmr->ifm_status = 0;
+ return;
+ }
+ }
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int dc_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct dc_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ DC_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->dc_if_flags & IFF_PROMISC)) {
+ dc_setfilt(sc);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->dc_if_flags & IFF_PROMISC) {
+ dc_setfilt(sc);
+ } else if (!(ifp->if_flags & IFF_RUNNING)) {
+ sc->dc_txthresh = 0;
+ dc_init(sc);
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ dc_stop(sc);
+ }
+ sc->dc_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ dc_setfilt(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->dc_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+#ifdef SRM_MEDIA
+ if (sc->dc_srm_media)
+ sc->dc_srm_media = 0;
+#endif
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ DC_UNLOCK(sc);
+
+ return(error);
+}
+
+static void dc_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+
+ sc = ifp->if_softc;
+
+ DC_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("dc%d: watchdog timeout\n", sc->dc_unit);
+
+ dc_stop(sc);
+ dc_reset(sc);
+ dc_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+ DC_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void dc_stop(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ DC_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ callout_stop(&sc->dc_stat_ch);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif
+
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON|DC_NETCFG_TX_ON));
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_TXADDR, 0x00000000);
+ CSR_WRITE_4(sc, DC_RXADDR, 0x00000000);
+ sc->dc_link = 0;
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_rx_chain[i] != NULL) {
+ m_freem(sc->dc_cdata.dc_rx_chain[i]);
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+ }
+ }
+ bzero((char *)&sc->dc_ldata->dc_rx_list,
+ sizeof(sc->dc_ldata->dc_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_tx_chain[i] != NULL) {
+ if (sc->dc_ldata->dc_tx_list[i].dc_ctl &
+ DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ continue;
+ }
+ m_freem(sc->dc_cdata.dc_tx_chain[i]);
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ }
+ }
+
+ bzero((char *)&sc->dc_ldata->dc_tx_list,
+ sizeof(sc->dc_ldata->dc_tx_list));
+
+ DC_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Device suspend routine. Stop the interface and save some PCI
+ * settings in case the BIOS doesn't restore them properly on
+ * resume.
+ */
+static int dc_suspend(dev)
+ device_t dev;
+{
+ register int i;
+ int s;
+ struct dc_softc *sc;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+
+ dc_stop(sc);
+
+ for (i = 0; i < 5; i++)
+ sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4);
+ sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
+ sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
+ sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
+
+ sc->suspended = 1;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Device resume routine. Restore some PCI settings in case the BIOS
+ * doesn't, re-enable busmastering, and restart the interface if
+ * appropriate.
+ */
+static int dc_resume(dev)
+ device_t dev;
+{
+ register int i;
+ int s;
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ dc_acpi(dev);
+
+ /* better way to do this? */
+ for (i = 0; i < 5; i++)
+ pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4);
+ pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
+ pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
+ pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
+ pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
+
+ /* reenable busmastering */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, DC_RES);
+
+ /* reinitialize interface if necessary */
+ if (ifp->if_flags & IFF_UP)
+ dc_init(sc);
+
+ sc->suspended = 0;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void dc_shutdown(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ dc_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_dcreg.h b/sys/pci/if_dcreg.h
new file mode 100644
index 0000000..5c0879a
--- /dev/null
+++ b/sys/pci/if_dcreg.h
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * 21143 and clone common register definitions.
+ */
+
+#define DC_BUSCTL 0x00 /* bus control */
+#define DC_TXSTART 0x08 /* tx start demand */
+#define DC_RXSTART 0x10 /* rx start demand */
+#define DC_RXADDR 0x18 /* rx descriptor list start addr */
+#define DC_TXADDR 0x20 /* tx descriptor list start addr */
+#define DC_ISR 0x28 /* interrupt status register */
+#define DC_NETCFG 0x30 /* network config register */
+#define DC_IMR 0x38 /* interrupt mask */
+#define DC_FRAMESDISCARDED 0x40 /* # of discarded frames */
+#define DC_SIO 0x48 /* MII and ROM/EEPROM access */
+#define DC_ROM 0x50 /* ROM programming address */
+#define DC_TIMER 0x58 /* general timer */
+#define DC_10BTSTAT 0x60 /* SIA status */
+#define DC_SIARESET 0x68 /* SIA connectivity */
+#define DC_10BTCTRL 0x70 /* SIA transmit and receive */
+#define DC_WATCHDOG 0x78 /* SIA and general purpose port */
+#define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */
+
+/*
+ * There are two general 'types' of MX chips that we need to be
+ * concerned with. One is the original 98713, which has its internal
+ * NWAY support controlled via the MDIO bits in the serial I/O
+ * register. The other is everything else (from the 98713A on up),
+ * which has its internal NWAY controlled via CSR13, CSR14 and CSR15,
+ * just like the 21143. This type setting also governs which of the
+ * 'magic' numbers we write to CSR16. The PNIC II falls into the
+ * 98713A/98715/98715A/98725 category.
+ */
+#define DC_TYPE_98713 0x1
+#define DC_TYPE_98713A 0x2
+#define DC_TYPE_987x5 0x3
+
+/* Other type of supported chips. */
+#define DC_TYPE_21143 0x4 /* Intel 21143 */
+#define DC_TYPE_ASIX 0x5 /* ASIX AX88140A/AX88141 */
+#define DC_TYPE_AL981 0x6 /* ADMtek AL981 Comet */
+#define DC_TYPE_AN985 0x7 /* ADMtek AN985 Centaur */
+#define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */
+#define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */
+#define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */
+#define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */
+#define DC_TYPE_CONEXANT 0xC /* Conexant LANfinity RS7112 */
+
+#define DC_IS_MACRONIX(x) \
+ (x->dc_type == DC_TYPE_98713 || \
+ x->dc_type == DC_TYPE_98713A || \
+ x->dc_type == DC_TYPE_987x5)
+
+#define DC_IS_ADMTEK(x) \
+ (x->dc_type == DC_TYPE_AL981 || \
+ x->dc_type == DC_TYPE_AN985)
+
+#define DC_IS_INTEL(x) (x->dc_type == DC_TYPE_21143)
+#define DC_IS_ASIX(x) (x->dc_type == DC_TYPE_ASIX)
+#define DC_IS_COMET(x) (x->dc_type == DC_TYPE_AL981)
+#define DC_IS_CENTAUR(x) (x->dc_type == DC_TYPE_AN985)
+#define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102)
+#define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII)
+#define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC)
+#define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM)
+#define DC_IS_CONEXANT(x) (x->dc_type == DC_TYPE_CONEXANT)
+
+/* MII/symbol mode port types */
+#define DC_PMODE_MII 0x1
+#define DC_PMODE_SYM 0x2
+#define DC_PMODE_SIA 0x3
+
+/*
+ * Bus control bits.
+ */
+#define DC_BUSCTL_RESET 0x00000001
+#define DC_BUSCTL_ARBITRATION 0x00000002
+#define DC_BUSCTL_SKIPLEN 0x0000007C
+#define DC_BUSCTL_BUF_BIGENDIAN 0x00000080
+#define DC_BUSCTL_BURSTLEN 0x00003F00
+#define DC_BUSCTL_CACHEALIGN 0x0000C000
+#define DC_BUSCTL_TXPOLL 0x000E0000
+#define DC_BUSCTL_DBO 0x00100000
+#define DC_BUSCTL_MRME 0x00200000
+#define DC_BUSCTL_MRLE 0x00800000
+#define DC_BUSCTL_MWIE 0x01000000
+#define DC_BUSCTL_ONNOW_ENB 0x04000000
+
+#define DC_SKIPLEN_1LONG 0x00000004
+#define DC_SKIPLEN_2LONG 0x00000008
+#define DC_SKIPLEN_3LONG 0x00000010
+#define DC_SKIPLEN_4LONG 0x00000020
+#define DC_SKIPLEN_5LONG 0x00000040
+
+#define DC_CACHEALIGN_NONE 0x00000000
+#define DC_CACHEALIGN_8LONG 0x00004000
+#define DC_CACHEALIGN_16LONG 0x00008000
+#define DC_CACHEALIGN_32LONG 0x0000C000
+
+#define DC_BURSTLEN_USECA 0x00000000
+#define DC_BURSTLEN_1LONG 0x00000100
+#define DC_BURSTLEN_2LONG 0x00000200
+#define DC_BURSTLEN_4LONG 0x00000400
+#define DC_BURSTLEN_8LONG 0x00000800
+#define DC_BURSTLEN_16LONG 0x00001000
+#define DC_BURSTLEN_32LONG 0x00002000
+
+#define DC_TXPOLL_OFF 0x00000000
+#define DC_TXPOLL_1 0x00020000
+#define DC_TXPOLL_2 0x00040000
+#define DC_TXPOLL_3 0x00060000
+#define DC_TXPOLL_4 0x00080000
+#define DC_TXPOLL_5 0x000A0000
+#define DC_TXPOLL_6 0x000C0000
+#define DC_TXPOLL_7 0x000E0000
+
+/*
+ * Interrupt status bits.
+ */
+#define DC_ISR_TX_OK 0x00000001
+#define DC_ISR_TX_IDLE 0x00000002
+#define DC_ISR_TX_NOBUF 0x00000004
+#define DC_ISR_TX_JABBERTIMEO 0x00000008
+#define DC_ISR_LINKGOOD 0x00000010
+#define DC_ISR_TX_UNDERRUN 0x00000020
+#define DC_ISR_RX_OK 0x00000040
+#define DC_ISR_RX_NOBUF 0x00000080
+#define DC_ISR_RX_READ 0x00000100
+#define DC_ISR_RX_WATDOGTIMEO 0x00000200
+#define DC_ISR_TX_EARLY 0x00000400
+#define DC_ISR_TIMER_EXPIRED 0x00000800
+#define DC_ISR_LINKFAIL 0x00001000
+#define DC_ISR_BUS_ERR 0x00002000
+#define DC_ISR_RX_EARLY 0x00004000
+#define DC_ISR_ABNORMAL 0x00008000
+#define DC_ISR_NORMAL 0x00010000
+#define DC_ISR_RX_STATE 0x000E0000
+#define DC_ISR_TX_STATE 0x00700000
+#define DC_ISR_BUSERRTYPE 0x03800000
+#define DC_ISR_100MBPSLINK 0x08000000
+#define DC_ISR_MAGICKPACK 0x10000000
+
+#define DC_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
+#define DC_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
+#define DC_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
+#define DC_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
+#define DC_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
+#define DC_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
+#define DC_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
+#define DC_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
+
+#define DC_TXSTATE_RESET 0x00000000 /* 000 - reset */
+#define DC_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
+#define DC_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
+#define DC_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
+#define DC_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
+#define DC_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
+#define DC_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
+#define DC_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
+
+/*
+ * Network config bits.
+ */
+#define DC_NETCFG_RX_HASHPERF 0x00000001
+#define DC_NETCFG_RX_ON 0x00000002
+#define DC_NETCFG_RX_HASHONLY 0x00000004
+#define DC_NETCFG_RX_BADFRAMES 0x00000008
+#define DC_NETCFG_RX_INVFILT 0x00000010
+#define DC_NETCFG_BACKOFFCNT 0x00000020
+#define DC_NETCFG_RX_PROMISC 0x00000040
+#define DC_NETCFG_RX_ALLMULTI 0x00000080
+#define DC_NETCFG_FULLDUPLEX 0x00000200
+#define DC_NETCFG_LOOPBACK 0x00000C00
+#define DC_NETCFG_FORCECOLL 0x00001000
+#define DC_NETCFG_TX_ON 0x00002000
+#define DC_NETCFG_TX_THRESH 0x0000C000
+#define DC_NETCFG_TX_BACKOFF 0x00020000
+#define DC_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */
+#define DC_NETCFG_HEARTBEAT 0x00080000
+#define DC_NETCFG_STORENFWD 0x00200000
+#define DC_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
+#define DC_NETCFG_PCS 0x00800000
+#define DC_NETCFG_SCRAMBLER 0x01000000
+#define DC_NETCFG_NO_RXCRC 0x02000000
+#define DC_NETCFG_RX_ALL 0x40000000
+#define DC_NETCFG_CAPEFFECT 0x80000000
+
+#define DC_OPMODE_NORM 0x00000000
+#define DC_OPMODE_INTLOOP 0x00000400
+#define DC_OPMODE_EXTLOOP 0x00000800
+
+#if 0
+#define DC_TXTHRESH_72BYTES 0x00000000
+#define DC_TXTHRESH_96BYTES 0x00004000
+#define DC_TXTHRESH_128BYTES 0x00008000
+#define DC_TXTHRESH_160BYTES 0x0000C000
+#endif
+
+#define DC_TXTHRESH_MIN 0x00000000
+#define DC_TXTHRESH_INC 0x00004000
+#define DC_TXTHRESH_MAX 0x0000C000
+
+
+/*
+ * Interrupt mask bits.
+ */
+#define DC_IMR_TX_OK 0x00000001
+#define DC_IMR_TX_IDLE 0x00000002
+#define DC_IMR_TX_NOBUF 0x00000004
+#define DC_IMR_TX_JABBERTIMEO 0x00000008
+#define DC_IMR_LINKGOOD 0x00000010
+#define DC_IMR_TX_UNDERRUN 0x00000020
+#define DC_IMR_RX_OK 0x00000040
+#define DC_IMR_RX_NOBUF 0x00000080
+#define DC_IMR_RX_READ 0x00000100
+#define DC_IMR_RX_WATDOGTIMEO 0x00000200
+#define DC_IMR_TX_EARLY 0x00000400
+#define DC_IMR_TIMER_EXPIRED 0x00000800
+#define DC_IMR_LINKFAIL 0x00001000
+#define DC_IMR_BUS_ERR 0x00002000
+#define DC_IMR_RX_EARLY 0x00004000
+#define DC_IMR_ABNORMAL 0x00008000
+#define DC_IMR_NORMAL 0x00010000
+#define DC_IMR_100MBPSLINK 0x08000000
+#define DC_IMR_MAGICKPACK 0x10000000
+
+#define DC_INTRS \
+ (DC_IMR_RX_OK|DC_IMR_TX_OK|DC_IMR_RX_NOBUF|DC_IMR_RX_WATDOGTIMEO|\
+ DC_IMR_TX_NOBUF|DC_IMR_TX_UNDERRUN|DC_IMR_BUS_ERR| \
+ DC_IMR_ABNORMAL|DC_IMR_NORMAL/*|DC_IMR_TX_EARLY*/)
+/*
+ * Serial I/O (EEPROM/ROM) bits.
+ */
+#define DC_SIO_EE_CS 0x00000001 /* EEPROM chip select */
+#define DC_SIO_EE_CLK 0x00000002 /* EEPROM clock */
+#define DC_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
+#define DC_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
+#define DC_SIO_ROMDATA4 0x00000010
+#define DC_SIO_ROMDATA5 0x00000020
+#define DC_SIO_ROMDATA6 0x00000040
+#define DC_SIO_ROMDATA7 0x00000080
+#define DC_SIO_EESEL 0x00000800
+#define DC_SIO_ROMSEL 0x00001000
+#define DC_SIO_ROMCTL_WRITE 0x00002000
+#define DC_SIO_ROMCTL_READ 0x00004000
+#define DC_SIO_MII_CLK 0x00010000 /* MDIO clock */
+#define DC_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
+#define DC_SIO_MII_DIR 0x00040000 /* MDIO dir */
+#define DC_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
+
+#define DC_EECMD_WRITE 0x140
+#define DC_EECMD_READ 0x180
+#define DC_EECMD_ERASE 0x1c0
+
+#define DC_EE_NODEADDR_OFFSET 0x70
+#define DC_EE_NODEADDR 10
+
+/*
+ * General purpose timer register
+ */
+#define DC_TIMER_VALUE 0x0000FFFF
+#define DC_TIMER_CONTINUOUS 0x00010000
+
+/*
+ * 10baseT status register
+ */
+#define DC_TSTAT_MIIACT 0x00000001 /* MII port activity */
+#define DC_TSTAT_LS100 0x00000002 /* link status of 100baseTX */
+#define DC_TSTAT_LS10 0x00000004 /* link status of 10baseT */
+#define DC_TSTAT_AUTOPOLARITY 0x00000008
+#define DC_TSTAT_AUIACT 0x00000100 /* AUI activity */
+#define DC_TSTAT_10BTACT 0x00000200 /* 10baseT activity */
+#define DC_TSTAT_NSN 0x00000400 /* non-stable FLPs detected */
+#define DC_TSTAT_REMFAULT 0x00000800
+#define DC_TSTAT_ANEGSTAT 0x00007000
+#define DC_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */
+#define DC_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */
+
+#define DC_ASTAT_DISABLE 0x00000000
+#define DC_ASTAT_TXDISABLE 0x00001000
+#define DC_ASTAT_ABDETECT 0x00002000
+#define DC_ASTAT_ACKDETECT 0x00003000
+#define DC_ASTAT_CMPACKDETECT 0x00004000
+#define DC_ASTAT_AUTONEGCMP 0x00005000
+#define DC_ASTAT_LINKCHECK 0x00006000
+
+/*
+ * PHY reset register
+ */
+#define DC_SIA_RESET 0x00000001
+#define DC_SIA_AUI 0x00000008 /* AUI or 10baseT */
+
+/*
+ * 10baseT control register
+ */
+#define DC_TCTL_ENCODER_ENB 0x00000001
+#define DC_TCTL_LOOPBACK 0x00000002
+#define DC_TCTL_DRIVER_ENB 0x00000004
+#define DC_TCTL_LNKPULSE_ENB 0x00000008
+#define DC_TCTL_HALFDUPLEX 0x00000040
+#define DC_TCTL_AUTONEGENBL 0x00000080
+#define DC_TCTL_RX_SQUELCH 0x00000100
+#define DC_TCTL_COLL_SQUELCH 0x00000200
+#define DC_TCTL_COLL_DETECT 0x00000400
+#define DC_TCTL_SQE_ENB 0x00000800
+#define DC_TCTL_LINKTEST 0x00001000
+#define DC_TCTL_AUTOPOLARITY 0x00002000
+#define DC_TCTL_SET_POL_PLUS 0x00004000
+#define DC_TCTL_AUTOSENSE 0x00008000 /* 10bt/AUI autosense */
+#define DC_TCTL_100BTXHALF 0x00010000
+#define DC_TCTL_100BTXFULL 0x00020000
+#define DC_TCTL_100BT4 0x00040000
+
+/*
+ * Watchdog timer register
+ */
+#define DC_WDOG_JABBERDIS 0x00000001
+#define DC_WDOG_HOSTUNJAB 0x00000002
+#define DC_WDOG_JABBERCLK 0x00000004
+#define DC_WDOG_RXWDOGDIS 0x00000010
+#define DC_WDOG_RXWDOGCLK 0x00000020
+#define DC_WDOG_MUSTBEZERO 0x00000100
+#define DC_WDOG_AUIBNC 0x00100000
+#define DC_WDOG_ACTIVITY 0x00200000
+#define DC_WDOG_RX_MATCH 0x00400000
+#define DC_WDOG_LINK 0x00800000
+#define DC_WDOG_CTLWREN 0x08000000
+
+/*
+ * SIA and General Purpose Port register (X3201)
+ */
+#define DC_SIAGP_RXMATCH 0x40000000
+#define DC_SIAGP_INT1 0x20000000
+#define DC_SIAGP_INT0 0x10000000
+#define DC_SIAGP_WRITE_EN 0x08000000
+#define DC_SIAGP_RXMATCH_EN 0x04000000
+#define DC_SIAGP_INT1_EN 0x02000000
+#define DC_SIAGP_INT0_EN 0x01000000
+#define DC_SIAGP_LED3 0x00800000
+#define DC_SIAGP_LED2 0x00400000
+#define DC_SIAGP_LED1 0x00200000
+#define DC_SIAGP_LED0 0x00100000
+#define DC_SIAGP_MD_GP3_OUTPUT 0x00080000
+#define DC_SIAGP_MD_GP2_OUTPUT 0x00040000
+#define DC_SIAGP_MD_GP1_OUTPUT 0x00020000
+#define DC_SIAGP_MD_GP0_OUTPUT 0x00010000
+
+/*
+ * Size of a setup frame.
+ */
+#define DC_SFRAME_LEN 192
+
+/*
+ * 21x4x TX/RX list structure.
+ */
+
+struct dc_desc {
+ u_int32_t dc_status;
+ u_int32_t dc_ctl;
+ u_int32_t dc_ptr1;
+ u_int32_t dc_ptr2;
+};
+
+#define dc_data dc_ptr1
+#define dc_next dc_ptr2
+
+#define DC_RXSTAT_FIFOOFLOW 0x00000001
+#define DC_RXSTAT_CRCERR 0x00000002
+#define DC_RXSTAT_DRIBBLE 0x00000004
+#define DC_RXSTAT_MIIERE 0x00000008
+#define DC_RXSTAT_WATCHDOG 0x00000010
+#define DC_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
+#define DC_RXSTAT_COLLSEEN 0x00000040
+#define DC_RXSTAT_GIANT 0x00000080
+#define DC_RXSTAT_LASTFRAG 0x00000100
+#define DC_RXSTAT_FIRSTFRAG 0x00000200
+#define DC_RXSTAT_MULTICAST 0x00000400
+#define DC_RXSTAT_RUNT 0x00000800
+#define DC_RXSTAT_RXTYPE 0x00003000
+#define DC_RXSTAT_DE 0x00004000
+#define DC_RXSTAT_RXERR 0x00008000
+#define DC_RXSTAT_RXLEN 0x3FFF0000
+#define DC_RXSTAT_OWN 0x80000000
+
+#define DC_RXBYTES(x) ((x & DC_RXSTAT_RXLEN) >> 16)
+#define DC_RXSTAT (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG|DC_RXSTAT_OWN)
+
+#define DC_RXCTL_BUFLEN1 0x00000FFF
+#define DC_RXCTL_BUFLEN2 0x00FFF000
+#define DC_RXCTL_RLINK 0x01000000
+#define DC_RXCTL_RLAST 0x02000000
+
+#define DC_TXSTAT_DEFER 0x00000001
+#define DC_TXSTAT_UNDERRUN 0x00000002
+#define DC_TXSTAT_LINKFAIL 0x00000003
+#define DC_TXSTAT_COLLCNT 0x00000078
+#define DC_TXSTAT_SQE 0x00000080
+#define DC_TXSTAT_EXCESSCOLL 0x00000100
+#define DC_TXSTAT_LATECOLL 0x00000200
+#define DC_TXSTAT_NOCARRIER 0x00000400
+#define DC_TXSTAT_CARRLOST 0x00000800
+#define DC_TXSTAT_JABTIMEO 0x00004000
+#define DC_TXSTAT_ERRSUM 0x00008000
+#define DC_TXSTAT_OWN 0x80000000
+
+#define DC_TXCTL_BUFLEN1 0x000007FF
+#define DC_TXCTL_BUFLEN2 0x003FF800
+#define DC_TXCTL_FILTTYPE0 0x00400000
+#define DC_TXCTL_PAD 0x00800000
+#define DC_TXCTL_TLINK 0x01000000
+#define DC_TXCTL_TLAST 0x02000000
+#define DC_TXCTL_NOCRC 0x04000000
+#define DC_TXCTL_SETUP 0x08000000
+#define DC_TXCTL_FILTTYPE1 0x10000000
+#define DC_TXCTL_FIRSTFRAG 0x20000000
+#define DC_TXCTL_LASTFRAG 0x40000000
+#define DC_TXCTL_FINT 0x80000000
+
+#define DC_FILTER_PERFECT 0x00000000
+#define DC_FILTER_HASHPERF 0x00400000
+#define DC_FILTER_INVERSE 0x10000000
+#define DC_FILTER_HASHONLY 0x10400000
+
+#define DC_MAXFRAGS 16
+#ifdef DEVICE_POLLING
+#define DC_RX_LIST_CNT 192
+#else
+#define DC_RX_LIST_CNT 64
+#endif
+#define DC_TX_LIST_CNT 256
+#define DC_MIN_FRAMELEN 60
+#define DC_RXLEN 1536
+
+#define DC_INC(x, y) (x) = (x + 1) % y
+
+struct dc_list_data {
+ struct dc_desc dc_rx_list[DC_RX_LIST_CNT];
+ struct dc_desc dc_tx_list[DC_TX_LIST_CNT];
+};
+
+struct dc_chain_data {
+ struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
+ struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
+ u_int32_t dc_sbuf[DC_SFRAME_LEN/sizeof(u_int32_t)];
+ u_int8_t dc_pad[DC_MIN_FRAMELEN];
+ int dc_tx_prod;
+ int dc_tx_cons;
+ int dc_tx_cnt;
+ int dc_rx_prod;
+};
+
+struct dc_mediainfo {
+ int dc_media;
+ u_int8_t *dc_gp_ptr;
+ u_int8_t dc_gp_len;
+ u_int8_t *dc_reset_ptr;
+ u_int8_t dc_reset_len;
+ struct dc_mediainfo *dc_next;
+};
+
+
+struct dc_type {
+ u_int16_t dc_vid;
+ u_int16_t dc_did;
+ char *dc_name;
+};
+
+struct dc_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define DC_MII_STARTDELIM 0x01
+#define DC_MII_READOP 0x02
+#define DC_MII_WRITEOP 0x01
+#define DC_MII_TURNAROUND 0x02
+
+
+/*
+ * Registers specific to clone devices.
+ * This mainly relates to RX filter programming: not all 21x4x clones
+ * use the standard DEC filter programming mechanism.
+ */
+
+/*
+ * ADMtek specific registers and constants for the AL981 and AN985.
+ * The AN985 doesn't use the magic PHY registers.
+ */
+#define DC_AL_PAR0 0xA4 /* station address */
+#define DC_AL_PAR1 0xA8 /* station address */
+#define DC_AL_MAR0 0xAC /* multicast hash filter */
+#define DC_AL_MAR1 0xB0 /* multicast hash filter */
+#define DC_AL_BMCR 0xB4 /* built in PHY control */
+#define DC_AL_BMSR 0xB8 /* built in PHY status */
+#define DC_AL_VENID 0xBC /* built in PHY ID0 */
+#define DC_AL_DEVID 0xC0 /* built in PHY ID1 */
+#define DC_AL_ANAR 0xC4 /* built in PHY autoneg advert */
+#define DC_AL_LPAR 0xC8 /* bnilt in PHY link part. ability */
+#define DC_AL_ANER 0xCC /* built in PHY autoneg expansion */
+
+#define DC_ADMTEK_PHYADDR 0x1
+#define DC_AL_EE_NODEADDR 4
+/* End of ADMtek specific registers */
+
+/*
+ * ASIX specific registers.
+ */
+#define DC_AX_FILTIDX 0x68 /* RX filter index */
+#define DC_AX_FILTDATA 0x70 /* RX filter data */
+
+/*
+ * Special ASIX-specific bits in the ASIX NETCFG register (CSR6).
+ */
+#define DC_AX_NETCFG_RX_BROAD 0x00000100
+
+/*
+ * RX Filter Index Register values
+ */
+#define DC_AX_FILTIDX_PAR0 0x00000000
+#define DC_AX_FILTIDX_PAR1 0x00000001
+#define DC_AX_FILTIDX_MAR0 0x00000002
+#define DC_AX_FILTIDX_MAR1 0x00000003
+/* End of ASIX specific registers */
+
+/*
+ * Macronix specific registers. The Macronix chips have a special
+ * register for reading the NWAY status, which we don't use, plus
+ * a magic packet register, which we need to tweak a bit per the
+ * Macronix application notes.
+ */
+#define DC_MX_MAGICPACKET 0x80
+#define DC_MX_NWAYSTAT 0xA0
+
+/*
+ * Magic packet register
+ */
+#define DC_MX_MPACK_DISABLE 0x00400000
+
+/*
+ * NWAY status register.
+ */
+#define DC_MX_NWAY_10BTHALF 0x08000000
+#define DC_MX_NWAY_10BTFULL 0x10000000
+#define DC_MX_NWAY_100BTHALF 0x20000000
+#define DC_MX_NWAY_100BTFULL 0x40000000
+#define DC_MX_NWAY_100BT4 0x80000000
+
+/*
+ * These are magic values that must be written into CSR16
+ * (DC_MX_MAGICPACKET) in order to put the chip into proper
+ * operating mode. The magic numbers are documented in the
+ * Macronix 98715 application notes.
+ */
+#define DC_MX_MAGIC_98713 0x0F370000
+#define DC_MX_MAGIC_98713A 0x0B3C0000
+#define DC_MX_MAGIC_98715 0x0B3C0000
+#define DC_MX_MAGIC_98725 0x0B3C0000
+/* End of Macronix specific registers */
+
+/*
+ * PNIC 82c168/82c169 specific registers.
+ * The PNIC has its own special NWAY support, which doesn't work,
+ * and shortcut ways of reading the EEPROM and MII bus.
+ */
+#define DC_PN_GPIO 0x60 /* general purpose pins control */
+#define DC_PN_PWRUP_CFG 0x90 /* config register, set by EEPROM */
+#define DC_PN_SIOCTL 0x98 /* serial EEPROM control register */
+#define DC_PN_MII 0xA0 /* MII access register */
+#define DC_PN_NWAY 0xB8 /* Internal NWAY register */
+
+/* Serial I/O EEPROM register */
+#define DC_PN_SIOCTL_DATA 0x0000003F
+#define DC_PN_SIOCTL_OPCODE 0x00000300
+#define DC_PN_SIOCTL_BUSY 0x80000000
+
+#define DC_PN_EEOPCODE_ERASE 0x00000300
+#define DC_PN_EEOPCODE_READ 0x00000600
+#define DC_PN_EEOPCODE_WRITE 0x00000100
+
+/*
+ * The first two general purpose pins control speed selection and
+ * 100Mbps loopback on the 82c168 chip. The control bits should always
+ * be set (to make the data pins outputs) and the speed selction and
+ * loopback bits set accordingly when changing media. Physically, this
+ * will set the state of a relay mounted on the card.
+ */
+#define DC_PN_GPIO_DATA0 0x000000001
+#define DC_PN_GPIO_DATA1 0x000000002
+#define DC_PN_GPIO_DATA2 0x000000004
+#define DC_PN_GPIO_DATA3 0x000000008
+#define DC_PN_GPIO_CTL0 0x000000010
+#define DC_PN_GPIO_CTL1 0x000000020
+#define DC_PN_GPIO_CTL2 0x000000040
+#define DC_PN_GPIO_CTL3 0x000000080
+#define DC_PN_GPIO_SPEEDSEL DC_PN_GPIO_DATA0/* 1 == 100Mbps, 0 == 10Mbps */
+#define DC_PN_GPIO_100TX_LOOP DC_PN_GPIO_DATA1/* 1 == normal, 0 == loop */
+#define DC_PN_GPIO_BNC_ENB DC_PN_GPIO_DATA2
+#define DC_PN_GPIO_100TX_LNK DC_PN_GPIO_DATA3
+#define DC_PN_GPIO_SETBIT(sc, r) \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) | (r << 4)))
+#define DC_PN_GPIO_CLRBIT(sc, r) \
+ { \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) << 4)); \
+ DC_CLRBIT(sc, DC_PN_GPIO, (r)); \
+ }
+
+/* shortcut MII access register */
+#define DC_PN_MII_DATA 0x0000FFFF
+#define DC_PN_MII_RESERVER 0x00020000
+#define DC_PN_MII_REGADDR 0x007C0000
+#define DC_PN_MII_PHYADDR 0x0F800000
+#define DC_PN_MII_OPCODE 0x30000000
+#define DC_PN_MII_BUSY 0x80000000
+
+#define DC_PN_MIIOPCODE_READ 0x60020000
+#define DC_PN_MIIOPCODE_WRITE 0x50020000
+
+/* Internal NWAY bits */
+#define DC_PN_NWAY_RESET 0x00000001 /* reset */
+#define DC_PN_NWAY_PDOWN 0x00000002 /* power down */
+#define DC_PN_NWAY_BYPASS 0x00000004 /* bypass */
+#define DC_PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */
+#define DC_PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */
+#define DC_PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */
+#define DC_PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */
+#define DC_PN_NWAY_DUPLEX 0x00000100 /* LED, 1 == full, 0 == half */
+#define DC_PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */
+#define DC_PN_NWAY_SPEEDSEL 0x00000800 /* LED, 0 = 10, 1 == 100 */
+#define DC_PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */
+#define DC_PN_NWAY_CAP10HDX 0x00002000
+#define DC_PN_NWAY_CAP10FDX 0x00004000
+#define DC_PN_NWAY_CAP100FDX 0x00008000
+#define DC_PN_NWAY_CAP100HDX 0x00010000
+#define DC_PN_NWAY_CAP100T4 0x00020000
+#define DC_PN_NWAY_ANEGRESTART 0x02000000 /* resets when aneg done */
+#define DC_PN_NWAY_REMFAULT 0x04000000
+#define DC_PN_NWAY_LPAR10HDX 0x08000000
+#define DC_PN_NWAY_LPAR10FDX 0x10000000
+#define DC_PN_NWAY_LPAR100FDX 0x20000000
+#define DC_PN_NWAY_LPAR100HDX 0x40000000
+#define DC_PN_NWAY_LPAR100T4 0x80000000
+
+/* End of PNIC specific registers */
+
+/*
+ * CONEXANT specific registers.
+ */
+
+#define DC_CONEXANT_PHYADDR 0x1
+#define DC_CONEXANT_EE_NODEADDR 0x19A
+
+/* End of CONEXANT specific registers */
+
+
+struct dc_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t dc_bhandle; /* bus space handle */
+ bus_space_tag_t dc_btag; /* bus space tag */
+ void *dc_intrhand;
+ struct resource *dc_irq;
+ struct resource *dc_res;
+ struct dc_type *dc_info; /* adapter info */
+ device_t dc_miibus;
+ u_int8_t dc_unit; /* interface number */
+ u_int8_t dc_type;
+ u_int8_t dc_pmode;
+ u_int8_t dc_link;
+ u_int8_t dc_cachesize;
+ int dc_pnic_rx_bug_save;
+ unsigned char *dc_pnic_rx_buf;
+ int dc_if_flags;
+ int dc_if_media;
+ u_int32_t dc_flags;
+ u_int32_t dc_txthresh;
+ u_int8_t dc_srom[1024];
+ struct dc_mediainfo *dc_mi;
+ struct dc_list_data *dc_ldata;
+ struct dc_chain_data dc_cdata;
+ struct callout dc_stat_ch;
+#ifdef SRM_MEDIA
+ int dc_srm_media;
+#endif
+ struct mtx dc_mtx;
+#ifdef DEVICE_POLLING
+ int rxcycles; /* ... when polling */
+#endif
+ int suspended; /* 0 = normal 1 = suspended */
+
+ u_int32_t saved_maps[5]; /* pci data */
+ u_int32_t saved_biosaddr;
+ u_int8_t saved_intline;
+ u_int8_t saved_cachelnsz;
+ u_int8_t saved_lattimer;
+};
+
+
+#define DC_LOCK(_sc) mtx_lock(&(_sc)->dc_mtx)
+#define DC_UNLOCK(_sc) mtx_unlock(&(_sc)->dc_mtx)
+
+#define DC_TX_POLL 0x00000001
+#define DC_TX_COALESCE 0x00000002
+#define DC_TX_ADMTEK_WAR 0x00000004
+#define DC_TX_USE_TX_INTR 0x00000008
+#define DC_RX_FILTER_TULIP 0x00000010
+#define DC_TX_INTR_FIRSTFRAG 0x00000020
+#define DC_PNIC_RX_BUG_WAR 0x00000040
+#define DC_TX_FIXED_RING 0x00000080
+#define DC_TX_STORENFWD 0x00000100
+#define DC_REDUCED_MII_POLL 0x00000200
+#define DC_TX_INTR_ALWAYS 0x00000400
+#define DC_21143_NWAY 0x00000800
+#define DC_128BIT_HASH 0x00001000
+#define DC_64BIT_HASH 0x00002000
+#define DC_TULIP_LEDS 0x00004000
+#define DC_TX_ONE 0x00008000
+#define DC_TX_ALIGN 0x00010000 /* align mbuf on tx */
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->dc_btag, sc->dc_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg)
+
+#define DC_TIMEOUT 1000
+#define ETHER_ALIGN 2
+
+/*
+ * General constants that are fun to know.
+ */
+
+/*
+ * DEC PCI vendor ID
+ */
+#define DC_VENDORID_DEC 0x1011
+
+/*
+ * DEC/Intel 21143 PCI device ID
+ */
+#define DC_DEVICEID_21143 0x0019
+
+/*
+ * Macronix PCI vendor ID
+ */
+#define DC_VENDORID_MX 0x10D9
+
+/*
+ * Macronix PMAC device IDs.
+ */
+#define DC_DEVICEID_98713 0x0512
+#define DC_DEVICEID_987x5 0x0531
+#define DC_DEVICEID_98727 0x0532
+#define DC_DEVICEID_98732 0x0532
+
+/* Macronix PCI revision codes. */
+#define DC_REVISION_98713 0x00
+#define DC_REVISION_98713A 0x10
+#define DC_REVISION_98715 0x20
+#define DC_REVISION_98715AEC_C 0x25
+#define DC_REVISION_98725 0x30
+
+/*
+ * Compex PCI vendor ID.
+ */
+#define DC_VENDORID_CP 0x11F6
+
+/*
+ * Compex PMAC PCI device IDs.
+ */
+#define DC_DEVICEID_98713_CP 0x9881
+
+/*
+ * Lite-On PNIC PCI vendor ID
+ */
+#define DC_VENDORID_LO 0x11AD
+
+/*
+ * 82c168/82c169 PNIC device IDs. Both chips have the same device
+ * ID but different revisions. Revision 0x10 is the 82c168, and
+ * 0x20 is the 82c169.
+ */
+#define DC_DEVICEID_82C168 0x0002
+
+#define DC_REVISION_82C168 0x10
+#define DC_REVISION_82C169 0x20
+
+/*
+ * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A
+ * with wake on lan/magic packet support.
+ */
+#define DC_DEVICEID_82C115 0xc115
+
+/*
+ * Davicom vendor ID.
+ */
+#define DC_VENDORID_DAVICOM 0x1282
+
+/*
+ * Davicom device IDs.
+ */
+#define DC_DEVICEID_DM9100 0x9100
+#define DC_DEVICEID_DM9102 0x9102
+
+/*
+ * The DM9102A has the same PCI device ID as the DM9102,
+ * but a higher revision code.
+ */
+#define DC_REVISION_DM9102 0x10
+#define DC_REVISION_DM9102A 0x30
+
+/*
+ * ADMtek vendor ID.
+ */
+#define DC_VENDORID_ADMTEK 0x1317
+
+/*
+ * ADMtek device IDs.
+ */
+#define DC_DEVICEID_AL981 0x0981
+#define DC_DEVICEID_AN985 0x0985
+
+/*
+ * ASIX vendor ID.
+ */
+#define DC_VENDORID_ASIX 0x125B
+
+/*
+ * ASIX device IDs.
+ */
+#define DC_DEVICEID_AX88140A 0x1400
+
+/*
+ * The ASIX AX88140 and ASIX AX88141 have the same vendor and
+ * device IDs but different revision values.
+ */
+#define DC_REVISION_88140 0x00
+#define DC_REVISION_88141 0x10
+
+/*
+ * Accton vendor ID.
+ */
+#define DC_VENDORID_ACCTON 0x1113
+
+/*
+ * Accton device IDs.
+ */
+#define DC_DEVICEID_EN1217 0x1217
+#define DC_DEVICEID_EN2242 0x1216
+
+/*
+ * Xircom vendor ID
+ */
+#define DC_VENDORID_XIRCOM 0x115d
+
+/*
+ * Xircom device IDs.
+ */
+#define DC_DEVICEID_X3201 0x0003
+
+/*
+ * Abocom vendor ID
+ */
+#define DC_VENDORID_ABOCOM 0x13d1
+
+/*
+ * Abocom device IDs.
+ */
+#define DC_DEVICEID_FE2500 0xAB02
+
+/*
+ * Conexant vendor ID.
+ */
+#define DC_VENDORID_CONEXANT 0x14f1
+
+/*
+ * Conexant device IDs.
+ */
+#define DC_DEVICEID_RS7112 0x1803
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define DC_PCI_CFID 0x00 /* Id */
+#define DC_PCI_CFCS 0x04 /* Command and status */
+#define DC_PCI_CFRV 0x08 /* Revision */
+#define DC_PCI_CFLT 0x0C /* Latency timer */
+#define DC_PCI_CFBIO 0x10 /* Base I/O address */
+#define DC_PCI_CFBMA 0x14 /* Base memory address */
+#define DC_PCI_CCIS 0x28 /* Card info struct */
+#define DC_PCI_CSID 0x2C /* Subsystem ID */
+#define DC_PCI_CBER 0x30 /* Expansion ROM base address */
+#define DC_PCI_CCAP 0x34 /* Caps pointer - PD/TD chip only */
+#define DC_PCI_CFIT 0x3C /* Interrupt */
+#define DC_PCI_CFDD 0x40 /* Device and driver area */
+#define DC_PCI_CWUA0 0x44 /* Wake-Up LAN addr 0 */
+#define DC_PCI_CWUA1 0x48 /* Wake-Up LAN addr 1 */
+#define DC_PCI_SOP0 0x4C /* SecureON passwd 0 */
+#define DC_PCI_SOP1 0x50 /* SecureON passwd 1 */
+#define DC_PCI_CWUC 0x54 /* Configuration Wake-Up cmd */
+#define DC_PCI_CCID 0xDC /* Capability ID - PD/TD only */
+#define DC_PCI_CPMC 0xE0 /* Pwrmgmt ctl & sts - PD/TD only */
+
+/* PCI ID register */
+#define DC_CFID_VENDOR 0x0000FFFF
+#define DC_CFID_DEVICE 0xFFFF0000
+
+/* PCI command/status register */
+#define DC_CFCS_IOSPACE 0x00000001 /* I/O space enable */
+#define DC_CFCS_MEMSPACE 0x00000002 /* memory space enable */
+#define DC_CFCS_BUSMASTER 0x00000004 /* bus master enable */
+#define DC_CFCS_MWI_ENB 0x00000010 /* mem write and inval enable */
+#define DC_CFCS_PARITYERR_ENB 0x00000040 /* parity error enable */
+#define DC_CFCS_SYSERR_ENB 0x00000100 /* system error enable */
+#define DC_CFCS_NEWCAPS 0x00100000 /* new capabilities */
+#define DC_CFCS_FAST_B2B 0x00800000 /* fast back-to-back capable */
+#define DC_CFCS_DATAPARITY 0x01000000 /* Parity error report */
+#define DC_CFCS_DEVSELTIM 0x06000000 /* devsel timing */
+#define DC_CFCS_TGTABRT 0x10000000 /* received target abort */
+#define DC_CFCS_MASTERABRT 0x20000000 /* received master abort */
+#define DC_CFCS_SYSERR 0x40000000 /* asserted system error */
+#define DC_CFCS_PARITYERR 0x80000000 /* asserted parity error */
+
+/* PCI revision register */
+#define DC_CFRV_STEPPING 0x0000000F
+#define DC_CFRV_REVISION 0x000000F0
+#define DC_CFRV_SUBCLASS 0x00FF0000
+#define DC_CFRV_BASECLASS 0xFF000000
+
+#define DC_21143_PB_REV 0x00000030
+#define DC_21143_TB_REV 0x00000030
+#define DC_21143_PC_REV 0x00000030
+#define DC_21143_TC_REV 0x00000030
+#define DC_21143_PD_REV 0x00000041
+#define DC_21143_TD_REV 0x00000041
+
+/* PCI latency timer register */
+#define DC_CFLT_CACHELINESIZE 0x000000FF
+#define DC_CFLT_LATENCYTIMER 0x0000FF00
+
+/* PCI subsystem ID register */
+#define DC_CSID_VENDOR 0x0000FFFF
+#define DC_CSID_DEVICE 0xFFFF0000
+
+/* PCI cababilities pointer */
+#define DC_CCAP_OFFSET 0x000000FF
+
+/* PCI interrupt config register */
+#define DC_CFIT_INTLINE 0x000000FF
+#define DC_CFIT_INTPIN 0x0000FF00
+#define DC_CFIT_MIN_GNT 0x00FF0000
+#define DC_CFIT_MAX_LAT 0xFF000000
+
+/* PCI capability register */
+#define DC_CCID_CAPID 0x000000FF
+#define DC_CCID_NEXTPTR 0x0000FF00
+#define DC_CCID_PM_VERS 0x00070000
+#define DC_CCID_PME_CLK 0x00080000
+#define DC_CCID_DVSPEC_INT 0x00200000
+#define DC_CCID_STATE_D1 0x02000000
+#define DC_CCID_STATE_D2 0x04000000
+#define DC_CCID_PME_D0 0x08000000
+#define DC_CCID_PME_D1 0x10000000
+#define DC_CCID_PME_D2 0x20000000
+#define DC_CCID_PME_D3HOT 0x40000000
+#define DC_CCID_PME_D3COLD 0x80000000
+
+/* PCI power management control/status register */
+#define DC_CPMC_STATE 0x00000003
+#define DC_CPMC_PME_ENB 0x00000100
+#define DC_CPMC_PME_STS 0x00008000
+
+#define DC_PSTATE_D0 0x0
+#define DC_PSTATE_D1 0x1
+#define DC_PSTATE_D2 0x2
+#define DC_PSTATE_D3 0x3
+
+/* Device specific region */
+/* Configuration and driver area */
+#define DC_CFDD_DRVUSE 0x0000FFFF
+#define DC_CFDD_SNOOZE_MODE 0x40000000
+#define DC_CFDD_SLEEP_MODE 0x80000000
+
+/* Configuration wake-up command register */
+#define DC_CWUC_MUST_BE_ZERO 0x00000001
+#define DC_CWUC_SECUREON_ENB 0x00000002
+#define DC_CWUC_FORCE_WUL 0x00000004
+#define DC_CWUC_BNC_ABILITY 0x00000008
+#define DC_CWUC_AUI_ABILITY 0x00000010
+#define DC_CWUC_TP10_ABILITY 0x00000020
+#define DC_CWUC_MII_ABILITY 0x00000040
+#define DC_CWUC_SYM_ABILITY 0x00000080
+#define DC_CWUC_LOCK 0x00000100
+
+/*
+ * SROM nonsense.
+ */
+
+#define DC_IB_CTLRCNT 0x13
+#define DC_IB_LEAF0_CNUM 0x1A
+#define DC_IB_LEAF0_OFFSET 0x1B
+
+struct dc_info_leaf {
+ u_int16_t dc_conntype;
+ u_int8_t dc_blkcnt;
+ u_int8_t dc_rsvd;
+ u_int16_t dc_infoblk;
+};
+
+#define DC_CTYPE_10BT 0x0000
+#define DC_CTYPE_10BT_NWAY 0x0100
+#define DC_CTYPE_10BT_FDX 0x0204
+#define DC_CTYPE_10B2 0x0001
+#define DC_CTYPE_10B5 0x0002
+#define DC_CTYPE_100BT 0x0003
+#define DC_CTYPE_100BT_FDX 0x0205
+#define DC_CTYPE_100T4 0x0006
+#define DC_CTYPE_100FX 0x0007
+#define DC_CTYPE_100FX_FDX 0x0208
+#define DC_CTYPE_MII_10BT 0x0009
+#define DC_CTYPE_MII_10BT_FDX 0x020A
+#define DC_CTYPE_MII_100BT 0x000D
+#define DC_CTYPE_MII_100BT_FDX 0x020E
+#define DC_CTYPE_MII_100T4 0x000F
+#define DC_CTYPE_MII_100FX 0x0010
+#define DC_CTYPE_MII_100FX_FDX 0x0211
+#define DC_CTYPE_DYN_PUP_AUTOSENSE 0x0800
+#define DC_CTYPE_PUP_AUTOSENSe 0x8800
+#define DC_CTYPE_NOMEDIA 0xFFFF
+
+#define DC_EBLOCK_SIA 0x0002
+#define DC_EBLOCK_MII 0x0003
+#define DC_EBLOCK_SYM 0x0004
+#define DC_EBLOCK_RESET 0x0005
+#define DC_EBLOCK_PHY_SHUTDOWN 0x0006
+
+struct dc_leaf_hdr {
+ u_int16_t dc_mtype;
+ u_int8_t dc_mcnt;
+ u_int8_t dc_rsvd;
+};
+
+struct dc_eblock_hdr {
+ u_int8_t dc_len;
+ u_int8_t dc_type;
+};
+
+struct dc_eblock_sia {
+ struct dc_eblock_hdr dc_sia_hdr;
+ u_int8_t dc_sia_code;
+ u_int8_t dc_sia_mediaspec[6]; /* CSR13, CSR14, CSR15 */
+ u_int8_t dc_sia_gpio_ctl[2];
+ u_int8_t dc_sia_gpio_dat[2];
+};
+
+#define DC_SIA_CODE_10BT 0x00
+#define DC_SIA_CODE_10B2 0x01
+#define DC_SIA_CODE_10B5 0x02
+#define DC_SIA_CODE_10BT_FDX 0x04
+#define DC_SIA_CODE_EXT 0x40
+
+/*
+ * Note that the first word in the gpr and reset
+ * sequences is always a control word.
+ */
+struct dc_eblock_mii {
+ struct dc_eblock_hdr dc_mii_hdr;
+ u_int8_t dc_mii_phynum;
+ u_int8_t dc_gpr_len;
+/* u_int16_t dc_gpr_dat[n]; */
+/* u_int8_t dc_reset_len; */
+/* u_int16_t dc_reset_dat[n]; */
+/* There are other fields after these, but we don't
+ * care about them since they can be determined by looking
+ * at the PHY.
+ */
+};
+
+struct dc_eblock_sym {
+ struct dc_eblock_hdr dc_sym_hdr;
+ u_int8_t dc_sym_code;
+ u_int8_t dc_sym_gpio_ctl[2];
+ u_int8_t dc_sym_gpio_dat[2];
+ u_int8_t dc_sym_cmd[2];
+};
+
+#define DC_SYM_CODE_100BT 0x03
+#define DC_SYM_CODE_100BT_FDX 0x05
+#define DC_SYM_CODE_100T4 0x06
+#define DC_SYM_CODE_100FX 0x07
+#define DC_SYM_CODE_100FX_FDX 0x08
+
+struct dc_eblock_reset {
+ struct dc_eblock_hdr dc_reset_hdr;
+ u_int8_t dc_reset_len;
+/* u_int16_t dc_reset_dat[n]; */
+};
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_de.c b/sys/pci/if_de.c
new file mode 100644
index 0000000..a48d93c
--- /dev/null
+++ b/sys/pci/if_de.c
@@ -0,0 +1,5271 @@
+/* $NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $ */
+
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
+ * 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. 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp
+ *
+ */
+
+/*
+ * DEC 21040 PCI Ethernet Controller
+ *
+ * Written by Matt Thomas
+ * BPF support code stolen directly from if_ec.c
+ *
+ * This driver supports the DEC DE435 or any other PCI
+ * board which support 21040, 21041, or 21140 (mostly).
+ */
+#define TULIP_HDR_DATA
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/eventhandler.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+#include <net/if_dl.h>
+#ifdef TULIP_USE_SOFTINTR
+#include <net/netisr.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <vm/vm.h>
+
+#include <net/if_var.h>
+#include <vm/pmap.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/dc21040reg.h>
+
+/*
+ * Intel CPUs should use I/O mapped access.
+ */
+#if defined(__i386__)
+#define TULIP_IOMAPPED
+#endif
+
+#if 0
+/*
+ * This turns on all sort of debugging stuff and make the
+ * driver much larger.
+ */
+#define TULIP_DEBUG
+#endif
+
+#if 0
+#define TULIP_PERFSTATS
+#endif
+
+#if 0
+#define TULIP_USE_SOFTINTR
+#endif
+
+#define TULIP_HZ 10
+
+#include <pci/if_devar.h>
+
+/*
+ * This module supports
+ * the DEC 21040 PCI Ethernet Controller.
+ * the DEC 21041 PCI Ethernet Controller.
+ * the DEC 21140 PCI Fast Ethernet Controller.
+ */
+static void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr);
+static void tulip_intr_shared(void *arg);
+static void tulip_intr_normal(void *arg);
+static void tulip_init(tulip_softc_t * const sc);
+static void tulip_ifinit(void *);
+static void tulip_reset(tulip_softc_t * const sc);
+static void tulip_ifstart_one(struct ifnet *ifp);
+static void tulip_ifstart(struct ifnet *ifp);
+static struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m);
+static void tulip_txput_setup(tulip_softc_t * const sc);
+static void tulip_rx_intr(tulip_softc_t * const sc);
+static void tulip_addr_filter(tulip_softc_t * const sc);
+static unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno);
+static void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data);
+static int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities);
+static tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc);
+static int tulip_srom_decode(tulip_softc_t * const sc);
+static int tulip_ifmedia_change(struct ifnet * const ifp);
+static void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req);
+/* static void tulip_21140_map_media(tulip_softc_t *sc); */
+
+static void
+tulip_timeout_callback(
+ void *arg)
+{
+ tulip_softc_t * const sc = arg;
+ int s = splimp();
+
+ TULIP_PERFSTART(timeout)
+
+ sc->tulip_flags &= ~TULIP_TIMEOUTPENDING;
+ sc->tulip_probe_timeout -= 1000 / TULIP_HZ;
+ (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER);
+
+ TULIP_PERFEND(timeout);
+ splx(s);
+}
+
+static void
+tulip_timeout(
+ tulip_softc_t * const sc)
+{
+ if (sc->tulip_flags & TULIP_TIMEOUTPENDING)
+ return;
+ sc->tulip_flags |= TULIP_TIMEOUTPENDING;
+ timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ);
+}
+
+#if defined(TULIP_NEED_FASTTIMEOUT)
+static void
+tulip_fasttimeout_callback(
+ void *arg)
+{
+ tulip_softc_t * const sc = arg;
+ int s = splimp();
+
+ sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING;
+ (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER);
+ splx(s);
+}
+
+static void
+tulip_fasttimeout(
+ tulip_softc_t * const sc)
+{
+ if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING)
+ return;
+ sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING;
+ timeout(tulip_fasttimeout_callback, sc, 1);
+}
+#endif
+
+static int
+tulip_txprobe(
+ tulip_softc_t * const sc)
+{
+ struct mbuf *m;
+ /*
+ * Before we are sure this is the right media we need
+ * to send a small packet to make sure there's carrier.
+ * Strangely, BNC and AUI will "see" receive data if
+ * either is connected so the transmit is the only way
+ * to verify the connectivity.
+ */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return 0;
+ /*
+ * Construct a LLC TEST message which will point to ourselves.
+ */
+ bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6);
+ bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6);
+ mtod(m, struct ether_header *)->ether_type = htons(3);
+ mtod(m, unsigned char *)[14] = 0;
+ mtod(m, unsigned char *)[15] = 0;
+ mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */
+ m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
+ /*
+ * send it!
+ */
+ sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
+ sc->tulip_intrmask |= TULIP_STS_TXINTR;
+ sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ if ((m = tulip_txput(sc, m)) != NULL)
+ m_freem(m);
+ sc->tulip_probe.probe_txprobes++;
+ return 1;
+}
+
+#ifdef BIG_PACKET
+#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0)
+#else
+#define TULIP_SIAGEN_WATCHDOG 0
+#endif
+
+static void
+tulip_media_set(
+ tulip_softc_t * const sc,
+ tulip_media_t media)
+{
+ const tulip_media_info_t *mi = sc->tulip_mediums[media];
+
+ if (mi == NULL)
+ return;
+
+ /*
+ * If we are switching media, make sure we don't think there's
+ * any stale RX activity
+ */
+ sc->tulip_flags &= ~TULIP_RXACT;
+ if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
+ TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
+ TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx);
+ if (sc->tulip_features & TULIP_HAVE_SIAGP) {
+ TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
+ DELAY(50);
+ TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
+ } else {
+ TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
+ }
+ TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity);
+ } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
+#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL)
+ /*
+ * If the cmdmode bits don't match the currently operating mode,
+ * set the cmdmode appropriately and reset the chip.
+ */
+ if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
+ sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
+ sc->tulip_cmdmode |= mi->mi_cmdmode;
+ tulip_reset(sc);
+ }
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata);
+ } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
+ /*
+ * If the cmdmode bits don't match the currently operating mode,
+ * set the cmdmode appropriately and reset the chip.
+ */
+ if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
+ sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
+ sc->tulip_cmdmode |= mi->mi_cmdmode;
+ tulip_reset(sc);
+ }
+ TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol);
+ TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata);
+ } else if (mi->mi_type == TULIP_MEDIAINFO_MII
+ && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) {
+ int idx;
+ if (sc->tulip_features & TULIP_HAVE_SIAGP) {
+ const u_int8_t *dp;
+ dp = &sc->tulip_rombuf[mi->mi_reset_offset];
+ for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
+ }
+ sc->tulip_phyaddr = mi->mi_phyaddr;
+ dp = &sc->tulip_rombuf[mi->mi_gpr_offset];
+ for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
+ }
+ } else {
+ for (idx = 0; idx < mi->mi_reset_length; idx++) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]);
+ }
+ sc->tulip_phyaddr = mi->mi_phyaddr;
+ for (idx = 0; idx < mi->mi_gpr_length; idx++) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]);
+ }
+ }
+ if (sc->tulip_flags & TULIP_TRYNWAY) {
+ tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
+ } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
+ u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL);
+ data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE);
+ sc->tulip_flags &= ~TULIP_DIDNWAY;
+ if (TULIP_IS_MEDIA_FD(media))
+ data |= PHYCTL_FULL_DUPLEX;
+ if (TULIP_IS_MEDIA_100MB(media))
+ data |= PHYCTL_SELECT_100MB;
+ tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data);
+ }
+ }
+}
+
+static void
+tulip_linkup(
+ tulip_softc_t * const sc,
+ tulip_media_t media)
+{
+ if ((sc->tulip_flags & TULIP_LINKUP) == 0)
+ sc->tulip_flags |= TULIP_PRINTLINKUP;
+ sc->tulip_flags |= TULIP_LINKUP;
+ sc->tulip_if.if_flags &= ~IFF_OACTIVE;
+#if 0 /* XXX how does with work with ifmedia? */
+ if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
+ if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
+ if (TULIP_CAN_MEDIA_FD(media)
+ && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL)
+ media = TULIP_FD_MEDIA_OF(media);
+ } else {
+ if (TULIP_IS_MEDIA_FD(media)
+ && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL)
+ media = TULIP_HD_MEDIA_OF(media);
+ }
+ }
+#endif
+ if (sc->tulip_media != media) {
+#ifdef TULIP_DEBUG
+ sc->tulip_dbg.dbg_last_media = sc->tulip_media;
+#endif
+ sc->tulip_media = media;
+ sc->tulip_flags |= TULIP_PRINTMEDIA;
+ if (TULIP_IS_MEDIA_FD(sc->tulip_media)) {
+ sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
+ } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) {
+ sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
+ }
+ }
+ /*
+ * We could set probe_timeout to 0 but setting to 3000 puts this
+ * in one central place and the only matters is tulip_link is
+ * followed by a tulip_timeout. Therefore setting it should not
+ * result in aberrant behavour.
+ */
+ sc->tulip_probe_timeout = 3000;
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY);
+ if (sc->tulip_flags & TULIP_INRESET) {
+ tulip_media_set(sc, sc->tulip_media);
+ } else if (sc->tulip_probe_media != sc->tulip_media) {
+ /*
+ * No reason to change media if we have the right media.
+ */
+ tulip_reset(sc);
+ }
+ tulip_init(sc);
+}
+
+static void
+tulip_media_print(
+ tulip_softc_t * const sc)
+{
+ if ((sc->tulip_flags & TULIP_LINKUP) == 0)
+ return;
+ if (sc->tulip_flags & TULIP_PRINTMEDIA) {
+ printf("%s%d: enabling %s port\n",
+ sc->tulip_name, sc->tulip_unit,
+ tulip_mediums[sc->tulip_media]);
+ sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
+ } else if (sc->tulip_flags & TULIP_PRINTLINKUP) {
+ printf("%s%d: link up\n", sc->tulip_name, sc->tulip_unit);
+ sc->tulip_flags &= ~TULIP_PRINTLINKUP;
+ }
+}
+
+#if defined(TULIP_DO_GPR_SENSE)
+static tulip_media_t
+tulip_21140_gpr_media_sense(
+ tulip_softc_t * const sc)
+{
+ tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN;
+ tulip_media_t last_media = TULIP_MEDIA_UNKNOWN;
+ tulip_media_t media;
+
+ /*
+ * If one of the media blocks contained a default media flag,
+ * use that.
+ */
+ for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
+ const tulip_media_info_t *mi;
+ /*
+ * Media is not supported (or is full-duplex).
+ */
+ if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media))
+ continue;
+ if (mi->mi_type != TULIP_MEDIAINFO_GPR)
+ continue;
+
+ /*
+ * Remember the media is this is the "default" media.
+ */
+ if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN)
+ maybe_media = media;
+
+ /*
+ * No activity mask? Can't see if it is active if there's no mask.
+ */
+ if (mi->mi_actmask == 0)
+ continue;
+
+ /*
+ * Does the activity data match?
+ */
+ if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata)
+ continue;
+
+#if defined(TULIP_DEBUG)
+ printf("%s%d: gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n",
+ sc->tulip_name, sc->tulip_unit, tulip_mediums[media],
+ TULIP_CSR_READ(sc, csr_gp) & 0xFF,
+ mi->mi_actmask, mi->mi_actdata);
+#endif
+ /*
+ * It does! If this is the first media we detected, then
+ * remember this media. If isn't the first, then there were
+ * multiple matches which we equate to no match (since we don't
+ * which to select (if any).
+ */
+ if (last_media == TULIP_MEDIA_UNKNOWN) {
+ last_media = media;
+ } else if (last_media != media) {
+ last_media = TULIP_MEDIA_UNKNOWN;
+ }
+ }
+ return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media;
+}
+#endif /* TULIP_DO_GPR_SENSE */
+
+static tulip_link_status_t
+tulip_media_link_monitor(
+ tulip_softc_t * const sc)
+{
+ const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media];
+ tulip_link_status_t linkup = TULIP_LINK_DOWN;
+
+ if (mi == NULL) {
+#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
+ panic("tulip_media_link_monitor: %s: botch at line %d\n",
+ tulip_mediums[sc->tulip_media],__LINE__);
+#endif
+ return TULIP_LINK_UNKNOWN;
+ }
+
+
+ /*
+ * Have we seen some packets? If so, the link must be good.
+ */
+ if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) {
+ sc->tulip_flags &= ~TULIP_RXACT;
+ sc->tulip_probe_timeout = 3000;
+ return TULIP_LINK_UP;
+ }
+
+ sc->tulip_flags &= ~TULIP_RXACT;
+ if (mi->mi_type == TULIP_MEDIAINFO_MII) {
+ u_int32_t status;
+ /*
+ * Read the PHY status register.
+ */
+ status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
+ if (status & PHYSTS_AUTONEG_DONE) {
+ /*
+ * If the PHY has completed autonegotiation, see the if the
+ * remote systems abilities have changed. If so, upgrade or
+ * downgrade as appropriate.
+ */
+ u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES);
+ abilities = (abilities << 6) & status;
+ if (abilities != sc->tulip_abilities) {
+#if defined(TULIP_DEBUG)
+ loudprintf("%s%d(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n",
+ sc->tulip_name, sc->tulip_unit, sc->tulip_phyaddr,
+ sc->tulip_abilities, abilities);
+#endif
+ if (tulip_mii_map_abilities(sc, abilities)) {
+ tulip_linkup(sc, sc->tulip_probe_media);
+ return TULIP_LINK_UP;
+ }
+ /*
+ * if we had selected media because of autonegotiation,
+ * we need to probe for the new media.
+ */
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ if (sc->tulip_flags & TULIP_DIDNWAY)
+ return TULIP_LINK_DOWN;
+ }
+ }
+ /*
+ * The link is now up. If was down, say its back up.
+ */
+ if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP)
+ linkup = TULIP_LINK_UP;
+ } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
+ /*
+ * No activity sensor? Assume all's well.
+ */
+ if (mi->mi_actmask == 0)
+ return TULIP_LINK_UNKNOWN;
+ /*
+ * Does the activity data match?
+ */
+ if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata)
+ linkup = TULIP_LINK_UP;
+ } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
+ /*
+ * Assume non TP ok for now.
+ */
+ if (!TULIP_IS_MEDIA_TP(sc->tulip_media))
+ return TULIP_LINK_UNKNOWN;
+ if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0)
+ linkup = TULIP_LINK_UP;
+#if defined(TULIP_DEBUG)
+ if (sc->tulip_probe_timeout <= 0)
+ printf("%s%d: sia status = 0x%08x\n", sc->tulip_name,
+ sc->tulip_unit, TULIP_CSR_READ(sc, csr_sia_status));
+#endif
+ } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
+ return TULIP_LINK_UNKNOWN;
+ }
+ /*
+ * We will wait for 3 seconds until the link goes into suspect mode.
+ */
+ if (sc->tulip_flags & TULIP_LINKUP) {
+ if (linkup == TULIP_LINK_UP)
+ sc->tulip_probe_timeout = 3000;
+ if (sc->tulip_probe_timeout > 0)
+ return TULIP_LINK_UP;
+
+ sc->tulip_flags &= ~TULIP_LINKUP;
+ printf("%s%d: link down: cable problem?\n", sc->tulip_name, sc->tulip_unit);
+ }
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_link_downed++;
+#endif
+ return TULIP_LINK_DOWN;
+}
+
+static void
+tulip_media_poll(
+ tulip_softc_t * const sc,
+ tulip_mediapoll_event_t event)
+{
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_events[event]++;
+#endif
+ if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE
+ && event == TULIP_MEDIAPOLL_TIMER) {
+ switch (tulip_media_link_monitor(sc)) {
+ case TULIP_LINK_DOWN: {
+ /*
+ * Link Monitor failed. Probe for new media.
+ */
+ event = TULIP_MEDIAPOLL_LINKFAIL;
+ break;
+ }
+ case TULIP_LINK_UP: {
+ /*
+ * Check again soon.
+ */
+ tulip_timeout(sc);
+ return;
+ }
+ case TULIP_LINK_UNKNOWN: {
+ /*
+ * We can't tell so don't bother.
+ */
+ return;
+ }
+ }
+ }
+
+ if (event == TULIP_MEDIAPOLL_LINKFAIL) {
+ if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) {
+ if (TULIP_DO_AUTOSENSE(sc)) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_link_failures++;
+#endif
+ sc->tulip_media = TULIP_MEDIA_UNKNOWN;
+ if (sc->tulip_if.if_flags & IFF_UP)
+ tulip_reset(sc); /* restart probe */
+ }
+ return;
+ }
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_link_pollintrs++;
+#endif
+ }
+
+ if (event == TULIP_MEDIAPOLL_START) {
+ sc->tulip_if.if_flags |= IFF_OACTIVE;
+ if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE)
+ return;
+ sc->tulip_probe_mediamask = 0;
+ sc->tulip_probe_passes = 0;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_media_probes++;
+#endif
+ /*
+ * If the SROM contained an explicit media to use, use it.
+ */
+ sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX);
+ sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS;
+ sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
+ /*
+ * connidx is defaulted to a media_unknown type.
+ */
+ sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media;
+ if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) {
+ tulip_linkup(sc, sc->tulip_probe_media);
+ tulip_timeout(sc);
+ return;
+ }
+
+ if (sc->tulip_features & TULIP_HAVE_GPR) {
+ sc->tulip_probe_state = TULIP_PROBE_GPRTEST;
+ sc->tulip_probe_timeout = 2000;
+ } else {
+ sc->tulip_probe_media = TULIP_MEDIA_MAX;
+ sc->tulip_probe_timeout = 0;
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ }
+ }
+
+ /*
+ * Ignore txprobe failures or spurious callbacks.
+ */
+ if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED
+ && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) {
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+ return;
+ }
+
+ /*
+ * If we really transmitted a packet, then that's the media we'll use.
+ */
+ if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) {
+ if (event == TULIP_MEDIAPOLL_LINKPASS) {
+ /* XXX Check media status just to be sure */
+ sc->tulip_probe_media = TULIP_MEDIA_10BASET;
+#if defined(TULIP_DEBUG)
+ } else {
+ sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
+#endif
+ }
+ tulip_linkup(sc, sc->tulip_probe_media);
+ tulip_timeout(sc);
+ return;
+ }
+
+ if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) {
+#if defined(TULIP_DO_GPR_SENSE)
+ /*
+ * Check for media via the general purpose register.
+ *
+ * Try to sense the media via the GPR. If the same value
+ * occurs 3 times in a row then just use that.
+ */
+ if (sc->tulip_probe_timeout > 0) {
+ tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc);
+#if defined(TULIP_DEBUG)
+ printf("%s%d: media_poll: gpr sensing = %s\n",
+ sc->tulip_name, sc->tulip_unit, tulip_mediums[new_probe_media]);
+#endif
+ if (new_probe_media != TULIP_MEDIA_UNKNOWN) {
+ if (new_probe_media == sc->tulip_probe_media) {
+ if (--sc->tulip_probe_count == 0)
+ tulip_linkup(sc, sc->tulip_probe_media);
+ } else {
+ sc->tulip_probe_count = 10;
+ }
+ }
+ sc->tulip_probe_media = new_probe_media;
+ tulip_timeout(sc);
+ return;
+ }
+#endif /* TULIP_DO_GPR_SENSE */
+ /*
+ * Brute force. We cycle through each of the media types
+ * and try to transmit a packet.
+ */
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ sc->tulip_probe_media = TULIP_MEDIA_MAX;
+ sc->tulip_probe_timeout = 0;
+ tulip_timeout(sc);
+ return;
+ }
+
+ if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST
+ && (sc->tulip_features & TULIP_HAVE_MII)) {
+ tulip_media_t old_media = sc->tulip_probe_media;
+ tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
+ switch (sc->tulip_probe_state) {
+ case TULIP_PROBE_FAILED:
+ case TULIP_PROBE_MEDIATEST: {
+ /*
+ * Try the next media.
+ */
+ sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask;
+ sc->tulip_probe_timeout = 0;
+#ifdef notyet
+ if (sc->tulip_probe_state == TULIP_PROBE_FAILED)
+ break;
+ if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
+ break;
+ sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300;
+#endif
+ break;
+ }
+ case TULIP_PROBE_PHYAUTONEG: {
+ return;
+ }
+ case TULIP_PROBE_INACTIVE: {
+ /*
+ * Only probe if we autonegotiated a media that hasn't failed.
+ */
+ sc->tulip_probe_timeout = 0;
+ if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) {
+ sc->tulip_probe_media = old_media;
+ break;
+ }
+ tulip_linkup(sc, sc->tulip_probe_media);
+ tulip_timeout(sc);
+ return;
+ }
+ default: {
+#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
+ panic("tulip_media_poll: botch at line %d\n", __LINE__);
+#endif
+ break;
+ }
+ }
+ }
+
+ if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++;
+#endif
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+ return;
+ }
+
+ /*
+ * switch to another media if we tried this one enough.
+ */
+ if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) {
+#if defined(TULIP_DEBUG)
+ if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
+ printf("%s%d: poll media unknown!\n",
+ sc->tulip_name, sc->tulip_unit);
+ sc->tulip_probe_media = TULIP_MEDIA_MAX;
+ }
+#endif
+ /*
+ * Find the next media type to check for. Full Duplex
+ * types are not allowed.
+ */
+ do {
+ sc->tulip_probe_media -= 1;
+ if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
+ if (++sc->tulip_probe_passes == 3) {
+ printf("%s%d: autosense failed: cable problem?\n",
+ sc->tulip_name, sc->tulip_unit);
+ if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
+ sc->tulip_if.if_flags &= ~IFF_RUNNING;
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ return;
+ }
+ }
+ sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */
+ sc->tulip_probe_mediamask = 0;
+ sc->tulip_probe_media = TULIP_MEDIA_MAX - 1;
+ }
+ } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL
+ || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media))
+ || TULIP_IS_MEDIA_FD(sc->tulip_probe_media));
+
+#if defined(TULIP_DEBUG)
+ printf("%s%d: %s: probing %s\n", sc->tulip_name, sc->tulip_unit,
+ event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout",
+ tulip_mediums[sc->tulip_probe_media]);
+#endif
+ sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000;
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ sc->tulip_probe.probe_txprobes = 0;
+ tulip_reset(sc);
+ tulip_media_set(sc, sc->tulip_probe_media);
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+ }
+ tulip_timeout(sc);
+
+ /*
+ * If this is hanging off a phy, we know are doing NWAY and we have
+ * forced the phy to a specific speed. Wait for link up before
+ * before sending a packet.
+ */
+ switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) {
+ case TULIP_MEDIAINFO_MII: {
+ if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
+ return;
+ break;
+ }
+ case TULIP_MEDIAINFO_SIA: {
+ if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) {
+ if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL)
+ return;
+ tulip_linkup(sc, sc->tulip_probe_media);
+#ifdef notyet
+ if (sc->tulip_features & TULIP_HAVE_MII)
+ tulip_timeout(sc);
+#endif
+ return;
+ }
+ break;
+ }
+ case TULIP_MEDIAINFO_RESET:
+ case TULIP_MEDIAINFO_SYM:
+ case TULIP_MEDIAINFO_NONE:
+ case TULIP_MEDIAINFO_GPR: {
+ break;
+ }
+ }
+ /*
+ * Try to send a packet.
+ */
+ tulip_txprobe(sc);
+}
+
+static void
+tulip_media_select(
+ tulip_softc_t * const sc)
+{
+ if (sc->tulip_features & TULIP_HAVE_GPR) {
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata);
+ }
+ /*
+ * If this board has no media, just return
+ */
+ if (sc->tulip_features & TULIP_HAVE_NOMEDIA)
+ return;
+
+ if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START);
+ } else {
+ tulip_media_set(sc, sc->tulip_media);
+ }
+}
+
+static void
+tulip_21040_mediainfo_init(
+ tulip_softc_t * const sc,
+ tulip_media_t media)
+{
+ sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
+ |TULIP_CMD_BACKOFFCTR;
+ sc->tulip_if.if_baudrate = 10000000;
+
+ if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) {
+ TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD);
+ sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
+ }
+
+ if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) {
+ TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC);
+ }
+
+ if (media == TULIP_MEDIA_UNKNOWN) {
+ TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA);
+ }
+}
+
+static void
+tulip_21040_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN);
+ return;
+}
+
+static void
+tulip_21040_10baset_only_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET);
+ tulip_media_set(sc, TULIP_MEDIA_10BASET);
+ sc->tulip_media = TULIP_MEDIA_10BASET;
+}
+
+static void
+tulip_21040_10baset_only_media_select(
+ tulip_softc_t * const sc)
+{
+ sc->tulip_flags |= TULIP_LINKUP;
+ if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) {
+ sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
+ sc->tulip_flags &= ~TULIP_SQETEST;
+ } else {
+ sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
+ sc->tulip_flags |= TULIP_SQETEST;
+ }
+ tulip_media_set(sc, sc->tulip_media);
+}
+
+static void
+tulip_21040_auibnc_only_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC);
+ sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
+ tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
+ sc->tulip_media = TULIP_MEDIA_AUIBNC;
+}
+
+static void
+tulip_21040_auibnc_only_media_select(
+ tulip_softc_t * const sc)
+{
+ tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
+ sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
+}
+
+static const tulip_boardsw_t tulip_21040_boardsw = {
+ TULIP_21040_GENERIC,
+ tulip_21040_media_probe,
+ tulip_media_select,
+ tulip_media_poll,
+};
+
+static const tulip_boardsw_t tulip_21040_10baset_only_boardsw = {
+ TULIP_21040_GENERIC,
+ tulip_21040_10baset_only_media_probe,
+ tulip_21040_10baset_only_media_select,
+ NULL,
+};
+
+static const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = {
+ TULIP_21040_GENERIC,
+ tulip_21040_auibnc_only_media_probe,
+ tulip_21040_auibnc_only_media_select,
+ NULL,
+};
+
+static void
+tulip_21041_mediainfo_init(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t * const mi = sc->tulip_mediainfo;
+
+#ifdef notyet
+ if (sc->tulip_revinfo >= 0x20) {
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC);
+ return;
+ }
+#endif
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI);
+ TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC);
+}
+
+static void
+tulip_21041_media_probe(
+ tulip_softc_t * const sc)
+{
+ sc->tulip_if.if_baudrate = 10000000;
+ sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT
+ |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR;
+ sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
+ tulip_21041_mediainfo_init(sc);
+}
+
+static void
+tulip_21041_media_poll(
+ tulip_softc_t * const sc,
+ const tulip_mediapoll_event_t event)
+{
+ u_int32_t sia_status;
+
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_events[event]++;
+#endif
+
+ if (event == TULIP_MEDIAPOLL_LINKFAIL) {
+ if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE
+ || !TULIP_DO_AUTOSENSE(sc))
+ return;
+ sc->tulip_media = TULIP_MEDIA_UNKNOWN;
+ tulip_reset(sc); /* start probe */
+ return;
+ }
+
+ /*
+ * If we've been been asked to start a poll or link change interrupt
+ * restart the probe (and reset the tulip to a known state).
+ */
+ if (event == TULIP_MEDIAPOLL_START) {
+ sc->tulip_if.if_flags |= IFF_OACTIVE;
+ sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN);
+#ifdef notyet
+ if (sc->tulip_revinfo >= 0x20) {
+ sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
+ sc->tulip_flags |= TULIP_DIDNWAY;
+ }
+#endif
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ sc->tulip_probe_media = TULIP_MEDIA_10BASET;
+ sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT;
+ tulip_media_set(sc, TULIP_MEDIA_10BASET);
+ tulip_timeout(sc);
+ return;
+ }
+
+ if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
+ return;
+
+ if (event == TULIP_MEDIAPOLL_TXPROBE_OK) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
+#endif
+ tulip_linkup(sc, sc->tulip_probe_media);
+ return;
+ }
+
+ sia_status = TULIP_CSR_READ(sc, csr_sia_status);
+ TULIP_CSR_WRITE(sc, csr_sia_status, sia_status);
+ if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) {
+ if (sc->tulip_revinfo >= 0x20) {
+ if (sia_status & (PHYSTS_10BASET_FD << (16 - 6)))
+ sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
+ }
+ /*
+ * If the link has passed LinkPass, 10baseT is the
+ * proper media to use.
+ */
+ tulip_linkup(sc, sc->tulip_probe_media);
+ return;
+ }
+
+ /*
+ * wait for up to 2.4 seconds for the link to reach pass state.
+ * Only then start scanning the other media for activity.
+ * choose media with receive activity over those without.
+ */
+ if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) {
+ if (event != TULIP_MEDIAPOLL_TIMER)
+ return;
+ if (sc->tulip_probe_timeout > 0
+ && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) {
+ tulip_timeout(sc);
+ return;
+ }
+ sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
+ sc->tulip_flags |= TULIP_WANTRXACT;
+ if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) {
+ sc->tulip_probe_media = TULIP_MEDIA_BNC;
+ } else {
+ sc->tulip_probe_media = TULIP_MEDIA_AUI;
+ }
+ tulip_media_set(sc, sc->tulip_probe_media);
+ tulip_timeout(sc);
+ return;
+ }
+
+ /*
+ * If we failed, clear the txprobe active flag.
+ */
+ if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED)
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+
+
+ if (event == TULIP_MEDIAPOLL_TIMER) {
+ /*
+ * If we've received something, then that's our link!
+ */
+ if (sc->tulip_flags & TULIP_RXACT) {
+ tulip_linkup(sc, sc->tulip_probe_media);
+ return;
+ }
+ /*
+ * if no txprobe active
+ */
+ if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0
+ && ((sc->tulip_flags & TULIP_WANTRXACT) == 0
+ || (sia_status & TULIP_SIASTS_RXACTIVITY))) {
+ sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
+ tulip_txprobe(sc);
+ tulip_timeout(sc);
+ return;
+ }
+ /*
+ * Take 2 passes through before deciding to not
+ * wait for receive activity. Then take another
+ * two passes before spitting out a warning.
+ */
+ if (sc->tulip_probe_timeout <= 0) {
+ if (sc->tulip_flags & TULIP_WANTRXACT) {
+ sc->tulip_flags &= ~TULIP_WANTRXACT;
+ sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
+ } else {
+ printf("%s%d: autosense failed: cable problem?\n",
+ sc->tulip_name, sc->tulip_unit);
+ if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
+ sc->tulip_if.if_flags &= ~IFF_RUNNING;
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ return;
+ }
+ }
+ }
+ }
+
+ /*
+ * Since this media failed to probe, try the other one.
+ */
+ sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
+ if (sc->tulip_probe_media == TULIP_MEDIA_AUI) {
+ sc->tulip_probe_media = TULIP_MEDIA_BNC;
+ } else {
+ sc->tulip_probe_media = TULIP_MEDIA_AUI;
+ }
+ tulip_media_set(sc, sc->tulip_probe_media);
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+ tulip_timeout(sc);
+}
+
+static const tulip_boardsw_t tulip_21041_boardsw = {
+ TULIP_21041_GENERIC,
+ tulip_21041_media_probe,
+ tulip_media_select,
+ tulip_21041_media_poll
+};
+
+static const tulip_phy_attr_t tulip_mii_phy_attrlist[] = {
+ { 0x20005c00, 0, /* 08-00-17 */
+ {
+ { 0x19, 0x0040, 0x0040 }, /* 10TX */
+ { 0x19, 0x0040, 0x0000 }, /* 100TX */
+ },
+#if defined(TULIP_DEBUG)
+ "NS DP83840",
+#endif
+ },
+ { 0x0281F400, 0, /* 00-A0-7D */
+ {
+ { 0x12, 0x0010, 0x0000 }, /* 10T */
+ { }, /* 100TX */
+ { 0x12, 0x0010, 0x0010 }, /* 100T4 */
+ { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */
+ },
+#if defined(TULIP_DEBUG)
+ "Seeq 80C240"
+#endif
+ },
+#if 0
+ { 0x0015F420, 0, /* 00-A0-7D */
+ {
+ { 0x12, 0x0010, 0x0000 }, /* 10T */
+ { }, /* 100TX */
+ { 0x12, 0x0010, 0x0010 }, /* 100T4 */
+ { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */
+ },
+#if defined(TULIP_DEBUG)
+ "Broadcom BCM5000"
+#endif
+ },
+#endif
+ { 0x0281F400, 0, /* 00-A0-BE */
+ {
+ { 0x11, 0x8000, 0x0000 }, /* 10T */
+ { 0x11, 0x8000, 0x8000 }, /* 100TX */
+ { }, /* 100T4 */
+ { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */
+ },
+#if defined(TULIP_DEBUG)
+ "ICS 1890"
+#endif
+ },
+ { 0 }
+};
+
+static tulip_media_t
+tulip_mii_phy_readspecific(
+ tulip_softc_t * const sc)
+{
+ const tulip_phy_attr_t *attr;
+ u_int16_t data;
+ u_int32_t id;
+ unsigned idx = 0;
+ static const tulip_media_t table[] = {
+ TULIP_MEDIA_UNKNOWN,
+ TULIP_MEDIA_10BASET,
+ TULIP_MEDIA_100BASETX,
+ TULIP_MEDIA_100BASET4,
+ TULIP_MEDIA_UNKNOWN,
+ TULIP_MEDIA_10BASET_FD,
+ TULIP_MEDIA_100BASETX_FD,
+ TULIP_MEDIA_UNKNOWN
+ };
+
+ /*
+ * Don't read phy specific registers if link is not up.
+ */
+ data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
+ if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS))
+ return TULIP_MEDIA_UNKNOWN;
+
+ id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) |
+ tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH);
+ for (attr = tulip_mii_phy_attrlist;; attr++) {
+ if (attr->attr_id == 0)
+ return TULIP_MEDIA_UNKNOWN;
+ if ((id & ~0x0F) == attr->attr_id)
+ break;
+ }
+
+ if (attr->attr_modes[PHY_MODE_100TX].pm_regno) {
+ const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX];
+ data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
+ if ((data & pm->pm_mask) == pm->pm_value)
+ idx = 2;
+ }
+ if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) {
+ const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4];
+ data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
+ if ((data & pm->pm_mask) == pm->pm_value)
+ idx = 3;
+ }
+ if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) {
+ const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T];
+ data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
+ if ((data & pm->pm_mask) == pm->pm_value)
+ idx = 1;
+ }
+ if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) {
+ const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX];
+ data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
+ idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0);
+ }
+ return table[idx];
+}
+
+static unsigned
+tulip_mii_get_phyaddr(
+ tulip_softc_t * const sc,
+ unsigned offset)
+{
+ unsigned phyaddr;
+
+ for (phyaddr = 1; phyaddr < 32; phyaddr++) {
+ unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
+ if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
+ continue;
+ if (offset == 0)
+ return phyaddr;
+ offset--;
+ }
+ if (offset == 0) {
+ unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS);
+ if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
+ return TULIP_MII_NOPHY;
+ return 0;
+ }
+ return TULIP_MII_NOPHY;
+}
+
+static int
+tulip_mii_map_abilities(
+ tulip_softc_t * const sc,
+ unsigned abilities)
+{
+ sc->tulip_abilities = abilities;
+ if (abilities & PHYSTS_100BASETX_FD) {
+ sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD;
+ } else if (abilities & PHYSTS_100BASET4) {
+ sc->tulip_probe_media = TULIP_MEDIA_100BASET4;
+ } else if (abilities & PHYSTS_100BASETX) {
+ sc->tulip_probe_media = TULIP_MEDIA_100BASETX;
+ } else if (abilities & PHYSTS_10BASET_FD) {
+ sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
+ } else if (abilities & PHYSTS_10BASET) {
+ sc->tulip_probe_media = TULIP_MEDIA_10BASET;
+ } else {
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ return 0;
+ }
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ return 1;
+}
+
+static void
+tulip_mii_autonegotiate(
+ tulip_softc_t * const sc,
+ const unsigned phyaddr)
+{
+ switch (sc->tulip_probe_state) {
+ case TULIP_PROBE_MEDIATEST:
+ case TULIP_PROBE_INACTIVE: {
+ sc->tulip_flags |= TULIP_DIDNWAY;
+ tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET);
+ sc->tulip_probe_timeout = 3000;
+ sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR;
+ sc->tulip_probe_state = TULIP_PROBE_PHYRESET;
+ /* FALL THROUGH */
+ }
+ case TULIP_PROBE_PHYRESET: {
+ u_int32_t status;
+ u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
+ if (data & PHYCTL_RESET) {
+ if (sc->tulip_probe_timeout > 0) {
+ tulip_timeout(sc);
+ return;
+ }
+ printf("%s%d(phy%d): error: reset of PHY never completed!\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr);
+ sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
+ sc->tulip_probe_state = TULIP_PROBE_FAILED;
+ sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+ return;
+ }
+ status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
+ if ((status & PHYSTS_CAN_AUTONEG) == 0) {
+#if defined(TULIP_DEBUG)
+ loudprintf("%s%d(phy%d): autonegotiation disabled\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr);
+#endif
+ sc->tulip_flags &= ~TULIP_DIDNWAY;
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ return;
+ }
+ if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01))
+ tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01);
+ tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE);
+ data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
+#if defined(TULIP_DEBUG)
+ if ((data & PHYCTL_AUTONEG_ENABLE) == 0)
+ loudprintf("%s%d(phy%d): oops: enable autonegotiation failed: 0x%04x\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr, data);
+ else
+ loudprintf("%s%d(phy%d): autonegotiation restarted: 0x%04x\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr, data);
+ sc->tulip_dbg.dbg_nway_starts++;
+#endif
+ sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG;
+ sc->tulip_probe_timeout = 3000;
+ /* FALL THROUGH */
+ }
+ case TULIP_PROBE_PHYAUTONEG: {
+ u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
+ u_int32_t data;
+ if ((status & PHYSTS_AUTONEG_DONE) == 0) {
+ if (sc->tulip_probe_timeout > 0) {
+ tulip_timeout(sc);
+ return;
+ }
+#if defined(TULIP_DEBUG)
+ loudprintf("%s%d(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr, status,
+ tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL));
+#endif
+ sc->tulip_flags &= ~TULIP_DIDNWAY;
+ sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
+ return;
+ }
+ data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES);
+#if defined(TULIP_DEBUG)
+ loudprintf("%s%d(phy%d): autonegotiation complete: 0x%04x\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr, data);
+#endif
+ data = (data << 6) & status;
+ if (!tulip_mii_map_abilities(sc, data))
+ sc->tulip_flags &= ~TULIP_DIDNWAY;
+ return;
+ }
+ default: {
+#if defined(DIAGNOSTIC)
+ panic("tulip_media_poll: botch at line %d\n", __LINE__);
+#endif
+ break;
+ }
+ }
+#if defined(TULIP_DEBUG)
+ loudprintf("%s%d(phy%d): autonegotiation failure: state = %d\n",
+ sc->tulip_name, sc->tulip_unit, phyaddr, sc->tulip_probe_state);
+ sc->tulip_dbg.dbg_nway_failures++;
+#endif
+}
+
+static void
+tulip_2114x_media_preset(
+ tulip_softc_t * const sc)
+{
+ const tulip_media_info_t *mi = NULL;
+ tulip_media_t media = sc->tulip_media;
+
+ if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
+ media = sc->tulip_media;
+ else
+ media = sc->tulip_probe_media;
+
+ sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT;
+ sc->tulip_flags &= ~TULIP_SQETEST;
+ if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) {
+#if defined(TULIP_DEBUG)
+ if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) {
+#endif
+ mi = sc->tulip_mediums[media];
+ if (mi->mi_type == TULIP_MEDIAINFO_MII) {
+ sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
+ } else if (mi->mi_type == TULIP_MEDIAINFO_GPR
+ || mi->mi_type == TULIP_MEDIAINFO_SYM) {
+ sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
+ sc->tulip_cmdmode |= mi->mi_cmdmode;
+ } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
+ TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
+ }
+#if defined(TULIP_DEBUG)
+ } else {
+ printf("%s%d: preset: bad media %d!\n",
+ sc->tulip_name, sc->tulip_unit, media);
+ }
+#endif
+ }
+ switch (media) {
+ case TULIP_MEDIA_BNC:
+ case TULIP_MEDIA_AUI:
+ case TULIP_MEDIA_10BASET: {
+ sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
+ sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
+ sc->tulip_if.if_baudrate = 10000000;
+ sc->tulip_flags |= TULIP_SQETEST;
+ break;
+ }
+ case TULIP_MEDIA_10BASET_FD: {
+ sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL;
+ sc->tulip_if.if_baudrate = 10000000;
+ break;
+ }
+ case TULIP_MEDIA_100BASEFX:
+ case TULIP_MEDIA_100BASET4:
+ case TULIP_MEDIA_100BASETX: {
+ sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL);
+ sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
+ sc->tulip_if.if_baudrate = 100000000;
+ break;
+ }
+ case TULIP_MEDIA_100BASEFX_FD:
+ case TULIP_MEDIA_100BASETX_FD: {
+ sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT;
+ sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
+ sc->tulip_if.if_baudrate = 100000000;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+}
+
+/*
+ ********************************************************************
+ * Start of 21140/21140A support which does not use the MII interface
+ */
+
+static void
+tulip_null_media_poll(
+ tulip_softc_t * const sc,
+ tulip_mediapoll_event_t event)
+{
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_events[event]++;
+#endif
+#if defined(DIAGNOSTIC)
+ printf("%s%d: botch(media_poll) at line %d\n",
+ sc->tulip_name, sc->tulip_unit, __LINE__);
+#endif
+}
+
+__inline__ static void
+tulip_21140_mediainit(
+ tulip_softc_t * const sc,
+ tulip_media_info_t * const mip,
+ tulip_media_t const media,
+ unsigned gpdata,
+ unsigned cmdmode)
+{
+ sc->tulip_mediums[media] = mip;
+ mip->mi_type = TULIP_MEDIAINFO_GPR;
+ mip->mi_cmdmode = cmdmode;
+ mip->mi_gpdata = gpdata;
+}
+
+static void
+tulip_21140_evalboard_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t *mip = sc->tulip_mediainfo;
+
+ sc->tulip_gpinit = TULIP_GP_EB_PINS;
+ sc->tulip_gpdata = TULIP_GP_EB_INIT;
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
+ TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
+ DELAY(1000000);
+ if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) {
+ sc->tulip_media = TULIP_MEDIA_10BASET;
+ } else {
+ sc->tulip_media = TULIP_MEDIA_100BASETX;
+ }
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
+ TULIP_GP_EB_INIT,
+ TULIP_CMD_TXTHRSHLDCTL);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
+ TULIP_GP_EB_INIT,
+ TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
+ TULIP_GP_EB_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
+ TULIP_GP_EB_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
+}
+
+static const tulip_boardsw_t tulip_21140_eb_boardsw = {
+ TULIP_21140_DEC_EB,
+ tulip_21140_evalboard_media_probe,
+ tulip_media_select,
+ tulip_null_media_poll,
+ tulip_2114x_media_preset,
+};
+
+static void
+tulip_21140_accton_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t *mip = sc->tulip_mediainfo;
+ unsigned gpdata;
+
+ sc->tulip_gpinit = TULIP_GP_EB_PINS;
+ sc->tulip_gpdata = TULIP_GP_EB_INIT;
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
+ TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
+ DELAY(1000000);
+ gpdata = TULIP_CSR_READ(sc, csr_gp);
+ if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) {
+ sc->tulip_media = TULIP_MEDIA_10BASET;
+ } else {
+ if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) {
+ sc->tulip_media = TULIP_MEDIA_BNC;
+ } else {
+ sc->tulip_media = TULIP_MEDIA_100BASETX;
+ }
+ }
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC,
+ TULIP_GP_EN1207_BNC_INIT,
+ TULIP_CMD_TXTHRSHLDCTL);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
+ TULIP_GP_EN1207_UTP_INIT,
+ TULIP_CMD_TXTHRSHLDCTL);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
+ TULIP_GP_EN1207_UTP_INIT,
+ TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
+ TULIP_GP_EN1207_100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
+ TULIP_GP_EN1207_100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
+}
+
+static const tulip_boardsw_t tulip_21140_accton_boardsw = {
+ TULIP_21140_EN1207,
+ tulip_21140_accton_media_probe,
+ tulip_media_select,
+ tulip_null_media_poll,
+ tulip_2114x_media_preset,
+};
+
+static void
+tulip_21140_smc9332_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t *mip = sc->tulip_mediainfo;
+ int idx, cnt = 0;
+
+ TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE);
+ TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at
+ 33MHz that comes to two microseconds but wait a
+ bit longer anyways) */
+ TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT |
+ TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
+ sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS;
+ sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT;
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
+ DELAY(200000);
+ for (idx = 1000; idx > 0; idx--) {
+ u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
+ if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) {
+ if (++cnt > 100)
+ break;
+ } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) {
+ break;
+ } else {
+ cnt = 0;
+ }
+ DELAY(1000);
+ }
+ sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
+ TULIP_GP_SMC_9332_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
+ TULIP_GP_SMC_9332_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
+ TULIP_GP_SMC_9332_INIT,
+ TULIP_CMD_TXTHRSHLDCTL);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
+ TULIP_GP_SMC_9332_INIT,
+ TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
+}
+
+static const tulip_boardsw_t tulip_21140_smc9332_boardsw = {
+ TULIP_21140_SMC_9332,
+ tulip_21140_smc9332_media_probe,
+ tulip_media_select,
+ tulip_null_media_poll,
+ tulip_2114x_media_preset,
+};
+
+static void
+tulip_21140_cogent_em100_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t *mip = sc->tulip_mediainfo;
+ u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command);
+
+ sc->tulip_gpinit = TULIP_GP_EM100_PINS;
+ sc->tulip_gpdata = TULIP_GP_EM100_INIT;
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
+
+ cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE;
+ cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER);
+ if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
+ TULIP_CSR_WRITE(sc, csr_command, cmdmode);
+ sc->tulip_media = TULIP_MEDIA_100BASEFX;
+
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX,
+ TULIP_GP_EM100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD,
+ TULIP_GP_EM100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_FULLDUPLEX);
+ } else {
+ TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER);
+ sc->tulip_media = TULIP_MEDIA_100BASETX;
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
+ TULIP_GP_EM100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
+ TULIP_GP_EM100_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
+ }
+}
+
+static const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = {
+ TULIP_21140_COGENT_EM100,
+ tulip_21140_cogent_em100_media_probe,
+ tulip_media_select,
+ tulip_null_media_poll,
+ tulip_2114x_media_preset
+};
+
+static void
+tulip_21140_znyx_zx34x_media_probe(
+ tulip_softc_t * const sc)
+{
+ tulip_media_info_t *mip = sc->tulip_mediainfo;
+ int cnt10 = 0, cnt100 = 0, idx;
+
+ sc->tulip_gpinit = TULIP_GP_ZX34X_PINS;
+ sc->tulip_gpdata = TULIP_GP_ZX34X_INIT;
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
+ TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
+ TULIP_CSR_WRITE(sc, csr_command,
+ TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
+
+ DELAY(200000);
+ for (idx = 1000; idx > 0; idx--) {
+ u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
+ if ((csr & (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) == (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) {
+ if (++cnt100 > 100)
+ break;
+ } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) {
+ if (++cnt10 > 100)
+ break;
+ } else {
+ cnt10 = 0;
+ cnt100 = 0;
+ }
+ DELAY(1000);
+ }
+ sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
+ TULIP_GP_ZX34X_INIT,
+ TULIP_CMD_TXTHRSHLDCTL);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
+ TULIP_GP_ZX34X_INIT,
+ TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
+ TULIP_GP_ZX34X_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER);
+ tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
+ TULIP_GP_ZX34X_INIT,
+ TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
+ |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
+}
+
+static const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = {
+ TULIP_21140_ZNYX_ZX34X,
+ tulip_21140_znyx_zx34x_media_probe,
+ tulip_media_select,
+ tulip_null_media_poll,
+ tulip_2114x_media_preset,
+};
+
+static void
+tulip_2114x_media_probe(
+ tulip_softc_t * const sc)
+{
+ sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE
+ |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72;
+}
+
+static const tulip_boardsw_t tulip_2114x_isv_boardsw = {
+ TULIP_21140_ISV,
+ tulip_2114x_media_probe,
+ tulip_media_select,
+ tulip_media_poll,
+ tulip_2114x_media_preset,
+};
+
+/*
+ * ******** END of chip-specific handlers. ***********
+ */
+
+/*
+ * Code the read the SROM and MII bit streams (I2C)
+ */
+#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
+
+static void
+tulip_srom_idle(
+ tulip_softc_t * const sc)
+{
+ unsigned bit, csr;
+
+ csr = SROMSEL ; EMIT;
+ csr = SROMSEL | SROMRD; EMIT;
+ csr ^= SROMCS; EMIT;
+ csr ^= SROMCLKON; EMIT;
+
+ /*
+ * Write 25 cycles of 0 which will force the SROM to be idle.
+ */
+ for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
+ csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
+ csr ^= SROMCLKON; EMIT; /* clock high; data valid */
+ }
+ csr ^= SROMCLKOFF; EMIT;
+ csr ^= SROMCS; EMIT;
+ csr = 0; EMIT;
+}
+
+
+static void
+tulip_srom_read(
+ tulip_softc_t * const sc)
+{
+ unsigned idx;
+ const unsigned bitwidth = SROM_BITWIDTH;
+ const unsigned cmdmask = (SROMCMD_RD << bitwidth);
+ const unsigned msb = 1 << (bitwidth + 3 - 1);
+ unsigned lastidx = (1 << bitwidth) - 1;
+
+ tulip_srom_idle(sc);
+
+ for (idx = 0; idx <= lastidx; idx++) {
+ unsigned lastbit, data, bits, bit, csr;
+ csr = SROMSEL ; EMIT;
+ csr = SROMSEL | SROMRD; EMIT;
+ csr ^= SROMCSON; EMIT;
+ csr ^= SROMCLKON; EMIT;
+
+ lastbit = 0;
+ for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) {
+ const unsigned thisbit = bits & msb;
+ csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
+ if (thisbit != lastbit) {
+ csr ^= SROMDOUT; EMIT; /* clock low; invert data */
+ } else {
+ EMIT;
+ }
+ csr ^= SROMCLKON; EMIT; /* clock high; data valid */
+ lastbit = thisbit;
+ }
+ csr ^= SROMCLKOFF; EMIT;
+
+ for (data = 0, bits = 0; bits < 16; bits++) {
+ data <<= 1;
+ csr ^= SROMCLKON; EMIT; /* clock high; data valid */
+ data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
+ csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
+ }
+ sc->tulip_rombuf[idx*2] = data & 0xFF;
+ sc->tulip_rombuf[idx*2+1] = data >> 8;
+ csr = SROMSEL | SROMRD; EMIT;
+ csr = 0; EMIT;
+ }
+ tulip_srom_idle(sc);
+}
+
+#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
+
+static void
+tulip_mii_writebits(
+ tulip_softc_t * const sc,
+ unsigned data,
+ unsigned bits)
+{
+ unsigned msb = 1 << (bits - 1);
+ unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
+ unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
+
+ csr |= MII_WR; MII_EMIT; /* clock low; assert write */
+
+ for (; bits > 0; bits--, data <<= 1) {
+ const unsigned thisbit = data & msb;
+ if (thisbit != lastbit) {
+ csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */
+ }
+ csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
+ lastbit = thisbit;
+ csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
+ }
+}
+
+static void
+tulip_mii_turnaround(
+ tulip_softc_t * const sc,
+ unsigned cmd)
+{
+ unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
+
+ if (cmd == MII_WRCMD) {
+ csr |= MII_DOUT; MII_EMIT; /* clock low; change data */
+ csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
+ csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
+ csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */
+ } else {
+ csr |= MII_RD; MII_EMIT; /* clock low; switch to read */
+ }
+ csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
+ csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
+}
+
+static unsigned
+tulip_mii_readbits(
+ tulip_softc_t * const sc)
+{
+ unsigned data;
+ unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
+ int idx;
+
+ for (idx = 0, data = 0; idx < 16; idx++) {
+ data <<= 1; /* this is NOOP on the first pass through */
+ csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
+ if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN)
+ data |= 1;
+ csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
+ }
+ csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */
+
+ return data;
+}
+
+static unsigned
+tulip_mii_readreg(
+ tulip_softc_t * const sc,
+ unsigned devaddr,
+ unsigned regno)
+{
+ unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
+ unsigned data;
+
+ csr &= ~(MII_RD|MII_CLK); MII_EMIT;
+ tulip_mii_writebits(sc, MII_PREAMBLE, 32);
+ tulip_mii_writebits(sc, MII_RDCMD, 8);
+ tulip_mii_writebits(sc, devaddr, 5);
+ tulip_mii_writebits(sc, regno, 5);
+ tulip_mii_turnaround(sc, MII_RDCMD);
+
+ data = tulip_mii_readbits(sc);
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_phyregs[regno][0] = data;
+ sc->tulip_dbg.dbg_phyregs[regno][1]++;
+#endif
+ return data;
+}
+
+static void
+tulip_mii_writereg(
+ tulip_softc_t * const sc,
+ unsigned devaddr,
+ unsigned regno,
+ unsigned data)
+{
+ unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
+ csr &= ~(MII_RD|MII_CLK); MII_EMIT;
+ tulip_mii_writebits(sc, MII_PREAMBLE, 32);
+ tulip_mii_writebits(sc, MII_WRCMD, 8);
+ tulip_mii_writebits(sc, devaddr, 5);
+ tulip_mii_writebits(sc, regno, 5);
+ tulip_mii_turnaround(sc, MII_WRCMD);
+ tulip_mii_writebits(sc, data, 16);
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_phyregs[regno][2] = data;
+ sc->tulip_dbg.dbg_phyregs[regno][3]++;
+#endif
+}
+
+#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF)
+#define tulip_srom_crcok(databuf) ( \
+ ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \
+ ((databuf)[126] | ((databuf)[127] << 8)))
+
+static unsigned
+tulip_crc32(
+ const unsigned char *databuf,
+ size_t datalen)
+{
+ u_int idx, crc = 0xFFFFFFFFUL;
+ static const u_int crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+
+ for (idx = 0; idx < datalen; idx++) {
+ crc ^= *databuf++;
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+ return crc;
+}
+
+static void
+tulip_identify_dec_nic(
+ tulip_softc_t * const sc)
+{
+ strcpy(sc->tulip_boardid, "DEC ");
+#define D0 4
+ if (sc->tulip_chipid <= TULIP_21040)
+ return;
+ if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0
+ || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) {
+ bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8);
+ sc->tulip_boardid[D0+8] = ' ';
+ }
+#undef D0
+}
+
+static void
+tulip_identify_znyx_nic(
+ tulip_softc_t * const sc)
+{
+ unsigned id = 0;
+ strcpy(sc->tulip_boardid, "ZNYX ZX3XX ");
+ if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
+ unsigned znyx_ptr;
+ sc->tulip_boardid[8] = '4';
+ znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125];
+ if (znyx_ptr < 26 || znyx_ptr > 116) {
+ sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
+ return;
+ }
+ /* ZX344 = 0010 .. 0013FF
+ */
+ if (sc->tulip_rombuf[znyx_ptr] == 0x4A
+ && sc->tulip_rombuf[znyx_ptr + 1] == 0x52
+ && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) {
+ id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4];
+ if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) {
+ sc->tulip_boardid[9] = '2';
+ if (id == TULIP_ZNYX_ID_ZX342B) {
+ sc->tulip_boardid[10] = 'B';
+ sc->tulip_boardid[11] = ' ';
+ }
+ sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
+ } else if (id == TULIP_ZNYX_ID_ZX344) {
+ sc->tulip_boardid[10] = '4';
+ sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
+ } else if (id == TULIP_ZNYX_ID_ZX345) {
+ sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5';
+ } else if (id == TULIP_ZNYX_ID_ZX346) {
+ sc->tulip_boardid[9] = '6';
+ } else if (id == TULIP_ZNYX_ID_ZX351) {
+ sc->tulip_boardid[8] = '5';
+ sc->tulip_boardid[9] = '1';
+ }
+ }
+ if (id == 0) {
+ /*
+ * Assume it's a ZX342...
+ */
+ sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
+ }
+ return;
+ }
+ sc->tulip_boardid[8] = '1';
+ if (sc->tulip_chipid == TULIP_21041) {
+ sc->tulip_boardid[10] = '1';
+ return;
+ }
+ if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) {
+ id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36];
+ if (id == TULIP_ZNYX_ID_ZX312T) {
+ sc->tulip_boardid[9] = '2';
+ sc->tulip_boardid[10] = 'T';
+ sc->tulip_boardid[11] = ' ';
+ sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
+ } else if (id == TULIP_ZNYX_ID_ZX314_INTA) {
+ sc->tulip_boardid[9] = '4';
+ sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
+ } else if (id == TULIP_ZNYX_ID_ZX314) {
+ sc->tulip_boardid[9] = '4';
+ sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
+ sc->tulip_features |= TULIP_HAVE_BASEROM;
+ } else if (id == TULIP_ZNYX_ID_ZX315_INTA) {
+ sc->tulip_boardid[9] = '5';
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
+ } else if (id == TULIP_ZNYX_ID_ZX315) {
+ sc->tulip_boardid[9] = '5';
+ sc->tulip_features |= TULIP_HAVE_BASEROM;
+ } else {
+ id = 0;
+ }
+ }
+ if (id == 0) {
+ if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) {
+ sc->tulip_boardid[9] = '4';
+ sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
+ } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) {
+ sc->tulip_boardid[9] = '5';
+ sc->tulip_boardsw = &tulip_21040_boardsw;
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
+ } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) {
+ sc->tulip_boardid[9] = '2';
+ sc->tulip_boardsw = &tulip_21040_boardsw;
+ }
+ }
+}
+
+static void
+tulip_identify_smc_nic(
+ tulip_softc_t * const sc)
+{
+ u_int32_t id1, id2, ei;
+ int auibnc = 0, utp = 0;
+ char *cp;
+
+ strcpy(sc->tulip_boardid, "SMC ");
+ if (sc->tulip_chipid == TULIP_21041)
+ return;
+ if (sc->tulip_chipid != TULIP_21040) {
+ if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
+ strcpy(&sc->tulip_boardid[4], "9332DST ");
+ sc->tulip_boardsw = &tulip_21140_smc9332_boardsw;
+ } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) {
+ strcpy(&sc->tulip_boardid[4], "9334BDT ");
+ } else {
+ strcpy(&sc->tulip_boardid[4], "9332BDT ");
+ }
+ return;
+ }
+ id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8);
+ id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8);
+ ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8);
+
+ strcpy(&sc->tulip_boardid[4], "8432");
+ cp = &sc->tulip_boardid[8];
+ if ((id1 & 1) == 0)
+ *cp++ = 'B', auibnc = 1;
+ if ((id1 & 0xFF) > 0x32)
+ *cp++ = 'T', utp = 1;
+ if ((id1 & 0x4000) == 0)
+ *cp++ = 'A', auibnc = 1;
+ if (id2 == 0x15) {
+ sc->tulip_boardid[7] = '4';
+ *cp++ = '-';
+ *cp++ = 'C';
+ *cp++ = 'H';
+ *cp++ = (ei ? '2' : '1');
+ }
+ *cp++ = ' ';
+ *cp = '\0';
+ if (utp && !auibnc)
+ sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
+ else if (!utp && auibnc)
+ sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw;
+}
+
+static void
+tulip_identify_cogent_nic(
+ tulip_softc_t * const sc)
+{
+ strcpy(sc->tulip_boardid, "Cogent ");
+ if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
+ if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) {
+ strcat(sc->tulip_boardid, "EM100TX ");
+ sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
+#if defined(TULIP_COGENT_EM110TX_ID)
+ } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) {
+ strcat(sc->tulip_boardid, "EM110TX ");
+ sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
+#endif
+ } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
+ strcat(sc->tulip_boardid, "EM100FX ");
+ sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
+ }
+ /*
+ * Magic number (0x24001109U) is the SubVendor (0x2400) and
+ * SubDevId (0x1109) for the ANA6944TX (EM440TX).
+ */
+ if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U
+ && (sc->tulip_features & TULIP_HAVE_BASEROM)) {
+ /*
+ * Cogent (Adaptec) is still mapping all INTs to INTA of
+ * first 21140. Dumb! Dumb!
+ */
+ strcat(sc->tulip_boardid, "EM440TX ");
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
+ }
+ } else if (sc->tulip_chipid == TULIP_21040) {
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
+ }
+}
+
+static void
+tulip_identify_accton_nic(
+ tulip_softc_t * const sc)
+{
+ strcpy(sc->tulip_boardid, "ACCTON ");
+ switch (sc->tulip_chipid) {
+ case TULIP_21140A:
+ strcat(sc->tulip_boardid, "EN1207 ");
+ if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
+ sc->tulip_boardsw = &tulip_21140_accton_boardsw;
+ break;
+ case TULIP_21140:
+ strcat(sc->tulip_boardid, "EN1207TX ");
+ if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
+ sc->tulip_boardsw = &tulip_21140_eb_boardsw;
+ break;
+ case TULIP_21040:
+ strcat(sc->tulip_boardid, "EN1203 ");
+ sc->tulip_boardsw = &tulip_21040_boardsw;
+ break;
+ case TULIP_21041:
+ strcat(sc->tulip_boardid, "EN1203 ");
+ sc->tulip_boardsw = &tulip_21041_boardsw;
+ break;
+ default:
+ sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
+ break;
+ }
+}
+
+static void
+tulip_identify_asante_nic(
+ tulip_softc_t * const sc)
+{
+ strcpy(sc->tulip_boardid, "Asante ");
+ if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A)
+ && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
+ tulip_media_info_t *mi = sc->tulip_mediainfo;
+ int idx;
+ /*
+ * The Asante Fast Ethernet doesn't always ship with a valid
+ * new format SROM. So if isn't in the new format, we cheat
+ * set it up as if we had.
+ */
+
+ sc->tulip_gpinit = TULIP_GP_ASANTE_PINS;
+ sc->tulip_gpdata = 0;
+
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET);
+ TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET);
+ DELAY(100);
+ TULIP_CSR_WRITE(sc, csr_gp, 0);
+
+ mi->mi_type = TULIP_MEDIAINFO_MII;
+ mi->mi_gpr_length = 0;
+ mi->mi_gpr_offset = 0;
+ mi->mi_reset_length = 0;
+ mi->mi_reset_offset = 0;;
+
+ mi->mi_phyaddr = TULIP_MII_NOPHY;
+ for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) {
+ DELAY(10000);
+ mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0);
+ }
+ if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
+ printf("%s%d: can't find phy 0\n", sc->tulip_name, sc->tulip_unit);
+ return;
+ }
+
+ sc->tulip_features |= TULIP_HAVE_MII;
+ mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
+ mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
+ mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD;
+ mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD;
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
+ mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
+ tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
+
+ sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
+ }
+}
+
+static void
+tulip_identify_compex_nic(
+ tulip_softc_t * const sc)
+{
+ strcpy(sc->tulip_boardid, "COMPEX ");
+ if (sc->tulip_chipid == TULIP_21140A) {
+ int root_unit;
+ tulip_softc_t *root_sc = NULL;
+
+ strcat(sc->tulip_boardid, "400TX/PCI ");
+ /*
+ * All 4 chips on these boards share an interrupt. This code
+ * copied from tulip_read_macaddr.
+ */
+ sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
+ for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
+ root_sc = tulips[root_unit];
+ if (root_sc == NULL
+ || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR))
+ break;
+ root_sc = NULL;
+ }
+ if (root_sc != NULL
+ && root_sc->tulip_chipid == sc->tulip_chipid
+ && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
+ sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
+ sc->tulip_slaves = root_sc->tulip_slaves;
+ root_sc->tulip_slaves = sc;
+ } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) {
+ printf("\nCannot find master device for de%d interrupts",
+ sc->tulip_unit);
+ }
+ } else {
+ strcat(sc->tulip_boardid, "unknown ");
+ }
+ /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */
+ return;
+}
+
+static int
+tulip_srom_decode(
+ tulip_softc_t * const sc)
+{
+ unsigned idx1, idx2, idx3;
+
+ const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0];
+ const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1);
+ tulip_srom_media_t srom_media;
+ tulip_media_info_t *mi = sc->tulip_mediainfo;
+ const u_int8_t *dp;
+ u_int32_t leaf_offset, blocks, data;
+
+ for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) {
+ if (shp->sh_adapter_count == 1)
+ break;
+ if (saip->sai_device == sc->tulip_pci_devno)
+ break;
+ }
+ /*
+ * Didn't find the right media block for this card.
+ */
+ if (idx1 == shp->sh_adapter_count)
+ return 0;
+
+ /*
+ * Save the hardware address.
+ */
+ bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6);
+ /*
+ * If this is a multiple port card, add the adapter index to the last
+ * byte of the hardware address. (if it isn't multiport, adding 0
+ * won't hurt.
+ */
+ sc->tulip_enaddr[5] += idx1;
+
+ leaf_offset = saip->sai_leaf_offset_lowbyte
+ + saip->sai_leaf_offset_highbyte * 256;
+ dp = sc->tulip_rombuf + leaf_offset;
+
+ sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2;
+
+ for (idx2 = 0;; idx2++) {
+ if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype
+ || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED)
+ break;
+ }
+ sc->tulip_connidx = idx2;
+
+ if (sc->tulip_chipid == TULIP_21041) {
+ blocks = *dp++;
+ for (idx2 = 0; idx2 < blocks; idx2++) {
+ tulip_media_t media;
+ data = *dp++;
+ srom_media = (tulip_srom_media_t) (data & 0x3F);
+ for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
+ if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
+ break;
+ }
+ media = tulip_srom_mediums[idx3].sm_type;
+ if (media != TULIP_MEDIA_UNKNOWN) {
+ if (data & TULIP_SROM_21041_EXTENDED) {
+ mi->mi_type = TULIP_MEDIAINFO_SIA;
+ sc->tulip_mediums[media] = mi;
+ mi->mi_sia_connectivity = dp[0] + dp[1] * 256;
+ mi->mi_sia_tx_rx = dp[2] + dp[3] * 256;
+ mi->mi_sia_general = dp[4] + dp[5] * 256;
+ mi++;
+ } else {
+ switch (media) {
+ case TULIP_MEDIA_BNC: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC);
+ mi++;
+ break;
+ }
+ case TULIP_MEDIA_AUI: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI);
+ mi++;
+ break;
+ }
+ case TULIP_MEDIA_10BASET: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET);
+ mi++;
+ break;
+ }
+ case TULIP_MEDIA_10BASET_FD: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD);
+ mi++;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+ if (data & TULIP_SROM_21041_EXTENDED)
+ dp += 6;
+ }
+#ifdef notdef
+ if (blocks == 0) {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++;
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++;
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++;
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++;
+ }
+#endif
+ } else {
+ unsigned length, type;
+ tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN;
+ if (sc->tulip_features & TULIP_HAVE_GPR)
+ sc->tulip_gpinit = *dp++;
+ blocks = *dp++;
+ for (idx2 = 0; idx2 < blocks; idx2++) {
+ const u_int8_t *ep;
+ if ((*dp & 0x80) == 0) {
+ length = 4;
+ type = 0;
+ } else {
+ length = (*dp++ & 0x7f) - 1;
+ type = *dp++ & 0x3f;
+ }
+ ep = dp + length;
+ switch (type & 0x3f) {
+ case 0: { /* 21140[A] GPR block */
+ tulip_media_t media;
+ srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
+ for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
+ if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
+ break;
+ }
+ media = tulip_srom_mediums[idx3].sm_type;
+ if (media == TULIP_MEDIA_UNKNOWN)
+ break;
+ mi->mi_type = TULIP_MEDIAINFO_GPR;
+ sc->tulip_mediums[media] = mi;
+ mi->mi_gpdata = dp[1];
+ if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) {
+ sc->tulip_gpdata = mi->mi_gpdata;
+ gp_media = media;
+ }
+ data = dp[2] + dp[3] * 256;
+ mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
+ if (data & TULIP_SROM_2114X_NOINDICATOR) {
+ mi->mi_actmask = 0;
+ } else {
+#if 0
+ mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
+#endif
+ mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
+ mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
+ }
+ mi++;
+ break;
+ }
+ case 1: { /* 21140[A] MII block */
+ const unsigned phyno = *dp++;
+ mi->mi_type = TULIP_MEDIAINFO_MII;
+ mi->mi_gpr_length = *dp++;
+ mi->mi_gpr_offset = dp - sc->tulip_rombuf;
+ dp += mi->mi_gpr_length;
+ mi->mi_reset_length = *dp++;
+ mi->mi_reset_offset = dp - sc->tulip_rombuf;
+ dp += mi->mi_reset_length;
+
+ /*
+ * Before we probe for a PHY, use the GPR information
+ * to select it. If we don't, it may be inaccessible.
+ */
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET);
+ for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]);
+ }
+ sc->tulip_phyaddr = mi->mi_phyaddr;
+ for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]);
+ }
+
+ /*
+ * At least write something!
+ */
+ if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
+ TULIP_CSR_WRITE(sc, csr_gp, 0);
+
+ mi->mi_phyaddr = TULIP_MII_NOPHY;
+ for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
+ DELAY(10000);
+ mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
+ }
+ if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
+#if defined(TULIP_DEBUG)
+ printf("%s%d: can't find phy %d\n",
+ sc->tulip_name, sc->tulip_unit, phyno);
+#endif
+ break;
+ }
+ sc->tulip_features |= TULIP_HAVE_MII;
+ mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2;
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
+ mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
+ tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
+ mi++;
+ break;
+ }
+ case 2: { /* 2114[23] SIA block */
+ tulip_media_t media;
+ srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
+ for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
+ if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
+ break;
+ }
+ media = tulip_srom_mediums[idx3].sm_type;
+ if (media == TULIP_MEDIA_UNKNOWN)
+ break;
+ mi->mi_type = TULIP_MEDIAINFO_SIA;
+ sc->tulip_mediums[media] = mi;
+ if (dp[0] & 0x40) {
+ mi->mi_sia_connectivity = dp[1] + dp[2] * 256;
+ mi->mi_sia_tx_rx = dp[3] + dp[4] * 256;
+ mi->mi_sia_general = dp[5] + dp[6] * 256;
+ dp += 6;
+ } else {
+ switch (media) {
+ case TULIP_MEDIA_BNC: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC);
+ break;
+ }
+ case TULIP_MEDIA_AUI: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI);
+ break;
+ }
+ case TULIP_MEDIA_10BASET: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET);
+ sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
+ break;
+ }
+ case TULIP_MEDIA_10BASET_FD: {
+ TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD);
+ sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
+ break;
+ }
+ default: {
+ goto bad_media;
+ }
+ }
+ }
+ mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16;
+ mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16;
+ mi++;
+ bad_media:
+ break;
+ }
+ case 3: { /* 2114[23] MII PHY block */
+ const unsigned phyno = *dp++;
+ const u_int8_t *dp0;
+ mi->mi_type = TULIP_MEDIAINFO_MII;
+ mi->mi_gpr_length = *dp++;
+ mi->mi_gpr_offset = dp - sc->tulip_rombuf;
+ dp += 2 * mi->mi_gpr_length;
+ mi->mi_reset_length = *dp++;
+ mi->mi_reset_offset = dp - sc->tulip_rombuf;
+ dp += 2 * mi->mi_reset_length;
+
+ dp0 = &sc->tulip_rombuf[mi->mi_reset_offset];
+ for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
+ }
+ sc->tulip_phyaddr = mi->mi_phyaddr;
+ dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset];
+ for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) {
+ DELAY(10);
+ TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
+ }
+
+ if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
+ TULIP_CSR_WRITE(sc, csr_sia_general, 0);
+
+ mi->mi_phyaddr = TULIP_MII_NOPHY;
+ for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
+ DELAY(10000);
+ mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
+ }
+ if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
+#if defined(TULIP_DEBUG)
+ printf("%s%d: can't find phy %d\n",
+ sc->tulip_name, sc->tulip_unit, phyno);
+#endif
+ break;
+ }
+ sc->tulip_features |= TULIP_HAVE_MII;
+ mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2;
+ mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2;
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
+ TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
+ mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
+ tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
+ mi++;
+ break;
+ }
+ case 4: { /* 21143 SYM block */
+ tulip_media_t media;
+ srom_media = (tulip_srom_media_t) dp[0];
+ for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
+ if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
+ break;
+ }
+ media = tulip_srom_mediums[idx3].sm_type;
+ if (media == TULIP_MEDIA_UNKNOWN)
+ break;
+ mi->mi_type = TULIP_MEDIAINFO_SYM;
+ sc->tulip_mediums[media] = mi;
+ mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16;
+ mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16;
+ data = dp[5] + dp[6] * 256;
+ mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
+ if (data & TULIP_SROM_2114X_NOINDICATOR) {
+ mi->mi_actmask = 0;
+ } else {
+ mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
+ mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
+ mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
+ }
+ if (TULIP_IS_MEDIA_TP(media))
+ sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
+ mi++;
+ break;
+ }
+#if 0
+ case 5: { /* 21143 Reset block */
+ mi->mi_type = TULIP_MEDIAINFO_RESET;
+ mi->mi_reset_length = *dp++;
+ mi->mi_reset_offset = dp - sc->tulip_rombuf;
+ dp += 2 * mi->mi_reset_length;
+ mi++;
+ break;
+ }
+#endif
+ default: {
+ }
+ }
+ dp = ep;
+ }
+ }
+ return mi - sc->tulip_mediainfo;
+}
+
+static const struct {
+ void (*vendor_identify_nic)(tulip_softc_t * const sc);
+ unsigned char vendor_oui[3];
+} tulip_vendors[] = {
+ { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } },
+ { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } },
+ { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } },
+ { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } },
+ { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } },
+ { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } },
+ { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } },
+ { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } },
+ { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } },
+ { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } },
+ { NULL }
+};
+
+/*
+ * This deals with the vagaries of the address roms and the
+ * brain-deadness that various vendors commit in using them.
+ */
+static int
+tulip_read_macaddr(
+ tulip_softc_t * const sc)
+{
+ unsigned cksum, rom_cksum, idx;
+ u_int32_t csr;
+ unsigned char tmpbuf[8];
+ static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
+
+ sc->tulip_connidx = TULIP_SROM_LASTCONNIDX;
+
+ if (sc->tulip_chipid == TULIP_21040) {
+ TULIP_CSR_WRITE(sc, csr_enetrom, 1);
+ for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
+ int cnt = 0;
+ while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000)
+ cnt++;
+ sc->tulip_rombuf[idx] = csr & 0xFF;
+ }
+ sc->tulip_boardsw = &tulip_21040_boardsw;
+ } else {
+ if (sc->tulip_chipid == TULIP_21041) {
+ /*
+ * Thankfully all 21041's act the same.
+ */
+ sc->tulip_boardsw = &tulip_21041_boardsw;
+ } else {
+ /*
+ * Assume all 21140 board are compatible with the
+ * DEC 10/100 evaluation board. Not really valid but
+ * it's the best we can do until every one switches to
+ * the new SROM format.
+ */
+
+ sc->tulip_boardsw = &tulip_21140_eb_boardsw;
+ }
+ tulip_srom_read(sc);
+ if (tulip_srom_crcok(sc->tulip_rombuf)) {
+ /*
+ * SROM CRC is valid therefore it must be in the
+ * new format.
+ */
+ sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM;
+ } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) {
+ /*
+ * No checksum is present. See if the SROM id checks out;
+ * the first 18 bytes should be 0 followed by a 1 followed
+ * by the number of adapters (which we don't deal with yet).
+ */
+ for (idx = 0; idx < 18; idx++) {
+ if (sc->tulip_rombuf[idx] != 0)
+ break;
+ }
+ if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0)
+ sc->tulip_features |= TULIP_HAVE_ISVSROM;
+ } else if (sc->tulip_chipid >= TULIP_21142) {
+ sc->tulip_features |= TULIP_HAVE_ISVSROM;
+ sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
+ }
+ if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) {
+ if (sc->tulip_chipid != TULIP_21041)
+ sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
+
+ /*
+ * If the SROM specifies more than one adapter, tag this as a
+ * BASE rom.
+ */
+ if (sc->tulip_rombuf[19] > 1)
+ sc->tulip_features |= TULIP_HAVE_BASEROM;
+ if (sc->tulip_boardsw == NULL)
+ return -6;
+ goto check_oui;
+ }
+ }
+
+
+ if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) {
+ /*
+ * Some folks don't use the standard ethernet rom format
+ * but instead just put the address in the first 6 bytes
+ * of the rom and let the rest be all 0xffs. (Can we say
+ * ZNYX?) (well sometimes they put in a checksum so we'll
+ * start at 8).
+ */
+ for (idx = 8; idx < 32; idx++) {
+ if (sc->tulip_rombuf[idx] != 0xFF)
+ return -4;
+ }
+ /*
+ * Make sure the address is not multicast or locally assigned
+ * that the OUI is not 00-00-00.
+ */
+ if ((sc->tulip_rombuf[0] & 3) != 0)
+ return -4;
+ if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0
+ && sc->tulip_rombuf[2] == 0)
+ return -4;
+ bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
+ sc->tulip_features |= TULIP_HAVE_OKROM;
+ goto check_oui;
+ } else {
+ /*
+ * A number of makers of multiport boards (ZNYX and Cogent)
+ * only put on one address ROM on their 21040 boards. So
+ * if the ROM is all zeros (or all 0xFFs), look at the
+ * previous configured boards (as long as they are on the same
+ * PCI bus and the bus number is non-zero) until we find the
+ * master board with address ROM. We then use its address ROM
+ * as the base for this board. (we add our relative board
+ * to the last byte of its address).
+ */
+ for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
+ if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF)
+ break;
+ }
+ if (idx == sizeof(sc->tulip_rombuf)) {
+ int root_unit;
+ tulip_softc_t *root_sc = NULL;
+ for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
+ root_sc = tulips[root_unit];
+ if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM)
+ break;
+ root_sc = NULL;
+ }
+ if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM)
+ && root_sc->tulip_chipid == sc->tulip_chipid
+ && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
+ sc->tulip_features |= TULIP_HAVE_SLAVEDROM;
+ sc->tulip_boardsw = root_sc->tulip_boardsw;
+ strcpy(sc->tulip_boardid, root_sc->tulip_boardid);
+ if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) {
+ bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf,
+ sizeof(sc->tulip_rombuf));
+ if (!tulip_srom_decode(sc))
+ return -5;
+ } else {
+ bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6);
+ sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit;
+ }
+ /*
+ * Now for a truly disgusting kludge: all 4 21040s on
+ * the ZX314 share the same INTA line so the mapping
+ * setup by the BIOS on the PCI bridge is worthless.
+ * Rather than reprogramming the value in the config
+ * register, we will handle this internally.
+ */
+ if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) {
+ sc->tulip_slaves = root_sc->tulip_slaves;
+ root_sc->tulip_slaves = sc;
+ sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
+ }
+ return 0;
+ }
+ }
+ }
+
+ /*
+ * This is the standard DEC address ROM test.
+ */
+
+ if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0)
+ return -3;
+
+ tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14];
+ tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12];
+ tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10];
+ tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8];
+ if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0)
+ return -2;
+
+ bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
+
+ cksum = *(u_int16_t *) &sc->tulip_enaddr[0];
+ cksum *= 2;
+ if (cksum > 65535) cksum -= 65535;
+ cksum += *(u_int16_t *) &sc->tulip_enaddr[2];
+ if (cksum > 65535) cksum -= 65535;
+ cksum *= 2;
+ if (cksum > 65535) cksum -= 65535;
+ cksum += *(u_int16_t *) &sc->tulip_enaddr[4];
+ if (cksum >= 65535) cksum -= 65535;
+
+ rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6];
+
+ if (cksum != rom_cksum)
+ return -1;
+
+ check_oui:
+ /*
+ * Check for various boards based on OUI. Did I say braindead?
+ */
+ for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) {
+ if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) {
+ (*tulip_vendors[idx].vendor_identify_nic)(sc);
+ break;
+ }
+ }
+
+ sc->tulip_features |= TULIP_HAVE_OKROM;
+ return 0;
+}
+
+static void
+tulip_ifmedia_add(
+ tulip_softc_t * const sc)
+{
+ tulip_media_t media;
+ int medias = 0;
+
+ for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
+ if (sc->tulip_mediums[media] != NULL) {
+ ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media],
+ 0, 0);
+ medias++;
+ }
+ }
+ if (medias == 0) {
+ sc->tulip_features |= TULIP_HAVE_NOMEDIA;
+ ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0);
+ ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE);
+ } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
+ ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
+ ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO);
+ } else {
+ ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]);
+ sc->tulip_flags |= TULIP_PRINTMEDIA;
+ tulip_linkup(sc, sc->tulip_media);
+ }
+}
+
+static int
+tulip_ifmedia_change(
+ struct ifnet * const ifp)
+{
+ tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
+
+ sc->tulip_flags |= TULIP_NEEDRESET;
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ sc->tulip_media = TULIP_MEDIA_UNKNOWN;
+ if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) {
+ tulip_media_t media;
+ for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
+ if (sc->tulip_mediums[media] != NULL
+ && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) {
+ sc->tulip_flags |= TULIP_PRINTMEDIA;
+ sc->tulip_flags &= ~TULIP_DIDNWAY;
+ tulip_linkup(sc, media);
+ return 0;
+ }
+ }
+ }
+ sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT);
+ tulip_reset(sc);
+ tulip_init(sc);
+ return 0;
+}
+
+/*
+ * Media status callback
+ */
+static void
+tulip_ifmedia_status(
+ struct ifnet * const ifp,
+ struct ifmediareq *req)
+{
+ tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc;
+
+ if (sc->tulip_media == TULIP_MEDIA_UNKNOWN)
+ return;
+
+ req->ifm_status = IFM_AVALID;
+ if (sc->tulip_flags & TULIP_LINKUP)
+ req->ifm_status |= IFM_ACTIVE;
+
+ req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media];
+}
+
+static void
+tulip_addr_filter(
+ tulip_softc_t * const sc)
+{
+ struct ifmultiaddr *ifma;
+ u_char *addrp;
+ int multicnt;
+
+ sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI);
+ sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART;
+ sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
+ sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
+#if defined(IFF_ALLMULTI)
+ if (sc->tulip_if.if_flags & IFF_ALLMULTI)
+ sc->tulip_flags |= TULIP_ALLMULTI ;
+#endif
+
+ multicnt = 0;
+ TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
+
+ if (ifma->ifma_addr->sa_family == AF_LINK)
+ multicnt++;
+ }
+
+ sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */
+ if (multicnt > 14) {
+ u_int32_t *sp = sc->tulip_setupdata;
+ unsigned hash;
+ /*
+ * Some early passes of the 21140 have broken implementations of
+ * hash-perfect mode. When we get too many multicasts for perfect
+ * filtering with these chips, we need to switch into hash-only
+ * mode (this is better than all-multicast on network with lots
+ * of multicast traffic).
+ */
+ if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH)
+ sc->tulip_flags |= TULIP_WANTHASHONLY;
+ else
+ sc->tulip_flags |= TULIP_WANTHASHPERFECT;
+ /*
+ * If we have more than 14 multicasts, we have
+ * go into hash perfect mode (512 bit multicast
+ * hash and one perfect hardware).
+ */
+ bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata));
+
+ TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
+
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+#if BYTE_ORDER == BIG_ENDIAN
+ sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
+#else
+ sp[hash >> 4] |= 1 << (hash & 0xF);
+#endif
+ }
+ /*
+ * No reason to use a hash if we are going to be
+ * receiving every multicast.
+ */
+ if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
+ hash = tulip_mchash(etherbroadcastaddr);
+#if BYTE_ORDER == BIG_ENDIAN
+ sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
+#else
+ sp[hash >> 4] |= 1 << (hash & 0xF);
+#endif
+ if (sc->tulip_flags & TULIP_WANTHASHONLY) {
+ hash = tulip_mchash(sc->tulip_enaddr);
+#if BYTE_ORDER == BIG_ENDIAN
+ sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
+#else
+ sp[hash >> 4] |= 1 << (hash & 0xF);
+#endif
+ } else {
+#if BYTE_ORDER == BIG_ENDIAN
+ sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0] << 16;
+ sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1] << 16;
+ sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2] << 16;
+#else
+ sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0];
+ sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1];
+ sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2];
+#endif
+ }
+ }
+ }
+ if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) {
+ u_int32_t *sp = sc->tulip_setupdata;
+ int idx = 0;
+ if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
+ /*
+ * Else can get perfect filtering for 16 addresses.
+ */
+ TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+#if BYTE_ORDER == BIG_ENDIAN
+ *sp++ = ((u_int16_t *) addrp)[0] << 16;
+ *sp++ = ((u_int16_t *) addrp)[1] << 16;
+ *sp++ = ((u_int16_t *) addrp)[2] << 16;
+#else
+ *sp++ = ((u_int16_t *) addrp)[0];
+ *sp++ = ((u_int16_t *) addrp)[1];
+ *sp++ = ((u_int16_t *) addrp)[2];
+#endif
+ idx++;
+ }
+ /*
+ * Add the broadcast address.
+ */
+ idx++;
+#if BYTE_ORDER == BIG_ENDIAN
+ *sp++ = 0xFFFF << 16;
+ *sp++ = 0xFFFF << 16;
+ *sp++ = 0xFFFF << 16;
+#else
+ *sp++ = 0xFFFF;
+ *sp++ = 0xFFFF;
+ *sp++ = 0xFFFF;
+#endif
+ }
+ /*
+ * Pad the rest with our hardware address
+ */
+ for (; idx < 16; idx++) {
+#if BYTE_ORDER == BIG_ENDIAN
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0] << 16;
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1] << 16;
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2] << 16;
+#else
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0];
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1];
+ *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2];
+#endif
+ }
+ }
+#if defined(IFF_ALLMULTI)
+ if (sc->tulip_flags & TULIP_ALLMULTI)
+ sc->tulip_if.if_flags |= IFF_ALLMULTI;
+#endif
+}
+
+static void
+tulip_reset(
+ tulip_softc_t * const sc)
+{
+ tulip_ringinfo_t *ri;
+ tulip_desc_t *di;
+ u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET);
+
+ /*
+ * Brilliant. Simply brilliant. When switching modes/speeds
+ * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS
+ * bits in CSR6 and then do a software reset to get the 21140
+ * to properly reset its internal pathways to the right places.
+ * Grrrr.
+ */
+ if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0
+ && sc->tulip_boardsw->bd_media_preset != NULL)
+ (*sc->tulip_boardsw->bd_media_preset)(sc);
+
+ TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at
+ 33MHz that comes to two microseconds but wait a
+ bit longer anyways) */
+
+ if (!inreset) {
+ sc->tulip_flags |= TULIP_INRESET;
+ sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW);
+ sc->tulip_if.if_flags &= ~IFF_OACTIVE;
+ sc->tulip_if.if_start = tulip_ifstart;
+ }
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr);
+#else
+ TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0]));
+#endif
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr);
+#else
+ TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0]));
+#endif
+ TULIP_CSR_WRITE(sc, csr_busmode,
+ (1 << (3 /*pci_max_burst_len*/ + 8))
+ |TULIP_BUSMODE_CACHE_ALIGN8
+ |TULIP_BUSMODE_READMULTIPLE
+ |(BYTE_ORDER != LITTLE_ENDIAN ?
+ TULIP_BUSMODE_DESC_BIGENDIAN : 0));
+
+ sc->tulip_txtimer = 0;
+ sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS;
+ /*
+ * Free all the mbufs that were on the transmit ring.
+ */
+ for (;;) {
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ bus_dmamap_t map;
+#endif
+ struct mbuf *m;
+ _IF_DEQUEUE(&sc->tulip_txq, m);
+ if (m == NULL)
+ break;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ map = M_GETCTX(m, bus_dmamap_t);
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
+#endif
+ m_freem(m);
+ }
+
+ ri = &sc->tulip_txinfo;
+ ri->ri_nextin = ri->ri_nextout = ri->ri_first;
+ ri->ri_free = ri->ri_max;
+ for (di = ri->ri_first; di < ri->ri_last; di++)
+ di->d_status = 0;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap,
+ 0, sc->tulip_txdescmap->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#endif
+
+ /*
+ * We need to collect all the mbufs were on the
+ * receive ring before we reinit it either to put
+ * them back on or to know if we have to allocate
+ * more.
+ */
+ ri = &sc->tulip_rxinfo;
+ ri->ri_nextin = ri->ri_nextout = ri->ri_first;
+ ri->ri_free = ri->ri_max;
+ for (di = ri->ri_first; di < ri->ri_last; di++) {
+ di->d_status = 0;
+ di->d_length1 = 0; di->d_addr1 = 0;
+ di->d_length2 = 0; di->d_addr2 = 0;
+ }
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap,
+ 0, sc->tulip_rxdescmap->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#endif
+ for (;;) {
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ bus_dmamap_t map;
+#endif
+ struct mbuf *m;
+ _IF_DEQUEUE(&sc->tulip_rxq, m);
+ if (m == NULL)
+ break;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ map = M_GETCTX(m, bus_dmamap_t);
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
+#endif
+ m_freem(m);
+ }
+
+ /*
+ * If tulip_reset is being called recurisvely, exit quickly knowing
+ * that when the outer tulip_reset returns all the right stuff will
+ * have happened.
+ */
+ if (inreset)
+ return;
+
+ sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR
+ |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED
+ |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE
+ |TULIP_STS_RXSTOPPED;
+
+ if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0)
+ (*sc->tulip_boardsw->bd_media_select)(sc);
+#if defined(TULIP_DEBUG)
+ if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET)
+ printf("%s%d: tulip_reset: additional reset needed?!?\n",
+ sc->tulip_name, sc->tulip_unit);
+#endif
+ tulip_media_print(sc);
+ if (sc->tulip_features & TULIP_HAVE_DUALSENSE)
+ TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
+
+ sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET
+ |TULIP_RXACT);
+ tulip_addr_filter(sc);
+}
+
+
+static void
+tulip_ifinit(
+ void * sc)
+{
+ tulip_init((tulip_softc_t *)sc);
+}
+
+static void
+tulip_init(
+ tulip_softc_t * const sc)
+{
+ if (sc->tulip_if.if_flags & IFF_UP) {
+ if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) {
+ /* initialize the media */
+ tulip_reset(sc);
+ }
+ sc->tulip_if.if_flags |= IFF_RUNNING;
+ if (sc->tulip_if.if_flags & IFF_PROMISC) {
+ sc->tulip_flags |= TULIP_PROMISC;
+ sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS;
+ sc->tulip_intrmask |= TULIP_STS_TXINTR;
+ } else {
+ sc->tulip_flags &= ~TULIP_PROMISC;
+ sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS;
+ if (sc->tulip_flags & TULIP_ALLMULTI) {
+ sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI;
+ } else {
+ sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI;
+ }
+ }
+ sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
+ if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) {
+ tulip_rx_intr(sc);
+ sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
+ sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
+ } else {
+ sc->tulip_if.if_flags |= IFF_OACTIVE;
+ sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
+ sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
+ }
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
+ tulip_txput_setup(sc);
+ } else {
+ sc->tulip_if.if_flags &= ~IFF_RUNNING;
+ tulip_reset(sc);
+ }
+}
+
+static void
+tulip_rx_intr(
+ tulip_softc_t * const sc)
+{
+ TULIP_PERFSTART(rxintr)
+ tulip_ringinfo_t * const ri = &sc->tulip_rxinfo;
+ struct ifnet * const ifp = &sc->tulip_if;
+ int fillok = 1;
+#if defined(TULIP_DEBUG)
+ int cnt = 0;
+#endif
+
+ for (;;) {
+ TULIP_PERFSTART(rxget)
+ struct ether_header eh;
+ tulip_desc_t *eop = ri->ri_nextin;
+ int total_len = 0, last_offset = 0;
+ struct mbuf *ms = NULL, *me = NULL;
+ int accept = 0;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ bus_dmamap_t map;
+ int error;
+#endif
+
+ if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET)
+ goto queue_mbuf;
+
+#if defined(TULIP_DEBUG)
+ if (cnt == ri->ri_max)
+ break;
+#endif
+ /*
+ * If the TULIP has no descriptors, there can't be any receive
+ * descriptors to process.
+ */
+ if (eop == ri->ri_nextout)
+ break;
+
+ /*
+ * 90% of the packets will fit in one descriptor. So we optimize
+ * for that case.
+ */
+ TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
+ if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
+ _IF_DEQUEUE(&sc->tulip_rxq, ms);
+ me = ms;
+ } else {
+ /*
+ * If still owned by the TULIP, don't touch it.
+ */
+ if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER)
+ break;
+
+ /*
+ * It is possible (though improbable unless the BIG_PACKET support
+ * is enabled or MCLBYTES < 1518) for a received packet to cross
+ * more than one receive descriptor.
+ */
+ while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) {
+ if (++eop == ri->ri_last)
+ eop = ri->ri_first;
+ TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
+ if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_rxintrs++;
+ sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
+#endif
+ TULIP_PERFEND(rxget);
+ TULIP_PERFEND(rxintr);
+ return;
+ }
+ total_len++;
+ }
+
+ /*
+ * Dequeue the first buffer for the start of the packet. Hopefully
+ * this will be the only one we need to dequeue. However, if the
+ * packet consumed multiple descriptors, then we need to dequeue
+ * those buffers and chain to the starting mbuf. All buffers but
+ * the last buffer have the same length so we can set that now.
+ * (we add to last_offset instead of multiplying since we normally
+ * won't go into the loop and thereby saving a ourselves from
+ * doing a multiplication by 0 in the normal case).
+ */
+ _IF_DEQUEUE(&sc->tulip_rxq, ms);
+ for (me = ms; total_len > 0; total_len--) {
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ map = M_GETCTX(me, bus_dmamap_t);
+ TULIP_RXMAP_POSTSYNC(sc, map);
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
+#if defined(DIAGNOSTIC)
+ M_SETCTX(me, NULL);
+#endif
+#endif /* TULIP_BUS_DMA */
+ me->m_len = TULIP_RX_BUFLEN;
+ last_offset += TULIP_RX_BUFLEN;
+ _IF_DEQUEUE(&sc->tulip_rxq, me->m_next);
+ me = me->m_next;
+ }
+ }
+
+ /*
+ * Now get the size of received packet (minus the CRC).
+ */
+ total_len = ((eop->d_status >> 16) & 0x7FFF) - 4;
+ if ((sc->tulip_flags & TULIP_RXIGNORE) == 0
+ && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0
+#ifdef BIG_PACKET
+ || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) &&
+ (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT|
+ TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC|
+ TULIP_DSTS_RxOVERFLOW)) == 0)
+#endif
+ )) {
+ me->m_len = total_len - last_offset;
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ map = M_GETCTX(me, bus_dmamap_t);
+ bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
+#if defined(DIAGNOSTIC)
+ M_SETCTX(me, NULL);
+#endif
+#endif /* TULIP_BUS_DMA */
+
+ eh = *mtod(ms, struct ether_header *);
+#ifndef __FreeBSD__
+ if (sc->tulip_if.if_bpf != NULL) {
+ if (me == ms)
+ bpf_tap(&sc->tulip_if, mtod(ms, caddr_t), total_len);
+ else
+ bpf_mtap(&sc->tulip_if, ms);
+ }
+#endif
+ sc->tulip_flags |= TULIP_RXACT;
+ accept = 1;
+ } else {
+ ifp->if_ierrors++;
+ if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) {
+ sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
+ } else {
+#if defined(TULIP_VERBOSE)
+ const char *error = NULL;
+#endif
+ if (eop->d_status & TULIP_DSTS_RxTOOLONG) {
+ sc->tulip_dot3stats.dot3StatsFrameTooLongs++;
+#if defined(TULIP_VERBOSE)
+ error = "frame too long";
+#endif
+ }
+ if (eop->d_status & TULIP_DSTS_RxBADCRC) {
+ if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) {
+ sc->tulip_dot3stats.dot3StatsAlignmentErrors++;
+#if defined(TULIP_VERBOSE)
+ error = "alignment error";
+#endif
+ } else {
+ sc->tulip_dot3stats.dot3StatsFCSErrors++;
+#if defined(TULIP_VERBOSE)
+ error = "bad crc";
+#endif
+ }
+ }
+#if defined(TULIP_VERBOSE)
+ if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) {
+ printf("%s%d: receive: %6D: %s\n",
+ sc->tulip_name, sc->tulip_unit,
+ mtod(ms, u_char *) + 6, ":",
+ error);
+ sc->tulip_flags |= TULIP_NOMESSAGES;
+ }
+#endif
+ }
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ map = M_GETCTX(me, bus_dmamap_t);
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
+#if defined(DIAGNOSTIC)
+ M_SETCTX(me, NULL);
+#endif
+#endif /* TULIP_BUS_DMA */
+ }
+#if defined(TULIP_DEBUG)
+ cnt++;
+#endif
+ ifp->if_ipackets++;
+ if (++eop == ri->ri_last)
+ eop = ri->ri_first;
+ ri->ri_nextin = eop;
+ queue_mbuf:
+ /*
+ * Either we are priming the TULIP with mbufs (m == NULL)
+ * or we are about to accept an mbuf for the upper layers
+ * so we need to allocate an mbuf to replace it. If we
+ * can't replace it, send up it anyways. This may cause
+ * us to drop packets in the future but that's better than
+ * being caught in livelock.
+ *
+ * Note that if this packet crossed multiple descriptors
+ * we don't even try to reallocate all the mbufs here.
+ * Instead we rely on the test of the beginning of
+ * the loop to refill for the extra consumed mbufs.
+ */
+ if (accept || ms == NULL) {
+ struct mbuf *m0;
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 != NULL) {
+#if defined(TULIP_COPY_RXDATA)
+ if (!accept || total_len >= (MHLEN - 2)) {
+#endif
+ MCLGET(m0, M_DONTWAIT);
+ if ((m0->m_flags & M_EXT) == 0) {
+ m_freem(m0);
+ m0 = NULL;
+ }
+#if defined(TULIP_COPY_RXDATA)
+ }
+#endif
+ }
+ if (accept
+#if defined(TULIP_COPY_RXDATA)
+ && m0 != NULL
+#endif
+ ) {
+#if !defined(TULIP_COPY_RXDATA)
+ ms->m_pkthdr.len = total_len;
+ ms->m_pkthdr.rcvif = ifp;
+ m_adj(ms, sizeof(struct ether_header));
+ ether_input(ifp, &eh, ms);
+#else
+#ifdef BIG_PACKET
+#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA
+#endif
+ m0->m_data += 2; /* align data after header */
+ m_copydata(ms, 0, total_len, mtod(m0, caddr_t));
+ m0->m_len = m0->m_pkthdr.len = total_len;
+ m0->m_pkthdr.rcvif = ifp;
+ m_adj(m0, sizeof(struct ether_header));
+ ether_input(ifp, &eh, m0);
+ m0 = ms;
+#endif /* ! TULIP_COPY_RXDATA */
+ }
+ ms = m0;
+ }
+ if (ms == NULL) {
+ /*
+ * Couldn't allocate a new buffer. Don't bother
+ * trying to replenish the receive queue.
+ */
+ fillok = 0;
+ sc->tulip_flags |= TULIP_RXBUFSLOW;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_rxlowbufs++;
+#endif
+ TULIP_PERFEND(rxget);
+ continue;
+ }
+ /*
+ * Now give the buffer(s) to the TULIP and save in our
+ * receive queue.
+ */
+ do {
+ tulip_desc_t * const nextout = ri->ri_nextout;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+ if (sc->tulip_rxmaps_free > 0) {
+ map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free];
+ } else {
+ m_freem(ms);
+ sc->tulip_flags |= TULIP_RXBUFSLOW;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_rxlowbufs++;
+#endif
+ break;
+ }
+ M_SETCTX(ms, map);
+ error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *),
+ TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT);
+ if (error) {
+ printf("%s%d: unable to load rx map, "
+ "error = %d\n", sc->tulip_name, sc->tulip_unit, error);
+ panic("tulip_rx_intr"); /* XXX */
+ }
+ nextout->d_addr1 = map->dm_segs[0].ds_addr;
+ nextout->d_length1 = map->dm_segs[0].ds_len;
+ if (map->dm_nsegs == 2) {
+ nextout->d_addr2 = map->dm_segs[1].ds_addr;
+ nextout->d_length2 = map->dm_segs[1].ds_len;
+ } else {
+ nextout->d_addr2 = 0;
+ nextout->d_length2 = 0;
+ }
+ TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout));
+#else /* TULIP_BUS_DMA */
+ nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t));
+ nextout->d_length1 = TULIP_RX_BUFLEN;
+#endif /* TULIP_BUS_DMA */
+ nextout->d_status = TULIP_DSTS_OWNER;
+ TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t));
+ if (++ri->ri_nextout == ri->ri_last)
+ ri->ri_nextout = ri->ri_first;
+ me = ms->m_next;
+ ms->m_next = NULL;
+ _IF_ENQUEUE(&sc->tulip_rxq, ms);
+ } while ((ms = me) != NULL);
+
+ if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET)
+ sc->tulip_flags &= ~TULIP_RXBUFSLOW;
+ TULIP_PERFEND(rxget);
+ }
+
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_rxintrs++;
+ sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
+#endif
+ TULIP_PERFEND(rxintr);
+}
+
+static int
+tulip_tx_intr(
+ tulip_softc_t * const sc)
+{
+ TULIP_PERFSTART(txintr)
+ tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
+ struct mbuf *m;
+ int xmits = 0;
+ int descs = 0;
+
+ while (ri->ri_free < ri->ri_max) {
+ u_int32_t d_flag;
+
+ TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin));
+ if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER)
+ break;
+
+ ri->ri_free++;
+ descs++;
+ d_flag = ri->ri_nextin->d_flag;
+ if (d_flag & TULIP_DFLAG_TxLASTSEG) {
+ if (d_flag & TULIP_DFLAG_TxSETUPPKT) {
+ /*
+ * We've just finished processing a setup packet.
+ * Mark that we finished it. If there's not
+ * another pending, startup the TULIP receiver.
+ * Make sure we ack the RXSTOPPED so we won't get
+ * an abormal interrupt indication.
+ */
+ TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap);
+ sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY);
+ if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT)
+ sc->tulip_flags |= TULIP_HASHONLY;
+ if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) {
+ tulip_rx_intr(sc);
+ sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
+ sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
+ TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ }
+ } else {
+ const u_int32_t d_status = ri->ri_nextin->d_status;
+ _IF_DEQUEUE(&sc->tulip_txq, m);
+ if (m != NULL) {
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
+ TULIP_TXMAP_POSTSYNC(sc, map);
+ sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
+#endif /* TULIP_BUS_DMA */
+ m_freem(m);
+#if defined(TULIP_DEBUG)
+ } else {
+ printf("%s%d: tx_intr: failed to dequeue mbuf?!?\n",
+ sc->tulip_name, sc->tulip_unit);
+#endif
+ }
+ if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
+ tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK;
+ if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) {
+#if defined(TULIP_DEBUG)
+ if (d_status & TULIP_DSTS_TxNOCARR)
+ sc->tulip_dbg.dbg_txprobe_nocarr++;
+ if (d_status & TULIP_DSTS_TxEXCCOLL)
+ sc->tulip_dbg.dbg_txprobe_exccoll++;
+#endif
+ event = TULIP_MEDIAPOLL_TXPROBE_FAILED;
+ }
+ (*sc->tulip_boardsw->bd_media_poll)(sc, event);
+ /*
+ * Escape from the loop before media poll has reset the TULIP!
+ */
+ break;
+ } else {
+ xmits++;
+ if (d_status & TULIP_DSTS_ERRSUM) {
+ sc->tulip_if.if_oerrors++;
+ if (d_status & TULIP_DSTS_TxEXCCOLL)
+ sc->tulip_dot3stats.dot3StatsExcessiveCollisions++;
+ if (d_status & TULIP_DSTS_TxLATECOLL)
+ sc->tulip_dot3stats.dot3StatsLateCollisions++;
+ if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS))
+ sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++;
+ if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE))
+ sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++;
+ if (d_status & TULIP_DSTS_TxUNDERFLOW)
+ sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++;
+ if (d_status & TULIP_DSTS_TxBABBLE)
+ sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++;
+ } else {
+ u_int32_t collisions =
+ (d_status & TULIP_DSTS_TxCOLLMASK)
+ >> TULIP_DSTS_V_TxCOLLCNT;
+ sc->tulip_if.if_collisions += collisions;
+ if (collisions == 1)
+ sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++;
+ else if (collisions > 1)
+ sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++;
+ else if (d_status & TULIP_DSTS_TxDEFERRED)
+ sc->tulip_dot3stats.dot3StatsDeferredTransmissions++;
+ /*
+ * SQE is only valid for 10baseT/BNC/AUI when not
+ * running in full-duplex. In order to speed up the
+ * test, the corresponding bit in tulip_flags needs to
+ * set as well to get us to count SQE Test Errors.
+ */
+ if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags)
+ sc->tulip_dot3stats.dot3StatsSQETestErrors++;
+ }
+ }
+ }
+ }
+
+ if (++ri->ri_nextin == ri->ri_last)
+ ri->ri_nextin = ri->ri_first;
+
+ if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
+ sc->tulip_if.if_flags &= ~IFF_OACTIVE;
+ }
+ /*
+ * If nothing left to transmit, disable the timer.
+ * Else if progress, reset the timer back to 2 ticks.
+ */
+ if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE))
+ sc->tulip_txtimer = 0;
+ else if (xmits > 0)
+ sc->tulip_txtimer = TULIP_TXTIMER;
+ sc->tulip_if.if_opackets += xmits;
+ TULIP_PERFEND(txintr);
+ return descs;
+}
+
+static void
+tulip_print_abnormal_interrupt(
+ tulip_softc_t * const sc,
+ u_int32_t csr)
+{
+ const char * const *msgp = tulip_status_bits;
+ const char *sep;
+ u_int32_t mask;
+ const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024";
+
+ csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1;
+ printf("%s%d: abnormal interrupt:", sc->tulip_name, sc->tulip_unit);
+ for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) {
+ if ((csr & mask) && *msgp != NULL) {
+ printf("%s%s", sep, *msgp);
+ if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) {
+ sc->tulip_flags &= ~TULIP_NEWTXTHRESH;
+ if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) {
+ printf(" (switching to store-and-forward mode)");
+ } else {
+ printf(" (raising TX threshold to %s)",
+ &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]);
+ }
+ }
+ sep = ", ";
+ }
+ }
+ printf("\n");
+}
+
+static void
+tulip_intr_handler(
+ tulip_softc_t * const sc,
+ int *progress_p)
+{
+ TULIP_PERFSTART(intr)
+ u_int32_t csr;
+
+ while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) {
+ *progress_p = 1;
+ TULIP_CSR_WRITE(sc, csr_status, csr);
+
+ if (csr & TULIP_STS_SYSERROR) {
+ sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
+ if (sc->tulip_flags & TULIP_NOMESSAGES) {
+ sc->tulip_flags |= TULIP_SYSTEMERROR;
+ } else {
+ printf("%s%d: system error: %s\n",
+ sc->tulip_name, sc->tulip_unit,
+ tulip_system_errors[sc->tulip_last_system_error]);
+ }
+ sc->tulip_flags |= TULIP_NEEDRESET;
+ sc->tulip_system_errors++;
+ break;
+ }
+ if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_link_intrs++;
+#endif
+ if (sc->tulip_boardsw->bd_media_poll != NULL) {
+ (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL
+ ? TULIP_MEDIAPOLL_LINKFAIL
+ : TULIP_MEDIAPOLL_LINKPASS);
+ csr &= ~TULIP_STS_ABNRMLINTR;
+ }
+ tulip_media_print(sc);
+ }
+ if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) {
+ u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames);
+ if (csr & TULIP_STS_RXNOBUF)
+ sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF;
+ /*
+ * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data
+ * on receive overflows.
+ */
+ if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) {
+ sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
+ /*
+ * Stop the receiver process and spin until it's stopped.
+ * Tell rx_intr to drop the packets it dequeues.
+ */
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN);
+ while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0)
+ ;
+ TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
+ sc->tulip_flags |= TULIP_RXIGNORE;
+ }
+ tulip_rx_intr(sc);
+ if (sc->tulip_flags & TULIP_RXIGNORE) {
+ /*
+ * Restart the receiver.
+ */
+ sc->tulip_flags &= ~TULIP_RXIGNORE;
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ }
+ }
+ if (csr & TULIP_STS_ABNRMLINTR) {
+ u_int32_t tmp = csr & sc->tulip_intrmask
+ & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
+ if (csr & TULIP_STS_TXUNDERFLOW) {
+ if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) {
+ sc->tulip_cmdmode += TULIP_CMD_THRSHLD96;
+ sc->tulip_flags |= TULIP_NEWTXTHRESH;
+ } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) {
+ sc->tulip_cmdmode |= TULIP_CMD_STOREFWD;
+ sc->tulip_flags |= TULIP_NEWTXTHRESH;
+ }
+ }
+ if (sc->tulip_flags & TULIP_NOMESSAGES) {
+ sc->tulip_statusbits |= tmp;
+ } else {
+ tulip_print_abnormal_interrupt(sc, tmp);
+ sc->tulip_flags |= TULIP_NOMESSAGES;
+ }
+ TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
+ }
+ if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) {
+ tulip_tx_intr(sc);
+ if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
+ tulip_ifstart(&sc->tulip_if);
+ }
+ }
+ if (sc->tulip_flags & TULIP_NEEDRESET) {
+ tulip_reset(sc);
+ tulip_init(sc);
+ }
+ TULIP_PERFEND(intr);
+}
+
+#if defined(TULIP_USE_SOFTINTR)
+/*
+ * This is a experimental idea to alleviate problems due to interrupt
+ * livelock. What is interrupt livelock? It's when you spend all your
+ * time servicing device interrupts and never drop below device ipl
+ * to do "useful" work.
+ *
+ * So what we do here is see if the device needs service and if so,
+ * disable interrupts (dismiss the interrupt), place it in a list of devices
+ * needing service, and issue a network software interrupt.
+ *
+ * When our network software interrupt routine gets called, we simply
+ * walk done the list of devices that we have created and deal with them
+ * at splnet/splsoftnet.
+ *
+ */
+static void
+tulip_hardintr_handler(
+ tulip_softc_t * const sc,
+ int *progress_p)
+{
+ if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0)
+ return;
+ *progress_p = 1;
+ /*
+ * disable interrupts
+ */
+ TULIP_CSR_WRITE(sc, csr_intr, 0);
+ /*
+ * mark it as needing a software interrupt
+ */
+ tulip_softintr_mask |= (1U << sc->tulip_unit);
+}
+
+static void
+tulip_softintr(
+ void)
+{
+ u_int32_t softintr_mask, mask;
+ int progress = 0;
+ int unit;
+ int s;
+
+ /*
+ * Copy mask to local copy and reset global one to 0.
+ */
+ s = splimp();
+ softintr_mask = tulip_softintr_mask;
+ tulip_softintr_mask = 0;
+ splx(s);
+
+ /*
+ * Optimize for the single unit case.
+ */
+ if (tulip_softintr_max_unit == 0) {
+ if (softintr_mask & 1) {
+ tulip_softc_t * const sc = tulips[0];
+ /*
+ * Handle the "interrupt" and then reenable interrupts
+ */
+ softintr_mask = 0;
+ tulip_intr_handler(sc, &progress);
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ }
+ return;
+ }
+
+ /*
+ * Handle all "queued" interrupts in a round robin fashion.
+ * This is done so as not to favor a particular interface.
+ */
+ unit = tulip_softintr_last_unit;
+ mask = (1U << unit);
+ while (softintr_mask != 0) {
+ if (tulip_softintr_max_unit == unit) {
+ unit = 0; mask = 1;
+ } else {
+ unit += 1; mask <<= 1;
+ }
+ if (softintr_mask & mask) {
+ tulip_softc_t * const sc = tulips[unit];
+ /*
+ * Handle the "interrupt" and then reenable interrupts
+ */
+ softintr_mask ^= mask;
+ tulip_intr_handler(sc, &progress);
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ }
+ }
+
+ /*
+ * Save where we ending up.
+ */
+ tulip_softintr_last_unit = unit;
+}
+#endif /* TULIP_USE_SOFTINTR */
+
+static void
+tulip_intr_shared(
+ void *arg)
+{
+ tulip_softc_t * sc = arg;
+ int progress = 0;
+
+ for (; sc != NULL; sc = sc->tulip_slaves) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_intrs++;
+#endif
+#if defined(TULIP_USE_SOFTINTR)
+ tulip_hardintr_handler(sc, &progress);
+#else
+ tulip_intr_handler(sc, &progress);
+#endif
+ }
+#if defined(TULIP_USE_SOFTINTR)
+ if (progress)
+ schednetisr(NETISR_DE);
+#endif
+}
+
+static void
+tulip_intr_normal(
+ void *arg)
+{
+ tulip_softc_t * sc = (tulip_softc_t *) arg;
+ int progress = 0;
+
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_intrs++;
+#endif
+#if defined(TULIP_USE_SOFTINTR)
+ tulip_hardintr_handler(sc, &progress);
+ if (progress)
+ schednetisr(NETISR_DE);
+#else
+ tulip_intr_handler(sc, &progress);
+#endif
+}
+
+static struct mbuf *
+tulip_mbuf_compress(
+ struct mbuf *m)
+{
+ struct mbuf *m0;
+#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET)
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 != NULL) {
+ if (m->m_pkthdr.len > MHLEN) {
+ MCLGET(m0, M_DONTWAIT);
+ if ((m0->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m_freem(m0);
+ return NULL;
+ }
+ }
+ m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
+ m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
+ }
+#else
+ int mlen = MHLEN;
+ int len = m->m_pkthdr.len;
+ struct mbuf **mp = &m0;
+
+ while (len > 0) {
+ if (mlen == MHLEN) {
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ } else {
+ MGET(*mp, M_DONTWAIT, MT_DATA);
+ }
+ if (*mp == NULL) {
+ m_freem(m0);
+ m0 = NULL;
+ break;
+ }
+ if (len > MLEN) {
+ MCLGET(*mp, M_DONTWAIT);
+ if (((*mp)->m_flags & M_EXT) == 0) {
+ m_freem(m0);
+ m0 = NULL;
+ break;
+ }
+ (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES;
+ } else {
+ (*mp)->m_len = len <= mlen ? len : mlen;
+ }
+ m_copydata(m, m->m_pkthdr.len - len,
+ (*mp)->m_len, mtod((*mp), caddr_t));
+ len -= (*mp)->m_len;
+ mp = &(*mp)->m_next;
+ mlen = MLEN;
+ }
+#endif
+ m_freem(m);
+ return m0;
+}
+
+static struct mbuf *
+tulip_txput(
+ tulip_softc_t * const sc,
+ struct mbuf *m)
+{
+ TULIP_PERFSTART(txput)
+ tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
+ tulip_desc_t *eop, *nextout;
+ int segcnt, free;
+ u_int32_t d_status;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ bus_dmamap_t map;
+ int error;
+#else
+ struct mbuf *m0;
+#endif
+
+#if defined(TULIP_DEBUG)
+ if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
+ printf("%s%d: txput%s: tx not running\n",
+ sc->tulip_name, sc->tulip_unit,
+ (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : "");
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+ sc->tulip_dbg.dbg_txput_finishes[0]++;
+ goto finish;
+ }
+#endif
+
+ /*
+ * Now we try to fill in our transmit descriptors. This is
+ * a bit reminiscent of going on the Ark two by two
+ * since each descriptor for the TULIP can describe
+ * two buffers. So we advance through packet filling
+ * each of the two entries at a time to to fill each
+ * descriptor. Clear the first and last segment bits
+ * in each descriptor (actually just clear everything
+ * but the end-of-ring or chain bits) to make sure
+ * we don't get messed up by previously sent packets.
+ *
+ * We may fail to put the entire packet on the ring if
+ * there is either not enough ring entries free or if the
+ * packet has more than MAX_TXSEG segments. In the former
+ * case we will just wait for the ring to empty. In the
+ * latter case we have to recopy.
+ */
+#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX)
+ again:
+ m0 = m;
+#endif
+ d_status = 0;
+ eop = nextout = ri->ri_nextout;
+ segcnt = 0;
+ free = ri->ri_free;
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ /*
+ * Reclaim some dma maps from if we are out.
+ */
+ if (sc->tulip_txmaps_free == 0) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_no_txmaps++;
+#endif
+ free += tulip_tx_intr(sc);
+ }
+ if (sc->tulip_txmaps_free > 0) {
+ map = sc->tulip_txmaps[sc->tulip_txmaps_free-1];
+ } else {
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[1]++;
+#endif
+ goto finish;
+ }
+ error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if (error == EFBIG) {
+ /*
+ * The packet exceeds the number of transmit buffer
+ * entries that we can use for one packet, so we have
+ * to recopy it into one mbuf and then try again.
+ */
+ m = tulip_mbuf_compress(m);
+ if (m == NULL) {
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[2]++;
+#endif
+ goto finish;
+ }
+ error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT);
+ }
+ if (error != 0) {
+ printf("%s%d: unable to load tx map, "
+ "error = %d\n", sc->tulip_name, sc->tulip_unit, error);
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[3]++;
+#endif
+ goto finish;
+ }
+ }
+ if ((free -= (map->dm_nsegs + 1) / 2) <= 0
+ /*
+ * See if there's any unclaimed space in the transmit ring.
+ */
+ && (free += tulip_tx_intr(sc)) <= 0) {
+ /*
+ * There's no more room but since nothing
+ * has been committed at this point, just
+ * show output is active, put back the
+ * mbuf and return.
+ */
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[4]++;
+#endif
+ bus_dmamap_unload(sc->tulip_dmatag, map);
+ goto finish;
+ }
+ for (; map->dm_nsegs - segcnt > 1; segcnt += 2) {
+ eop = nextout;
+ eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
+ eop->d_status = d_status;
+ eop->d_addr1 = map->dm_segs[segcnt].ds_addr;
+ eop->d_length1 = map->dm_segs[segcnt].ds_len;
+ eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr;
+ eop->d_length2 = map->dm_segs[segcnt+1].ds_len;
+ d_status = TULIP_DSTS_OWNER;
+ if (++nextout == ri->ri_last)
+ nextout = ri->ri_first;
+ }
+ if (segcnt < map->dm_nsegs) {
+ eop = nextout;
+ eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
+ eop->d_status = d_status;
+ eop->d_addr1 = map->dm_segs[segcnt].ds_addr;
+ eop->d_length1 = map->dm_segs[segcnt].ds_len;
+ eop->d_addr2 = 0;
+ eop->d_length2 = 0;
+ if (++nextout == ri->ri_last)
+ nextout = ri->ri_first;
+ }
+ TULIP_TXMAP_PRESYNC(sc, map);
+ M_SETCTX(m, map);
+ map = NULL;
+ --sc->tulip_txmaps_free; /* commit to using the dmamap */
+
+#else /* !TULIP_BUS_DMA */
+
+ do {
+ int len = m0->m_len;
+ caddr_t addr = mtod(m0, caddr_t);
+ unsigned clsize = PAGE_SIZE - (((uintptr_t) addr) & (PAGE_SIZE-1));
+
+ while (len > 0) {
+ unsigned slen = min(len, clsize);
+#ifdef BIG_PACKET
+ int partial = 0;
+ if (slen >= 2048)
+ slen = 2040, partial = 1;
+#endif
+ segcnt++;
+ if (segcnt > TULIP_MAX_TXSEG) {
+ /*
+ * The packet exceeds the number of transmit buffer
+ * entries that we can use for one packet, so we have
+ * recopy it into one mbuf and then try again.
+ */
+ m = tulip_mbuf_compress(m);
+ if (m == NULL)
+ goto finish;
+ goto again;
+ }
+ if (segcnt & 1) {
+ if (--free == 0) {
+ /*
+ * See if there's any unclaimed space in the
+ * transmit ring.
+ */
+ if ((free += tulip_tx_intr(sc)) == 0) {
+ /*
+ * There's no more room but since nothing
+ * has been committed at this point, just
+ * show output is active, put back the
+ * mbuf and return.
+ */
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[1]++;
+#endif
+ goto finish;
+ }
+ }
+ eop = nextout;
+ if (++nextout == ri->ri_last)
+ nextout = ri->ri_first;
+ eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
+ eop->d_status = d_status;
+ eop->d_addr1 = TULIP_KVATOPHYS(sc, addr);
+ eop->d_length1 = slen;
+ } else {
+ /*
+ * Fill in second half of descriptor
+ */
+ eop->d_addr2 = TULIP_KVATOPHYS(sc, addr);
+ eop->d_length2 = slen;
+ }
+ d_status = TULIP_DSTS_OWNER;
+ len -= slen;
+ addr += slen;
+#ifdef BIG_PACKET
+ if (partial)
+ continue;
+#endif
+ clsize = PAGE_SIZE;
+ }
+ } while ((m0 = m0->m_next) != NULL);
+#endif /* TULIP_BUS_DMA */
+
+ /*
+ * bounce a copy to the bpf listener, if any.
+ */
+ if (sc->tulip_if.if_bpf != NULL)
+ bpf_mtap(&sc->tulip_if, m);
+
+ /*
+ * The descriptors have been filled in. Now get ready
+ * to transmit.
+ */
+ _IF_ENQUEUE(&sc->tulip_txq, m);
+ m = NULL;
+
+ /*
+ * Make sure the next descriptor after this packet is owned
+ * by us since it may have been set up above if we ran out
+ * of room in the ring.
+ */
+ nextout->d_status = 0;
+ TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t));
+
+#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX)
+ /*
+ * If we only used the first segment of the last descriptor,
+ * make sure the second segment will not be used.
+ */
+ if (segcnt & 1) {
+ eop->d_addr2 = 0;
+ eop->d_length2 = 0;
+ }
+#endif /* TULIP_BUS_DMA */
+
+ /*
+ * Mark the last and first segments, indicate we want a transmit
+ * complete interrupt, and tell it to transmit!
+ */
+ eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR;
+
+ /*
+ * Note that ri->ri_nextout is still the start of the packet
+ * and until we set the OWNER bit, we can still back out of
+ * everything we have done.
+ */
+ ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG;
+#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX)
+ if (eop < ri->ri_nextout) {
+ TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout,
+ (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout);
+ TULIP_TXDESC_PRESYNC(sc, ri->ri_first,
+ (caddr_t) (eop + 1) - (caddr_t) ri->ri_first);
+ } else {
+ TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout,
+ (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout);
+ }
+#endif
+ ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
+ TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t));
+
+ /*
+ * This advances the ring for us.
+ */
+ ri->ri_nextout = nextout;
+ ri->ri_free = free;
+
+ TULIP_PERFEND(txput);
+
+ if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
+ TULIP_CSR_WRITE(sc, csr_txpoll, 1);
+ sc->tulip_if.if_flags |= IFF_OACTIVE;
+ sc->tulip_if.if_start = tulip_ifstart;
+ TULIP_PERFEND(txput);
+ return NULL;
+ }
+
+ /*
+ * switch back to the single queueing ifstart.
+ */
+ sc->tulip_flags &= ~TULIP_WANTTXSTART;
+ if (sc->tulip_txtimer == 0)
+ sc->tulip_txtimer = TULIP_TXTIMER;
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[5]++;
+#endif
+
+ /*
+ * If we want a txstart, there must be not enough space in the
+ * transmit ring. So we want to enable transmit done interrupts
+ * so we can immediately reclaim some space. When the transmit
+ * interrupt is posted, the interrupt handler will call tx_intr
+ * to reclaim space and then txstart (since WANTTXSTART is set).
+ * txstart will move the packet into the transmit ring and clear
+ * WANTTXSTART thereby causing TXINTR to be cleared.
+ */
+ finish:
+#if defined(TULIP_DEBUG)
+ sc->tulip_dbg.dbg_txput_finishes[6]++;
+#endif
+ if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) {
+ sc->tulip_if.if_flags |= IFF_OACTIVE;
+ sc->tulip_if.if_start = tulip_ifstart;
+ if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
+ sc->tulip_intrmask |= TULIP_STS_TXINTR;
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ }
+ } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) {
+ if (sc->tulip_intrmask & TULIP_STS_TXINTR) {
+ sc->tulip_intrmask &= ~TULIP_STS_TXINTR;
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ }
+ }
+ TULIP_CSR_WRITE(sc, csr_txpoll, 1);
+ TULIP_PERFEND(txput);
+ return m;
+}
+
+static void
+tulip_txput_setup(
+ tulip_softc_t * const sc)
+{
+ tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
+ tulip_desc_t *nextout;
+
+ /*
+ * We will transmit, at most, one setup packet per call to ifstart.
+ */
+
+#if defined(TULIP_DEBUG)
+ if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
+ printf("%s%d: txput_setup: tx not running\n",
+ sc->tulip_name, sc->tulip_unit);
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+ sc->tulip_if.if_start = tulip_ifstart;
+ return;
+ }
+#endif
+ /*
+ * Try to reclaim some free descriptors..
+ */
+ if (ri->ri_free < 2)
+ tulip_tx_intr(sc);
+ if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) {
+ sc->tulip_flags |= TULIP_WANTTXSTART;
+ sc->tulip_if.if_start = tulip_ifstart;
+ return;
+ }
+ bcopy(sc->tulip_setupdata, sc->tulip_setupbuf,
+ sizeof(sc->tulip_setupbuf));
+ /*
+ * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is
+ * set and DOINGSETUP is clear doing an XOR of the two will DTRT.
+ */
+ sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP;
+ ri->ri_free--;
+ nextout = ri->ri_nextout;
+ nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
+ nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG
+ |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR;
+ if (sc->tulip_flags & TULIP_WANTHASHPERFECT)
+ nextout->d_flag |= TULIP_DFLAG_TxHASHFILT;
+ else if (sc->tulip_flags & TULIP_WANTHASHONLY)
+ nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT;
+
+ nextout->d_length2 = 0;
+ nextout->d_addr2 = 0;
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+ nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len;
+ nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr;
+ if (sc->tulip_setupmap->dm_nsegs == 2) {
+ nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len;
+ nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr;
+ }
+ TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap);
+ TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout));
+#else
+ nextout->d_length1 = sizeof(sc->tulip_setupbuf);
+ nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf);
+#endif
+
+ /*
+ * Advance the ring for the next transmit packet.
+ */
+ if (++ri->ri_nextout == ri->ri_last)
+ ri->ri_nextout = ri->ri_first;
+
+ /*
+ * Make sure the next descriptor is owned by us since it
+ * may have been set up above if we ran out of room in the
+ * ring.
+ */
+ ri->ri_nextout->d_status = 0;
+ TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t));
+ nextout->d_status = TULIP_DSTS_OWNER;
+ /*
+ * Flush the ownwership of the current descriptor
+ */
+ TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t));
+ TULIP_CSR_WRITE(sc, csr_txpoll, 1);
+ if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
+ sc->tulip_intrmask |= TULIP_STS_TXINTR;
+ TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
+ }
+}
+
+
+/*
+ * This routine is entered at splnet() (splsoftnet() on NetBSD)
+ * and thereby imposes no problems when TULIP_USE_SOFTINTR is
+ * defined or not.
+ */
+static int
+tulip_ifioctl(
+ struct ifnet * ifp,
+ u_long cmd,
+ caddr_t data)
+{
+ TULIP_PERFSTART(ifioctl)
+ tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s;
+ int error = 0;
+
+#if defined(TULIP_USE_SOFTINTR)
+ s = splnet();
+#else
+ s = splimp();
+#endif
+ switch (cmd) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR: {
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ case SIOCSIFFLAGS: {
+ tulip_addr_filter(sc); /* reinit multicast filter */
+ tulip_init(sc);
+ break;
+ }
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA: {
+ error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd);
+ break;
+ }
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI: {
+ /*
+ * Update multicast listeners
+ */
+ tulip_addr_filter(sc); /* reset multicast filtering */
+ tulip_init(sc);
+ error = 0;
+ break;
+ }
+
+ case SIOCSIFMTU:
+ /*
+ * Set the interface MTU.
+ */
+ if (ifr->ifr_mtu > ETHERMTU
+#ifdef BIG_PACKET
+ && sc->tulip_chipid != TULIP_21140
+ && sc->tulip_chipid != TULIP_21140A
+ && sc->tulip_chipid != TULIP_21041
+#endif
+ ) {
+ error = EINVAL;
+ break;
+ }
+ ifp->if_mtu = ifr->ifr_mtu;
+#ifdef BIG_PACKET
+ tulip_reset(sc);
+ tulip_init(sc);
+#endif
+ break;
+
+#ifdef SIOCGADDRROM
+ case SIOCGADDRROM: {
+ error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf));
+ break;
+ }
+#endif
+#ifdef SIOCGCHIPID
+ case SIOCGCHIPID: {
+ ifr->ifr_metric = (int) sc->tulip_chipid;
+ break;
+ }
+#endif
+ default: {
+ error = EINVAL;
+ break;
+ }
+ }
+
+ splx(s);
+ TULIP_PERFEND(ifioctl);
+ return error;
+}
+
+/*
+ * These routines gets called at device spl (from ether_output). This might
+ * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at
+ * device spl from another driver.
+ */
+
+static void
+tulip_ifstart(
+ struct ifnet * const ifp)
+{
+ TULIP_PERFSTART(ifstart)
+ tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
+
+ if (sc->tulip_if.if_flags & IFF_RUNNING) {
+
+ if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
+ tulip_txput_setup(sc);
+
+ while (sc->tulip_if.if_snd.ifq_head != NULL) {
+ struct mbuf *m;
+ IF_DEQUEUE(&sc->tulip_if.if_snd, m);
+ if ((m = tulip_txput(sc, m)) != NULL) {
+ IF_PREPEND(&sc->tulip_if.if_snd, m);
+ break;
+ }
+ }
+ if (sc->tulip_if.if_snd.ifq_head == NULL)
+ sc->tulip_if.if_start = tulip_ifstart_one;
+ }
+
+ TULIP_PERFEND(ifstart);
+}
+
+static void
+tulip_ifstart_one(
+ struct ifnet * const ifp)
+{
+ TULIP_PERFSTART(ifstart_one)
+ tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
+
+ if ((sc->tulip_if.if_flags & IFF_RUNNING)
+ && sc->tulip_if.if_snd.ifq_head != NULL) {
+ struct mbuf *m;
+ IF_DEQUEUE(&sc->tulip_if.if_snd, m);
+ if ((m = tulip_txput(sc, m)) != NULL)
+ IF_PREPEND(&sc->tulip_if.if_snd, m);
+ }
+ TULIP_PERFEND(ifstart_one);
+}
+
+/*
+ * Even though this routine runs at device spl, it does not break
+ * our use of splnet (splsoftnet under NetBSD) for the majority
+ * of this driver (if TULIP_USE_SOFTINTR defined) since
+ * if_watcbog is called from if_watchdog which is called from
+ * splsoftclock which is below spl[soft]net.
+ */
+static void
+tulip_ifwatchdog(
+ struct ifnet *ifp)
+{
+ TULIP_PERFSTART(ifwatchdog)
+ tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
+
+#if defined(TULIP_DEBUG)
+ u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs;
+ if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz)
+ sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs;
+ sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs;
+#endif /* TULIP_DEBUG */
+
+ sc->tulip_if.if_timer = 1;
+ /*
+ * These should be rare so do a bulk test up front so we can just skip
+ * them if needed.
+ */
+ if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) {
+ /*
+ * If the number of receive buffer is low, try to refill
+ */
+ if (sc->tulip_flags & TULIP_RXBUFSLOW)
+ tulip_rx_intr(sc);
+
+ if (sc->tulip_flags & TULIP_SYSTEMERROR) {
+ printf("%s%d: %d system errors: last was %s\n",
+ sc->tulip_name, sc->tulip_unit, sc->tulip_system_errors,
+ tulip_system_errors[sc->tulip_last_system_error]);
+ }
+ if (sc->tulip_statusbits) {
+ tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits);
+ sc->tulip_statusbits = 0;
+ }
+
+ sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR);
+ }
+
+ if (sc->tulip_txtimer)
+ tulip_tx_intr(sc);
+ if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) {
+ printf("%s%d: transmission timeout\n", sc->tulip_name, sc->tulip_unit);
+ if (TULIP_DO_AUTOSENSE(sc)) {
+ sc->tulip_media = TULIP_MEDIA_UNKNOWN;
+ sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
+ sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP);
+ }
+ tulip_reset(sc);
+ tulip_init(sc);
+ }
+
+ TULIP_PERFEND(ifwatchdog);
+ TULIP_PERFMERGE(sc, perf_intr_cycles);
+ TULIP_PERFMERGE(sc, perf_ifstart_cycles);
+ TULIP_PERFMERGE(sc, perf_ifioctl_cycles);
+ TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles);
+ TULIP_PERFMERGE(sc, perf_timeout_cycles);
+ TULIP_PERFMERGE(sc, perf_ifstart_one_cycles);
+ TULIP_PERFMERGE(sc, perf_txput_cycles);
+ TULIP_PERFMERGE(sc, perf_txintr_cycles);
+ TULIP_PERFMERGE(sc, perf_rxintr_cycles);
+ TULIP_PERFMERGE(sc, perf_rxget_cycles);
+ TULIP_PERFMERGE(sc, perf_intr);
+ TULIP_PERFMERGE(sc, perf_ifstart);
+ TULIP_PERFMERGE(sc, perf_ifioctl);
+ TULIP_PERFMERGE(sc, perf_ifwatchdog);
+ TULIP_PERFMERGE(sc, perf_timeout);
+ TULIP_PERFMERGE(sc, perf_ifstart_one);
+ TULIP_PERFMERGE(sc, perf_txput);
+ TULIP_PERFMERGE(sc, perf_txintr);
+ TULIP_PERFMERGE(sc, perf_rxintr);
+ TULIP_PERFMERGE(sc, perf_rxget);
+}
+
+/*
+ * All printf's are real as of now!
+ */
+#ifdef printf
+#undef printf
+#endif
+
+static void
+tulip_attach(
+ tulip_softc_t * const sc)
+{
+ struct ifnet * const ifp = &sc->tulip_if;
+
+ ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST;
+ ifp->if_ioctl = tulip_ifioctl;
+ ifp->if_start = tulip_ifstart;
+ ifp->if_watchdog = tulip_ifwatchdog;
+ ifp->if_timer = 1;
+ ifp->if_output = ether_output;
+ ifp->if_init = tulip_ifinit;
+
+ printf("%s%d: %s%s pass %d.%d%s\n",
+ sc->tulip_name, sc->tulip_unit,
+ sc->tulip_boardid,
+ tulip_chipdescs[sc->tulip_chipid],
+ (sc->tulip_revinfo & 0xF0) >> 4,
+ sc->tulip_revinfo & 0x0F,
+ (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM))
+ == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : "");
+ printf("%s%d: address %6D\n",
+ sc->tulip_name, sc->tulip_unit, sc->tulip_enaddr, ":");
+
+#if defined(__alpha__)
+ /*
+ * In case the SRM console told us about a bogus media,
+ * we need to check to be safe.
+ */
+ if (sc->tulip_mediums[sc->tulip_media] == NULL)
+ sc->tulip_media = TULIP_MEDIA_UNKNOWN;
+#endif
+
+ (*sc->tulip_boardsw->bd_media_probe)(sc);
+ ifmedia_init(&sc->tulip_ifmedia, 0,
+ tulip_ifmedia_change,
+ tulip_ifmedia_status);
+ sc->tulip_flags &= ~TULIP_DEVICEPROBE;
+ tulip_ifmedia_add(sc);
+
+ tulip_reset(sc);
+
+ ether_ifattach(&(sc)->tulip_if, ETHER_BPF_SUPPORTED);
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+}
+
+#if defined(TULIP_BUS_DMA)
+#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX)
+static int
+tulip_busdma_allocmem(
+ tulip_softc_t * const sc,
+ size_t size,
+ bus_dmamap_t *map_p,
+ tulip_desc_t **desc_p)
+{
+ bus_dma_segment_t segs[1];
+ int nsegs, error;
+ error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, PAGE_SIZE,
+ segs, sizeof(segs)/sizeof(segs[0]),
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error == 0) {
+ void *desc;
+ error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size,
+ (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ if (error == 0) {
+ bus_dmamap_t map;
+ error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0,
+ BUS_DMA_NOWAIT, &map);
+ if (error == 0) {
+ error = bus_dmamap_load(sc->tulip_dmatag, map, desc,
+ size, NULL, BUS_DMA_NOWAIT);
+ if (error)
+ bus_dmamap_destroy(sc->tulip_dmatag, map);
+ else
+ *map_p = map;
+ }
+ if (error)
+ bus_dmamem_unmap(sc->tulip_dmatag, desc, size);
+ }
+ if (error)
+ bus_dmamem_free(sc->tulip_dmatag, segs, nsegs);
+ else
+ *desc_p = desc;
+ }
+ return error;
+}
+#endif
+
+static int
+tulip_busdma_init(
+ tulip_softc_t * const sc)
+{
+ int error = 0;
+
+#if !defined(TULIP_BUS_DMA_NOTX)
+ /*
+ * Allocate dmamap for setup descriptor
+ */
+ error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2,
+ sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT,
+ &sc->tulip_setupmap);
+ if (error == 0) {
+ error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap,
+ sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf),
+ NULL, BUS_DMA_NOWAIT);
+ if (error)
+ bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap);
+ }
+ /*
+ * Allocate space and dmamap for transmit ring
+ */
+ if (error == 0) {
+ error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS,
+ &sc->tulip_txdescmap,
+ &sc->tulip_txdescs);
+ }
+
+ /*
+ * Allocate dmamaps for each transmit descriptors
+ */
+ if (error == 0) {
+ while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) {
+ bus_dmamap_t map;
+ if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0)
+ sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
+ }
+ if (error) {
+ while (sc->tulip_txmaps_free > 0)
+ bus_dmamap_destroy(sc->tulip_dmatag,
+ sc->tulip_txmaps[--sc->tulip_txmaps_free]);
+ }
+ }
+#else
+ if (error == 0) {
+ sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT);
+ if (sc->tulip_txdescs == NULL)
+ error = ENOMEM;
+ }
+#endif
+#if !defined(TULIP_BUS_DMA_NORX)
+ /*
+ * Allocate space and dmamap for receive ring
+ */
+ if (error == 0) {
+ error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS,
+ &sc->tulip_rxdescmap,
+ &sc->tulip_rxdescs);
+ }
+
+ /*
+ * Allocate dmamaps for each receive descriptors
+ */
+ if (error == 0) {
+ while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) {
+ bus_dmamap_t map;
+ if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0)
+ sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
+ }
+ if (error) {
+ while (sc->tulip_rxmaps_free > 0)
+ bus_dmamap_destroy(sc->tulip_dmatag,
+ sc->tulip_rxmaps[--sc->tulip_rxmaps_free]);
+ }
+ }
+#else
+ if (error == 0) {
+ sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT);
+ if (sc->tulip_rxdescs == NULL)
+ error = ENOMEM;
+ }
+#endif
+ return error;
+}
+#endif /* TULIP_BUS_DMA */
+
+static void
+tulip_initcsrs(
+ tulip_softc_t * const sc,
+ tulip_csrptr_t csr_base,
+ size_t csr_size)
+{
+ sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size;
+ sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size;
+ sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size;
+ sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size;
+ sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size;
+ sc->tulip_csrs.csr_status = csr_base + 5 * csr_size;
+ sc->tulip_csrs.csr_command = csr_base + 6 * csr_size;
+ sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size;
+ sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size;
+ sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size;
+ sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size;
+ sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size;
+ sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size;
+ sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size;
+ sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size;
+ sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size;
+}
+
+static void
+tulip_initring(
+ tulip_softc_t * const sc,
+ tulip_ringinfo_t * const ri,
+ tulip_desc_t *descs,
+ int ndescs)
+{
+ ri->ri_max = ndescs;
+ ri->ri_first = descs;
+ ri->ri_last = ri->ri_first + ri->ri_max;
+ bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max);
+ ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING;
+}
+
+/*
+ * This is the PCI configuration support.
+ */
+
+#define PCI_CBIO 0x10 /* Configuration Base IO Address */
+#define PCI_CBMA 0x14 /* Configuration Base Memory Address */
+#define PCI_CFDA 0x40 /* Configuration Driver Area */
+
+static int
+tulip_pci_probe(device_t dev)
+{
+ const char *name = NULL;
+
+ if (pci_get_vendor(dev) != DEC_VENDORID)
+ return ENXIO;
+
+ /*
+ * Some LanMedia WAN cards use the Tulip chip, but they have
+ * their own driver, and we should not recognize them
+ */
+ if (pci_get_subvendor(dev) == 0x1376)
+ return ENXIO;
+
+ switch (pci_get_device(dev)) {
+ case CHIPID_21040:
+ name = "Digital 21040 Ethernet";
+ break;
+ case CHIPID_21041:
+ name = "Digital 21041 Ethernet";
+ break;
+ case CHIPID_21140:
+ if (pci_get_revid(dev) >= 0x20)
+ name = "Digital 21140A Fast Ethernet";
+ else
+ name = "Digital 21140 Fast Ethernet";
+ break;
+ case CHIPID_21142:
+ if (pci_get_revid(dev) >= 0x20)
+ name = "Digital 21143 Fast Ethernet";
+ else
+ name = "Digital 21142 Fast Ethernet";
+ break;
+ }
+ if (name) {
+ device_set_desc(dev, name);
+ return -200;
+ }
+ return ENXIO;
+}
+
+static int
+tulip_shutdown(device_t dev)
+{
+ tulip_softc_t * const sc = device_get_softc(dev);
+ TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at
+ 33MHz that comes to two microseconds but wait a
+ bit longer anyways) */
+ return 0;
+}
+
+static int
+tulip_pci_attach(device_t dev)
+{
+ tulip_softc_t *sc;
+#if defined(__alpha__)
+ tulip_media_t media = TULIP_MEDIA_UNKNOWN;
+#endif
+ int retval, idx;
+ u_int32_t revinfo, cfdainfo, cfcsinfo;
+ unsigned csroffset = TULIP_PCI_CSROFFSET;
+ unsigned csrsize = TULIP_PCI_CSRSIZE;
+ tulip_csrptr_t csr_base;
+ tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN;
+ struct resource *res;
+ int rid, unit;
+
+ unit = device_get_unit(dev);
+
+ if (unit >= TULIP_MAX_DEVICES) {
+ printf("de%d", unit);
+ printf(": not configured; limit of %d reached or exceeded\n",
+ TULIP_MAX_DEVICES);
+ return ENXIO;
+ }
+
+ revinfo = pci_get_revid(dev);
+ cfdainfo = pci_read_config(dev, PCI_CFDA, 4);
+ cfcsinfo = pci_read_config(dev, PCIR_COMMAND, 4);
+
+ /* turn busmaster on in case BIOS doesn't set it */
+ if(!(cfcsinfo & PCIM_CMD_BUSMASTEREN)) {
+ cfcsinfo |= PCIM_CMD_BUSMASTEREN;
+ pci_write_config(dev, PCIR_COMMAND, cfcsinfo, 4);
+ }
+
+ if (pci_get_vendor(dev) == DEC_VENDORID) {
+ if (pci_get_device(dev) == CHIPID_21040)
+ chipid = TULIP_21040;
+ else if (pci_get_device(dev) == CHIPID_21041)
+ chipid = TULIP_21041;
+ else if (pci_get_device(dev) == CHIPID_21140)
+ chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140;
+ else if (pci_get_device(dev) == CHIPID_21142)
+ chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142;
+ }
+ if (chipid == TULIP_CHIPID_UNKNOWN)
+ return ENXIO;
+
+ if (chipid == TULIP_21040 && revinfo < 0x20) {
+ printf("de%d", unit);
+ printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n",
+ revinfo >> 4, revinfo & 0x0f);
+ return ENXIO;
+ } else if (chipid == TULIP_21140 && revinfo < 0x11) {
+ printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n",
+ unit, revinfo >> 4, revinfo & 0x0f);
+ return ENXIO;
+ }
+
+ sc = device_get_softc(dev);
+ sc->tulip_pci_busno = pci_get_bus(dev);
+ sc->tulip_pci_devno = pci_get_slot(dev);
+ sc->tulip_chipid = chipid;
+ sc->tulip_flags |= TULIP_DEVICEPROBE;
+ if (chipid == TULIP_21140 || chipid == TULIP_21140A)
+ sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD;
+ if (chipid == TULIP_21140A && revinfo <= 0x22)
+ sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW;
+ if (chipid == TULIP_21140)
+ sc->tulip_features |= TULIP_HAVE_BROKEN_HASH;
+ if (chipid != TULIP_21040 && chipid != TULIP_21140)
+ sc->tulip_features |= TULIP_HAVE_POWERMGMT;
+ if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) {
+ sc->tulip_features |= TULIP_HAVE_DUALSENSE;
+ if (chipid != TULIP_21041 || revinfo >= 0x20)
+ sc->tulip_features |= TULIP_HAVE_SIANWAY;
+ if (chipid != TULIP_21041)
+ sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD;
+ if (chipid != TULIP_21041 && revinfo >= 0x20)
+ sc->tulip_features |= TULIP_HAVE_SIA100;
+ }
+
+ if (sc->tulip_features & TULIP_HAVE_POWERMGMT
+ && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) {
+ cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE);
+ pci_write_config(dev, PCI_CFDA, cfdainfo, 4);
+ DELAY(11*1000);
+ }
+#if defined(__alpha__)
+ /*
+ * The Alpha SRM console encodes a console set media in the driver
+ * part of the CFDA register. Note that the Multia presents a
+ * problem in that its BNC mode is really EXTSIA. So in that case
+ * force a probe.
+ */
+ switch ((cfdainfo >> 8) & 0xff) {
+ case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break;
+ case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break;
+ case 3: media = TULIP_MEDIA_10BASET; break;
+ case 4: media = TULIP_MEDIA_10BASET_FD; break;
+ case 5: media = TULIP_MEDIA_100BASETX; break;
+ case 6: media = TULIP_MEDIA_100BASETX_FD; break;
+ default: media = TULIP_MEDIA_UNKNOWN; break;
+ }
+#endif
+
+ sc->tulip_unit = unit;
+ sc->tulip_name = "de";
+ sc->tulip_revinfo = revinfo;
+ sc->tulip_if.if_softc = sc;
+#if defined(TULIP_IOMAPPED)
+ rid = PCI_CBIO;
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+#else
+ rid = PCI_CBMA;
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+#endif
+ if (!res)
+ return ENXIO;
+ sc->tulip_csrs_bst = rman_get_bustag(res);
+ sc->tulip_csrs_bsh = rman_get_bushandle(res);
+ csr_base = 0;
+
+ tulips[unit] = sc;
+
+ tulip_initcsrs(sc, csr_base + csroffset, csrsize);
+
+#if defined(TULIP_BUS_DMA)
+ if ((retval = tulip_busdma_init(sc)) != 0) {
+ printf("error initing bus_dma: %d\n", retval);
+ return ENXIO;
+ }
+#else
+ sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT);
+ sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT);
+ if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) {
+ printf("malloc failed\n");
+ if (sc->tulip_rxdescs)
+ free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
+ if (sc->tulip_txdescs)
+ free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
+ return ENXIO;
+ }
+#endif
+
+ tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS);
+ tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS);
+
+ /*
+ * Make sure there won't be any interrupts or such...
+ */
+ TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at
+ 33MHz that comes to two microseconds but wait a
+ bit longer anyways) */
+
+ if ((retval = tulip_read_macaddr(sc)) < 0) {
+ printf("%s%d", sc->tulip_name, sc->tulip_unit);
+ printf(": can't read ENET ROM (why=%d) (", retval);
+ for (idx = 0; idx < 32; idx++)
+ printf("%02x", sc->tulip_rombuf[idx]);
+ printf("\n");
+ printf("%s%d: %s%s pass %d.%d\n",
+ sc->tulip_name, sc->tulip_unit,
+ sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid],
+ (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F);
+ printf("%s%d: address unknown\n", sc->tulip_name, sc->tulip_unit);
+ } else {
+ int s;
+ void (*intr_rtn)(void *) = tulip_intr_normal;
+
+ if (sc->tulip_features & TULIP_HAVE_SHAREDINTR)
+ intr_rtn = tulip_intr_shared;
+
+ if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
+ void *ih;
+
+ rid = 0;
+ res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET,
+ intr_rtn, sc, &ih)) {
+ printf("%s%d: couldn't map interrupt\n",
+ sc->tulip_name, sc->tulip_unit);
+ free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
+ free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
+ return ENXIO;
+ }
+ }
+#if defined(TULIP_USE_SOFTINTR)
+ if (sc->tulip_unit > tulip_softintr_max_unit)
+ tulip_softintr_max_unit = sc->tulip_unit;
+#endif
+
+ s = splimp();
+#if defined(__alpha__)
+ sc->tulip_media = media;
+#endif
+ tulip_attach(sc);
+#if defined(__alpha__)
+ if (sc->tulip_media != TULIP_MEDIA_UNKNOWN)
+ tulip_linkup(sc, media);
+#endif
+ splx(s);
+ }
+ return 0;
+}
+
+static device_method_t tulip_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tulip_pci_probe),
+ DEVMETHOD(device_attach, tulip_pci_attach),
+ DEVMETHOD(device_shutdown, tulip_shutdown),
+ { 0, 0 }
+};
+static driver_t tulip_pci_driver = {
+ "de",
+ tulip_pci_methods,
+ sizeof(tulip_softc_t),
+};
+static devclass_t tulip_devclass;
+DRIVER_MODULE(if_de, pci, tulip_pci_driver, tulip_devclass, 0, 0);
diff --git a/sys/pci/if_devar.h b/sys/pci/if_devar.h
new file mode 100644
index 0000000..f9e63b3
--- /dev/null
+++ b/sys/pci/if_devar.h
@@ -0,0 +1,924 @@
+/* $NetBSD: if_devar.h,v 1.32 1999/04/01 14:55:25 tsubai Exp $ */
+
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
+ * 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. 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Id: if_devar.h,v 1.28 1997/07/03 16:55:07 thomas Exp
+ */
+
+#if !defined(_DEVAR_H)
+#define _DEVAR_H
+
+typedef bus_addr_t tulip_csrptr_t;
+
+#define TULIP_PCI_CSRSIZE 8
+#define TULIP_PCI_CSROFFSET 0
+
+#define TULIP_CSR_READ(sc, csr) \
+ bus_space_read_4((sc)->tulip_csrs_bst, \
+ (sc)->tulip_csrs_bsh, \
+ (sc)->tulip_csrs.csr)
+#define TULIP_CSR_WRITE(sc, csr, val) \
+ bus_space_write_4((sc)->tulip_csrs_bst, \
+ (sc)->tulip_csrs_bsh, \
+ (sc)->tulip_csrs.csr, val)
+
+#define TULIP_CSR_READBYTE(sc, csr) \
+ bus_space_read_1((sc)->tulip_csrs_bst, \
+ (sc)->tulip_csrs_bsh, \
+ (sc)->tulip_csrs.csr)
+#define TULIP_CSR_WRITEBYTE(sc, csr, val) \
+ bus_space_write_1((sc)->tulip_csrs_bst, \
+ (sc)->tulip_csrs_bsh, \
+ (sc)->tulip_csrs.csr, val)
+
+/*
+ * This structure contains "pointers" for the registers on
+ * the various 21x4x chips. CSR0 through CSR8 are common
+ * to all chips. After that, it gets messy...
+ */
+typedef struct {
+ tulip_csrptr_t csr_busmode; /* CSR0 */
+ tulip_csrptr_t csr_txpoll; /* CSR1 */
+ tulip_csrptr_t csr_rxpoll; /* CSR2 */
+ tulip_csrptr_t csr_rxlist; /* CSR3 */
+ tulip_csrptr_t csr_txlist; /* CSR4 */
+ tulip_csrptr_t csr_status; /* CSR5 */
+ tulip_csrptr_t csr_command; /* CSR6 */
+ tulip_csrptr_t csr_intr; /* CSR7 */
+ tulip_csrptr_t csr_missed_frames; /* CSR8 */
+ tulip_csrptr_t csr_9; /* CSR9 */
+ tulip_csrptr_t csr_10; /* CSR10 */
+ tulip_csrptr_t csr_11; /* CSR11 */
+ tulip_csrptr_t csr_12; /* CSR12 */
+ tulip_csrptr_t csr_13; /* CSR13 */
+ tulip_csrptr_t csr_14; /* CSR14 */
+ tulip_csrptr_t csr_15; /* CSR15 */
+} tulip_regfile_t;
+
+#define csr_enetrom csr_9 /* 21040 */
+#define csr_reserved csr_10 /* 21040 */
+#define csr_full_duplex csr_11 /* 21040 */
+#define csr_bootrom csr_10 /* 21041/21140A/?? */
+#define csr_gp csr_12 /* 21140* */
+#define csr_watchdog csr_15 /* 21140* */
+#define csr_gp_timer csr_11 /* 21041/21140* */
+#define csr_srom_mii csr_9 /* 21041/21140* */
+#define csr_sia_status csr_12 /* 2104x */
+#define csr_sia_connectivity csr_13 /* 2104x */
+#define csr_sia_tx_rx csr_14 /* 2104x */
+#define csr_sia_general csr_15 /* 2104x */
+
+/*
+ * While 21x4x allows chaining of its descriptors, this driver
+ * doesn't take advantage of it. We keep the descriptors in a
+ * traditional FIFO ring.
+ */
+typedef struct {
+ tulip_desc_t *ri_first; /* first entry in ring */
+ tulip_desc_t *ri_last; /* one after last entry */
+ tulip_desc_t *ri_nextin; /* next to processed by host */
+ tulip_desc_t *ri_nextout; /* next to processed by adapter */
+ int ri_max;
+ int ri_free;
+} tulip_ringinfo_t;
+
+/*
+ * The 21040 has a stupid restriction in that the receive
+ * buffers must be longword aligned. But since Ethernet
+ * headers are not a multiple of longwords in size this forces
+ * the data to non-longword aligned. Since IP requires the
+ * data to be longword aligned, we need to copy it after it has
+ * been DMA'ed in our memory.
+ *
+ * Since we have to copy it anyways, we might as well as allocate
+ * dedicated receive space for the input. This allows to use a
+ * small receive buffer size and more ring entries to be able to
+ * better keep with a flood of tiny Ethernet packets.
+ *
+ * The receive space MUST ALWAYS be a multiple of the page size.
+ * And the number of receive descriptors multiplied by the size
+ * of the receive buffers must equal the recevive space. This
+ * is so that we can manipulate the page tables so that even if a
+ * packet wraps around the end of the receive space, we can
+ * treat it as virtually contiguous.
+ *
+ * The above used to be true (the stupid restriction is still true)
+ * but we gone to directly DMA'ing into MBUFs (unless it's on an
+ * architecture which can't handle unaligned accesses) because with
+ * 100Mb/s cards the copying is just too much of a hit.
+ */
+#if !defined(__i386__)
+#define TULIP_COPY_RXDATA 1
+#endif
+
+#define TULIP_DATA_PER_DESC 2032
+#define TULIP_TXTIMER 4
+#define TULIP_RXDESCS 48
+#define TULIP_TXDESCS 128
+#define TULIP_RXQ_TARGET 32
+#if TULIP_RXQ_TARGET >= TULIP_RXDESCS
+#error TULIP_RXQ_TARGET must be less than TULIP_RXDESCS
+#endif
+#define TULIP_RX_BUFLEN ((MCLBYTES < 2048 ? MCLBYTES : 2048) - 16)
+
+/*
+ * Forward reference to make C happy.
+ */
+typedef struct _tulip_softc_t tulip_softc_t;
+
+/*
+ * The various controllers support.
+ */
+
+typedef enum {
+ TULIP_21040,
+ TULIP_21041,
+ TULIP_21140, TULIP_21140A, TULIP_21142,
+ TULIP_21143,
+ TULIP_CHIPID_UNKNOWN
+} tulip_chipid_t;
+
+/*
+ * Various physical media types supported.
+ * BNCAUI is BNC or AUI since on the 21040 you can't really tell
+ * which is in use.
+ */
+typedef enum {
+ TULIP_MEDIA_UNKNOWN,
+ TULIP_MEDIA_10BASET,
+ TULIP_MEDIA_10BASET_FD,
+ TULIP_MEDIA_BNC,
+ TULIP_MEDIA_AUI,
+ TULIP_MEDIA_EXTSIA,
+ TULIP_MEDIA_AUIBNC,
+ TULIP_MEDIA_100BASETX,
+ TULIP_MEDIA_100BASETX_FD,
+ TULIP_MEDIA_100BASET4,
+ TULIP_MEDIA_100BASEFX,
+ TULIP_MEDIA_100BASEFX_FD,
+ TULIP_MEDIA_MAX
+} tulip_media_t;
+
+#define TULIP_BIT(b) (1L << ((int)(b)))
+#define TULIP_FDBIT(m) (1L << ((int)TULIP_MEDIA_ ## m ## _FD))
+#define TULIP_MBIT(m) (1L << ((int)TULIP_MEDIA_ ## m ))
+#define TULIP_IS_MEDIA_FD(m) (TULIP_BIT(m) & \
+ (TULIP_FDBIT(10BASET) \
+ |TULIP_FDBIT(100BASETX) \
+ |TULIP_FDBIT(100BASEFX)))
+#define TULIP_CAN_MEDIA_FD(m) (TULIP_BIT(m) & \
+ (TULIP_MBIT(10BASET) \
+ |TULIP_MBIT(100BASETX) \
+ |TULIP_MBIT(100BASEFX)))
+#define TULIP_FD_MEDIA_OF(m) ((tulip_media_t)((m) + 1))
+#define TULIP_HD_MEDIA_OF(m) ((tulip_media_t)((m) - 1))
+#define TULIP_IS_MEDIA_100MB(m) ((m) >= TULIP_MEDIA_100BASETX)
+#define TULIP_IS_MEDIA_TP(m) ((TULIP_BIT(m) & \
+ (TULIP_MBIT(BNC) \
+ |TULIP_MBIT(AUI) \
+ |TULIP_MBIT(AUIBNC) \
+ |TULIP_MBIT(EXTSIA))) == 0)
+
+#define TULIP_SROM_ATTR_MII 0x0100
+#define TULIP_SROM_ATTR_NWAY 0x0200
+#define TULIP_SROM_ATTR_AUTOSENSE 0x0400
+#define TULIP_SROM_ATTR_POWERUP 0x0800
+#define TULIP_SROM_ATTR_NOLINKPASS 0x1000
+
+typedef struct {
+ enum {
+ TULIP_MEDIAINFO_NONE,
+ TULIP_MEDIAINFO_SIA,
+ TULIP_MEDIAINFO_GPR,
+ TULIP_MEDIAINFO_MII,
+ TULIP_MEDIAINFO_RESET,
+ TULIP_MEDIAINFO_SYM
+ } mi_type;
+ union {
+ struct {
+ u_int16_t sia_connectivity;
+ u_int16_t sia_tx_rx;
+ u_int16_t sia_general;
+ u_int32_t sia_gp_control; /* 21142/21143 */
+ u_int32_t sia_gp_data; /* 21142/21143 */
+ } un_sia;
+ struct {
+ u_int32_t gpr_cmdmode;
+ u_int32_t gpr_gpcontrol; /* 21142/21143 */
+ u_int32_t gpr_gpdata;
+ u_int8_t gpr_actmask;
+ u_int8_t gpr_actdata;
+ u_int gpr_default : 1;
+ } un_gpr;
+ struct {
+ u_int32_t mii_mediamask;
+ u_int16_t mii_capabilities;
+ u_int16_t mii_advertisement;
+ u_int16_t mii_full_duplex;
+ u_int16_t mii_tx_threshold;
+ u_int16_t mii_interrupt; /* 21142/21143 */
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_gpr_length;
+ u_int8_t mii_gpr_offset;
+ u_int8_t mii_reset_length;
+ u_int8_t mii_reset_offset;
+ u_int32_t mii_phyid;
+ } un_mii;
+ } mi_un;
+} tulip_media_info_t;
+
+#define mi_sia_connectivity mi_un.un_sia.sia_connectivity
+#define mi_sia_tx_rx mi_un.un_sia.sia_tx_rx
+#define mi_sia_general mi_un.un_sia.sia_general
+#define mi_sia_gp_control mi_un.un_sia.sia_gp_control
+#define mi_sia_gp_data mi_un.un_sia.sia_gp_data
+
+#define mi_gpcontrol mi_un.un_gpr.gpr_gpcontrol
+#define mi_gpdata mi_un.un_gpr.gpr_gpdata
+#define mi_actmask mi_un.un_gpr.gpr_actmask
+#define mi_actdata mi_un.un_gpr.gpr_actdata
+#define mi_default mi_un.un_gpr.gpr_default
+#define mi_cmdmode mi_un.un_gpr.gpr_cmdmode
+
+#define mi_phyaddr mi_un.un_mii.mii_phyaddr
+#define mi_gpr_length mi_un.un_mii.mii_gpr_length
+#define mi_gpr_offset mi_un.un_mii.mii_gpr_offset
+#define mi_reset_length mi_un.un_mii.mii_reset_length
+#define mi_reset_offset mi_un.un_mii.mii_reset_offset
+#define mi_capabilities mi_un.un_mii.mii_capabilities
+#define mi_advertisement mi_un.un_mii.mii_advertisement
+#define mi_full_duplex mi_un.un_mii.mii_full_duplex
+#define mi_tx_threshold mi_un.un_mii.mii_tx_threshold
+#define mi_mediamask mi_un.un_mii.mii_mediamask
+#define mi_mii_interrupt mi_un.un_mii.mii_interrupt
+#define mi_phyid mi_un.un_mii.mii_phyid
+
+#define TULIP_MEDIAINFO_SIA_INIT(sc, mi, chipid, media) do { \
+ (mi)->mi_type = TULIP_MEDIAINFO_SIA; \
+ sc->tulip_mediums[TULIP_MEDIA_ ## media] = (mi); \
+ (mi)->mi_sia_connectivity = TULIP_ ## chipid ## _SIACONN_ ## media; \
+ (mi)->mi_sia_tx_rx = TULIP_ ## chipid ## _SIATXRX_ ## media; \
+ (mi)->mi_sia_general = TULIP_ ## chipid ## _SIAGEN_ ## media; \
+} while (0)
+
+#define TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, media) do { \
+ if ((sc)->tulip_mediums[TULIP_MEDIA_ ## media] == NULL \
+ && ((mi)->mi_capabilities & PHYSTS_ ## media)) { \
+ (sc)->tulip_mediums[TULIP_MEDIA_ ## media] = (mi); \
+ (mi)->mi_mediamask |= TULIP_BIT(TULIP_MEDIA_ ## media); \
+ } \
+} while (0)
+
+#define TULIP_MII_NOPHY 32
+/*
+ * Some boards need to treated specially. The following enumeration
+ * identifies the cards with quirks (or those we just want to single
+ * out for special merit or scorn).
+ */
+typedef enum {
+ TULIP_21040_GENERIC, /* Generic 21040 (works with most any board) */
+ TULIP_21140_ISV, /* Digital Semicondutor 21140 ISV SROM Format */
+ TULIP_21142_ISV, /* Digital Semicondutor 21142 ISV SROM Format */
+ TULIP_21143_ISV, /* Digital Semicondutor 21143 ISV SROM Format */
+ TULIP_21140_DEC_EB, /* Digital Semicondutor 21140 Evaluation Board */
+ TULIP_21140_MII, /* 21140[A] with MII */
+ TULIP_21140_DEC_DE500, /* Digital DE500-?? 10/100 */
+ TULIP_21140_SMC_9332, /* SMC 9332 */
+ TULIP_21140_COGENT_EM100, /* Cogent EM100 100 only */
+ TULIP_21140_ZNYX_ZX34X, /* ZNYX ZX342 10/100 */
+ TULIP_21140_ASANTE, /* AsanteFast 10/100 */
+ TULIP_21140_EN1207, /* Accton EN2107 10/100 BNC */
+ TULIP_21041_GENERIC /* Generic 21041 card */
+} tulip_board_t;
+
+typedef enum {
+ TULIP_MEDIAPOLL_TIMER, /* 100ms timer fired */
+ TULIP_MEDIAPOLL_FASTTIMER, /* <100ms timer fired */
+ TULIP_MEDIAPOLL_LINKFAIL, /* called from interrupt routine */
+ TULIP_MEDIAPOLL_LINKPASS, /* called from interrupt routine */
+ TULIP_MEDIAPOLL_START, /* start a media probe (called from reset) */
+ TULIP_MEDIAPOLL_TXPROBE_OK, /* txprobe succeeded */
+ TULIP_MEDIAPOLL_TXPROBE_FAILED, /* txprobe failed */
+ TULIP_MEDIAPOLL_MAX
+} tulip_mediapoll_event_t;
+
+typedef enum {
+ TULIP_LINK_DOWN, /* Link is down */
+ TULIP_LINK_UP, /* link is ok */
+ TULIP_LINK_UNKNOWN /* we can't tell either way */
+} tulip_link_status_t;
+
+
+/*
+ * This data structure is used to abstract out the quirks.
+ * media_probe = tries to determine the media type.
+ * media_select = enables the current media (or autosenses)
+ * media_poll = autosenses media
+ * media_preset = 21140, etal requires bit to set before the
+ * the software reset; hence pre-set. Should be
+ * pre-reset but that's ugly.
+ */
+
+typedef struct {
+ tulip_board_t bd_type;
+ void (*bd_media_probe)(tulip_softc_t * const sc);
+ void (*bd_media_select)(tulip_softc_t * const sc);
+ void (*bd_media_poll)(tulip_softc_t * const sc, tulip_mediapoll_event_t event);
+ void (*bd_media_preset)(tulip_softc_t * const sc);
+} tulip_boardsw_t;
+
+/*
+ * The next few declarations are for MII/PHY based board.
+ *
+ * The first enumeration identifies a superset of various datums
+ * that can be obtained from various PHY chips. Not all PHYs will
+ * support all datums.
+ * The modedata structure indicates what register contains
+ * a datum, what mask is applied the register contents, and what the
+ * result should be.
+ * The attr structure records information about a supported PHY.
+ * The phy structure records information about a PHY instance.
+ */
+
+typedef enum {
+ PHY_MODE_10T,
+ PHY_MODE_100TX,
+ PHY_MODE_100T4,
+ PHY_MODE_FULLDUPLEX,
+ PHY_MODE_MAX
+} tulip_phy_mode_t;
+
+typedef struct {
+ u_int16_t pm_regno;
+ u_int16_t pm_mask;
+ u_int16_t pm_value;
+} tulip_phy_modedata_t;
+
+typedef struct {
+ u_int32_t attr_id;
+ u_int16_t attr_flags;
+#define PHY_NEED_HARD_RESET 0x0001
+#define PHY_DUAL_CYCLE_TA 0x0002
+ tulip_phy_modedata_t attr_modes[PHY_MODE_MAX];
+#ifdef TULIP_DEBUG
+ const char *attr_name;
+#endif
+} tulip_phy_attr_t;
+
+/*
+ * Various probe states used when trying to autosense the media.
+ */
+
+typedef enum {
+ TULIP_PROBE_INACTIVE,
+ TULIP_PROBE_PHYRESET,
+ TULIP_PROBE_PHYAUTONEG,
+ TULIP_PROBE_GPRTEST,
+ TULIP_PROBE_MEDIATEST,
+ TULIP_PROBE_FAILED
+} tulip_probe_state_t;
+
+typedef struct {
+ /*
+ * Transmit Statistics
+ */
+ u_int32_t dot3StatsSingleCollisionFrames;
+ u_int32_t dot3StatsMultipleCollisionFrames;
+ u_int32_t dot3StatsSQETestErrors;
+ u_int32_t dot3StatsDeferredTransmissions;
+ u_int32_t dot3StatsLateCollisions;
+ u_int32_t dot3StatsExcessiveCollisions;
+ u_int32_t dot3StatsCarrierSenseErrors;
+ u_int32_t dot3StatsInternalMacTransmitErrors;
+ u_int32_t dot3StatsInternalTransmitUnderflows; /* not in rfc1650! */
+ u_int32_t dot3StatsInternalTransmitBabbles; /* not in rfc1650! */
+ /*
+ * Receive Statistics
+ */
+ u_int32_t dot3StatsMissedFrames; /* not in rfc1650! */
+ u_int32_t dot3StatsAlignmentErrors;
+ u_int32_t dot3StatsFCSErrors;
+ u_int32_t dot3StatsFrameTooLongs;
+ u_int32_t dot3StatsInternalMacReceiveErrors;
+} tulip_dot3_stats_t;
+
+/*
+ * Now to important stuff. This is softc structure (where does softc
+ * come from??? No idea) for the tulip device.
+ */
+struct _tulip_softc_t {
+ struct ifmedia tulip_ifmedia;
+#if defined(TULIP_BUS_DMA)
+ bus_dma_tag_t tulip_dmatag; /* bus DMA tag */
+#if !defined(TULIP_BUS_DMA_NOTX)
+ bus_dmamap_t tulip_setupmap;
+ bus_dmamap_t tulip_txdescmap;
+ bus_dmamap_t tulip_txmaps[TULIP_TXDESCS];
+ unsigned tulip_txmaps_free;
+#endif
+#if !defined(TULIP_BUS_DMA_NORX)
+ bus_dmamap_t tulip_rxdescmap;
+ bus_dmamap_t tulip_rxmaps[TULIP_RXDESCS];
+ unsigned tulip_rxmaps_free;
+#endif
+#endif
+ struct arpcom tulip_ac;
+ bus_space_tag_t tulip_csrs_bst;
+ bus_space_handle_t tulip_csrs_bsh;
+ tulip_regfile_t tulip_csrs;
+ u_int32_t tulip_flags;
+#define TULIP_WANTSETUP 0x00000001
+#define TULIP_WANTHASHPERFECT 0x00000002
+#define TULIP_WANTHASHONLY 0x00000004
+#define TULIP_DOINGSETUP 0x00000008
+#define TULIP_PRINTMEDIA 0x00000010
+#define TULIP_TXPROBE_ACTIVE 0x00000020
+#define TULIP_ALLMULTI 0x00000040
+#define TULIP_WANTRXACT 0x00000080
+#define TULIP_RXACT 0x00000100
+#define TULIP_INRESET 0x00000200
+#define TULIP_NEEDRESET 0x00000400
+#define TULIP_SQETEST 0x00000800
+#define TULIP_xxxxxx0 0x00001000
+#define TULIP_xxxxxx1 0x00002000
+#define TULIP_WANTTXSTART 0x00004000
+#define TULIP_NEWTXTHRESH 0x00008000
+#define TULIP_NOAUTOSENSE 0x00010000
+#define TULIP_PRINTLINKUP 0x00020000
+#define TULIP_LINKUP 0x00040000
+#define TULIP_RXBUFSLOW 0x00080000
+#define TULIP_NOMESSAGES 0x00100000
+#define TULIP_SYSTEMERROR 0x00200000
+#define TULIP_TIMEOUTPENDING 0x00400000
+#define TULIP_xxxxxx2 0x00800000
+#define TULIP_TRYNWAY 0x01000000
+#define TULIP_DIDNWAY 0x02000000
+#define TULIP_RXIGNORE 0x04000000
+#define TULIP_PROBE1STPASS 0x08000000
+#define TULIP_DEVICEPROBE 0x10000000
+#define TULIP_PROMISC 0x20000000
+#define TULIP_HASHONLY 0x40000000
+#define TULIP_xxxxxx3 0x80000000
+ /* only 4 bits left! */
+ u_int32_t tulip_features; /* static bits indicating features of chip */
+#define TULIP_HAVE_GPR 0x00000001 /* have gp register (140[A]) */
+#define TULIP_HAVE_RXBADOVRFLW 0x00000002 /* RX corrupts on overflow */
+#define TULIP_HAVE_POWERMGMT 0x00000004 /* Snooze/sleep modes */
+#define TULIP_HAVE_MII 0x00000008 /* Some medium on MII */
+#define TULIP_HAVE_SIANWAY 0x00000010 /* SIA does NWAY */
+#define TULIP_HAVE_DUALSENSE 0x00000020 /* SIA senses both AUI & TP */
+#define TULIP_HAVE_SIAGP 0x00000040 /* SIA has a GP port */
+#define TULIP_HAVE_BROKEN_HASH 0x00000080 /* Broken Multicast Hash */
+#define TULIP_HAVE_ISVSROM 0x00000100 /* uses ISV SROM Format */
+#define TULIP_HAVE_BASEROM 0x00000200 /* Board ROM can be cloned */
+#define TULIP_HAVE_SLAVEDROM 0x00000400 /* Board ROM cloned */
+#define TULIP_HAVE_SLAVEDINTR 0x00000800 /* Board slaved interrupt */
+#define TULIP_HAVE_SHAREDINTR 0x00001000 /* Board shares interrupts */
+#define TULIP_HAVE_OKROM 0x00002000 /* ROM was recognized */
+#define TULIP_HAVE_NOMEDIA 0x00004000 /* did not detect any media */
+#define TULIP_HAVE_STOREFWD 0x00008000 /* have CMD_STOREFWD */
+#define TULIP_HAVE_SIA100 0x00010000 /* has LS100 in SIA status */
+#define TULIP_HAVE_OKSROM 0x00020000 /* SROM CRC is OK */
+ u_int32_t tulip_intrmask; /* our copy of csr_intr */
+ u_int32_t tulip_cmdmode; /* our copy of csr_cmdmode */
+ u_int32_t tulip_last_system_error : 3; /* last system error (only value is TULIP_SYSTEMERROR is also set) */
+ u_int32_t tulip_txtimer : 2; /* transmission timer */
+ u_int32_t tulip_system_errors; /* number of system errors encountered */
+ u_int32_t tulip_statusbits; /* status bits from CSR5 that may need to be printed */
+
+ tulip_media_info_t *tulip_mediums[TULIP_MEDIA_MAX]; /* indexes into mediainfo */
+ tulip_media_t tulip_media; /* current media type */
+ u_int32_t tulip_abilities; /* remote system's abiltities (as defined in IEEE 802.3u) */
+
+ u_int8_t tulip_revinfo; /* revision of chip */
+ u_int8_t tulip_phyaddr; /* 0..31 -- address of current phy */
+ u_int8_t tulip_gpinit; /* active pins on 21140 */
+ u_int8_t tulip_gpdata; /* default gpdata for 21140 */
+
+ struct {
+ u_int8_t probe_count; /* count of probe operations */
+ int32_t probe_timeout; /* time in ms of probe timeout */
+ tulip_probe_state_t probe_state; /* current media probe state */
+ tulip_media_t probe_media; /* current media being probed */
+ u_int32_t probe_mediamask; /* medias checked */
+ u_int32_t probe_passes; /* times autosense failed */
+ u_int32_t probe_txprobes; /* txprobes attempted */
+ } tulip_probe;
+#define tulip_probe_count tulip_probe.probe_count
+#define tulip_probe_timeout tulip_probe.probe_timeout
+#define tulip_probe_state tulip_probe.probe_state
+#define tulip_probe_media tulip_probe.probe_media
+#define tulip_probe_mediamask tulip_probe.probe_mediamask
+#define tulip_probe_passes tulip_probe.probe_passes
+
+ tulip_chipid_t tulip_chipid; /* type of chip we are using */
+ const tulip_boardsw_t *tulip_boardsw; /* board/chip characteristics */
+ tulip_softc_t *tulip_slaves; /* slaved devices (ZX3xx) */
+#if defined(TULIP_DEBUG)
+ /*
+ * Debugging/Statistical information
+ */
+ struct {
+ tulip_media_t dbg_last_media;
+ u_int32_t dbg_intrs;
+ u_int32_t dbg_media_probes;
+ u_int32_t dbg_txprobe_nocarr;
+ u_int32_t dbg_txprobe_exccoll;
+ u_int32_t dbg_link_downed;
+ u_int32_t dbg_link_suspected;
+ u_int32_t dbg_link_intrs;
+ u_int32_t dbg_link_pollintrs;
+ u_int32_t dbg_link_failures;
+ u_int32_t dbg_nway_starts;
+ u_int32_t dbg_nway_failures;
+ u_int16_t dbg_phyregs[32][4];
+ u_int32_t dbg_rxlowbufs;
+ u_int32_t dbg_rxintrs;
+ u_int32_t dbg_last_rxintrs;
+ u_int32_t dbg_high_rxintrs_hz;
+ u_int32_t dbg_no_txmaps;
+ u_int32_t dbg_txput_finishes[8];
+ u_int32_t dbg_txprobes_ok[TULIP_MEDIA_MAX];
+ u_int32_t dbg_txprobes_failed[TULIP_MEDIA_MAX];
+ u_int32_t dbg_events[TULIP_MEDIAPOLL_MAX];
+ u_int32_t dbg_rxpktsperintr[TULIP_RXDESCS];
+ } tulip_dbg;
+#endif
+#if defined(TULIP_PERFSTATS)
+#define TULIP_PERF_CURRENT 0
+#define TULIP_PERF_PREVIOUS 1
+#define TULIP_PERF_TOTAL 2
+#define TULIP_PERF_MAX 3
+ struct tulip_perfstats {
+ u_quad_t perf_intr_cycles;
+ u_quad_t perf_ifstart_cycles;
+ u_quad_t perf_ifstart_one_cycles;
+ u_quad_t perf_ifioctl_cycles;
+ u_quad_t perf_ifwatchdog_cycles;
+ u_quad_t perf_timeout_cycles;
+ u_quad_t perf_txput_cycles;
+ u_quad_t perf_txintr_cycles;
+ u_quad_t perf_rxintr_cycles;
+ u_quad_t perf_rxget_cycles;
+ unsigned perf_intr;
+ unsigned perf_ifstart;
+ unsigned perf_ifstart_one;
+ unsigned perf_ifioctl;
+ unsigned perf_ifwatchdog;
+ unsigned perf_timeout;
+ unsigned perf_txput;
+ unsigned perf_txintr;
+ unsigned perf_rxintr;
+ unsigned perf_rxget;
+ } tulip_perfstats[TULIP_PERF_MAX];
+#define tulip_curperfstats tulip_perfstats[TULIP_PERF_CURRENT]
+#endif
+ struct ifqueue tulip_txq;
+ struct ifqueue tulip_rxq;
+ tulip_dot3_stats_t tulip_dot3stats;
+ tulip_ringinfo_t tulip_rxinfo;
+ tulip_ringinfo_t tulip_txinfo;
+ tulip_media_info_t tulip_mediainfo[10];
+ /*
+ * The setup buffers for sending the setup frame to the chip.
+ * one is the one being sent while the other is the one being
+ * filled.
+ */
+ u_int32_t tulip_setupbuf[192/sizeof(u_int32_t)];
+ u_int32_t tulip_setupdata[192/sizeof(u_int32_t)];
+ char tulip_boardid[16]; /* buffer for board ID */
+ u_int8_t tulip_rombuf[128];
+ u_int8_t tulip_pci_busno; /* needed for multiport boards */
+ u_int8_t tulip_pci_devno; /* needed for multiport boards */
+ u_int8_t tulip_connidx;
+ tulip_srom_connection_t tulip_conntype;
+ tulip_desc_t *tulip_rxdescs;
+ tulip_desc_t *tulip_txdescs;
+};
+
+#define TULIP_DO_AUTOSENSE(sc) (IFM_SUBTYPE((sc)->tulip_ifmedia.ifm_media) == IFM_AUTO)
+
+
+#if defined(TULIP_HDR_DATA)
+static const char * const tulip_chipdescs[] = {
+ "21040 [10Mb/s]",
+ "21041 [10Mb/s]",
+ "21140 [10-100Mb/s]",
+ "21140A [10-100Mb/s]",
+ "21142 [10-100Mb/s]",
+ "21143 [10-100Mb/s]",
+};
+
+static const char * const tulip_mediums[] = {
+ "unknown", /* TULIP_MEDIA_UNKNOWN */
+ "10baseT", /* TULIP_MEDIA_10BASET */
+ "Full Duplex 10baseT", /* TULIP_MEDIA_10BASET_FD */
+ "BNC", /* TULIP_MEDIA_BNC */
+ "AUI", /* TULIP_MEDIA_AUI */
+ "External SIA", /* TULIP_MEDIA_EXTSIA */
+ "AUI/BNC", /* TULIP_MEDIA_AUIBNC */
+ "100baseTX", /* TULIP_MEDIA_100BASET */
+ "Full Duplex 100baseTX", /* TULIP_MEDIA_100BASET_FD */
+ "100baseT4", /* TULIP_MEDIA_100BASET4 */
+ "100baseFX", /* TULIP_MEDIA_100BASEFX */
+ "Full Duplex 100baseFX", /* TULIP_MEDIA_100BASEFX_FD */
+};
+
+static const int tulip_media_to_ifmedia[] = {
+ IFM_ETHER | IFM_NONE, /* TULIP_MEDIA_UNKNOWN */
+ IFM_ETHER | IFM_10_T, /* TULIP_MEDIA_10BASET */
+ IFM_ETHER | IFM_10_T | IFM_FDX, /* TULIP_MEDIA_10BASET_FD */
+ IFM_ETHER | IFM_10_2, /* TULIP_MEDIA_BNC */
+ IFM_ETHER | IFM_10_5, /* TULIP_MEDIA_AUI */
+ IFM_ETHER | IFM_MANUAL, /* TULIP_MEDIA_EXTSIA */
+ IFM_ETHER | IFM_10_5, /* TULIP_MEDIA_AUIBNC */
+ IFM_ETHER | IFM_100_TX, /* TULIP_MEDIA_100BASET */
+ IFM_ETHER | IFM_100_TX | IFM_FDX, /* TULIP_MEDIA_100BASET_FD */
+ IFM_ETHER | IFM_100_T4, /* TULIP_MEDIA_100BASET4 */
+ IFM_ETHER | IFM_100_FX, /* TULIP_MEDIA_100BASEFX */
+ IFM_ETHER | IFM_100_FX | IFM_FDX, /* TULIP_MEDIA_100BASEFX_FD */
+};
+
+static const char * const tulip_system_errors[] = {
+ "parity error",
+ "master abort",
+ "target abort",
+ "reserved #3",
+ "reserved #4",
+ "reserved #5",
+ "reserved #6",
+ "reserved #7",
+};
+
+static const char * const tulip_status_bits[] = {
+ NULL,
+ "transmit process stopped",
+ NULL,
+ "transmit jabber timeout",
+
+ NULL,
+ "transmit underflow",
+ NULL,
+ "receive underflow",
+
+ "receive process stopped",
+ "receive watchdog timeout",
+ NULL,
+ NULL,
+
+ "link failure",
+ NULL,
+ NULL,
+};
+
+static const struct {
+ tulip_srom_connection_t sc_type;
+ tulip_media_t sc_media;
+ u_int32_t sc_attrs;
+} tulip_srom_conninfo[] = {
+ { TULIP_SROM_CONNTYPE_10BASET, TULIP_MEDIA_10BASET },
+ { TULIP_SROM_CONNTYPE_BNC, TULIP_MEDIA_BNC },
+ { TULIP_SROM_CONNTYPE_AUI, TULIP_MEDIA_AUI },
+ { TULIP_SROM_CONNTYPE_100BASETX, TULIP_MEDIA_100BASETX },
+ { TULIP_SROM_CONNTYPE_100BASET4, TULIP_MEDIA_100BASET4 },
+ { TULIP_SROM_CONNTYPE_100BASEFX, TULIP_MEDIA_100BASEFX },
+ { TULIP_SROM_CONNTYPE_MII_10BASET, TULIP_MEDIA_10BASET,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_MII_100BASETX, TULIP_MEDIA_100BASETX,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_MII_100BASET4, TULIP_MEDIA_100BASET4,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_MII_100BASEFX, TULIP_MEDIA_100BASEFX,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_10BASET_NWAY, TULIP_MEDIA_10BASET,
+ TULIP_SROM_ATTR_NWAY },
+ { TULIP_SROM_CONNTYPE_10BASET_FD, TULIP_MEDIA_10BASET_FD },
+ { TULIP_SROM_CONNTYPE_MII_10BASET_FD, TULIP_MEDIA_10BASET_FD,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_100BASETX_FD, TULIP_MEDIA_100BASETX_FD },
+ { TULIP_SROM_CONNTYPE_MII_100BASETX_FD, TULIP_MEDIA_100BASETX_FD,
+ TULIP_SROM_ATTR_MII },
+ { TULIP_SROM_CONNTYPE_10BASET_NOLINKPASS, TULIP_MEDIA_10BASET,
+ TULIP_SROM_ATTR_NOLINKPASS },
+ { TULIP_SROM_CONNTYPE_AUTOSENSE, TULIP_MEDIA_UNKNOWN,
+ TULIP_SROM_ATTR_AUTOSENSE },
+ { TULIP_SROM_CONNTYPE_AUTOSENSE_POWERUP, TULIP_MEDIA_UNKNOWN,
+ TULIP_SROM_ATTR_AUTOSENSE|TULIP_SROM_ATTR_POWERUP },
+ { TULIP_SROM_CONNTYPE_AUTOSENSE_NWAY, TULIP_MEDIA_UNKNOWN,
+ TULIP_SROM_ATTR_AUTOSENSE|TULIP_SROM_ATTR_NWAY },
+ { TULIP_SROM_CONNTYPE_NOT_USED, TULIP_MEDIA_UNKNOWN }
+};
+#define TULIP_SROM_LASTCONNIDX \
+ (sizeof(tulip_srom_conninfo)/sizeof(tulip_srom_conninfo[0]) - 1)
+
+static const struct {
+ tulip_media_t sm_type;
+ tulip_srom_media_t sm_srom_type;
+} tulip_srom_mediums[] = {
+ { TULIP_MEDIA_100BASEFX_FD, TULIP_SROM_MEDIA_100BASEFX_FD },
+ { TULIP_MEDIA_100BASEFX, TULIP_SROM_MEDIA_100BASEFX },
+ { TULIP_MEDIA_100BASET4, TULIP_SROM_MEDIA_100BASET4 },
+ { TULIP_MEDIA_100BASETX_FD, TULIP_SROM_MEDIA_100BASETX_FD },
+ { TULIP_MEDIA_100BASETX, TULIP_SROM_MEDIA_100BASETX },
+ { TULIP_MEDIA_10BASET_FD, TULIP_SROM_MEDIA_10BASET_FD },
+ { TULIP_MEDIA_AUI, TULIP_SROM_MEDIA_AUI },
+ { TULIP_MEDIA_BNC, TULIP_SROM_MEDIA_BNC },
+ { TULIP_MEDIA_10BASET, TULIP_SROM_MEDIA_10BASET },
+ { TULIP_MEDIA_UNKNOWN }
+};
+#endif /* TULIP_HDR_DATA */
+
+/*
+ * This driver supports a maximum of 32 tulip boards.
+ * This should be enough for the forseeable future.
+ */
+#define TULIP_MAX_DEVICES 32
+
+#if defined(TULIP_USE_SOFTINTR) && defined(TULIP_HDR_DATA)
+static u_int32_t tulip_softintr_mask;
+static int tulip_softintr_last_unit;
+static int tulip_softintr_max_unit;
+static void tulip_softintr(void);
+#endif
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
+#define TULIP_RXDESC_PRESYNC(sc, di, s) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (sc)->tulip_rxdescmap, \
+ (caddr_t) di - (caddr_t) (sc)->tulip_rxdescs, \
+ (s), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define TULIP_RXDESC_POSTSYNC(sc, di, s) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (sc)->tulip_rxdescmap, \
+ (caddr_t) di - (caddr_t) (sc)->tulip_rxdescs, \
+ (s), BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+#define TULIP_RXMAP_PRESYNC(sc, map) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (map), 0, (map)->dm_mapsize, \
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define TULIP_RXMAP_POSTSYNC(sc, map) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (map), 0, (map)->dm_mapsize, \
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+#define TULIP_RXMAP_CREATE(sc, mapp) \
+ bus_dmamap_create((sc)->tulip_dmatag, TULIP_RX_BUFLEN, 2, \
+ TULIP_DATA_PER_DESC, 0, \
+ BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, (mapp))
+#else
+#ifdef __alpha__
+#define TULIP_RXDESC_PRESYNC(sc, di, s) alpha_mb()
+#define TULIP_RXDESC_POSTSYNC(sc, di, s) alpha_mb()
+#define TULIP_RXMAP_PRESYNC(sc, map) alpha_mb()
+#define TULIP_RXMAP_POSTSYNC(sc, map) alpha_mb()
+#else
+#define TULIP_RXDESC_PRESYNC(sc, di, s) do { } while (0)
+#define TULIP_RXDESC_POSTSYNC(sc, di, s) do { } while (0)
+#define TULIP_RXMAP_PRESYNC(sc, map) do { } while (0)
+#define TULIP_RXMAP_POSTSYNC(sc, map) do { } while (0)
+#endif
+#define TULIP_RXMAP_CREATE(sc, mapp) do { } while (0)
+#endif
+
+#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
+#define TULIP_TXDESC_PRESYNC(sc, di, s) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (sc)->tulip_txdescmap, \
+ (caddr_t) di - (caddr_t) (sc)->tulip_txdescs, \
+ (s), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define TULIP_TXDESC_POSTSYNC(sc, di, s) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (sc)->tulip_txdescmap, \
+ (caddr_t) di - (caddr_t) (sc)->tulip_txdescs, \
+ (s), BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+#define TULIP_TXMAP_PRESYNC(sc, map) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (map), 0, (map)->dm_mapsize, \
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define TULIP_TXMAP_POSTSYNC(sc, map) \
+ bus_dmamap_sync((sc)->tulip_dmatag, (map), 0, (map)->dm_mapsize, \
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+#define TULIP_TXMAP_CREATE(sc, mapp) \
+ bus_dmamap_create((sc)->tulip_dmatag, TULIP_DATA_PER_DESC, \
+ TULIP_MAX_TXSEG, TULIP_DATA_PER_DESC, \
+ 0, BUS_DMA_NOWAIT, (mapp))
+#else
+#ifdef __alpha__
+#define TULIP_TXDESC_PRESYNC(sc, di, s) alpha_mb()
+#define TULIP_TXDESC_POSTSYNC(sc, di, s) alpha_mb()
+#define TULIP_TXMAP_PRESYNC(sc, map) alpha_mb()
+#define TULIP_TXMAP_POSTSYNC(sc, map) alpha_mb()
+#else
+#define TULIP_TXDESC_PRESYNC(sc, di, s) do { } while (0)
+#define TULIP_TXDESC_POSTSYNC(sc, di, s) do { } while (0)
+#define TULIP_TXMAP_PRESYNC(sc, map) do { } while (0)
+#define TULIP_TXMAP_POSTSYNC(sc, map) do { } while (0)
+#endif
+#define TULIP_TXMAP_CREATE(sc, mapp) do { } while (0)
+#endif
+
+#ifdef notyet
+#define SIOCGADDRROM _IOW('i', 240, struct ifreq) /* get 128 bytes of ROM */
+#define SIOCGCHIPID _IOWR('i', 241, struct ifreq) /* get chipid */
+#endif
+
+#if defined(TULIP_HDR_DATA)
+static tulip_softc_t *tulips[TULIP_MAX_DEVICES];
+#endif
+
+#if defined(TULIP_USE_SOFTINTR)
+NETISR_SET(NETISR_DE, tulip_softintr);
+#endif
+
+#define loudprintf if (bootverbose) printf
+
+#ifndef tulip_if
+#define tulip_if tulip_ac.ac_if
+#endif
+#ifndef tulip_unit
+#define tulip_unit tulip_if.if_unit
+#endif
+#define tulip_name tulip_if.if_name
+#ifndef tulip_enaddr
+#define tulip_enaddr tulip_ac.ac_enaddr
+#endif
+
+#if !defined(TULIP_KVATOPHYS) && (!defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NORX) || defined(TULIP_BUS_DMA_NOTX))
+#if defined(__alpha__)
+/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
+#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va)
+#else
+#define vtobus(va) vtophys(va)
+#endif
+#define TULIP_KVATOPHYS(sc, va) vtobus(va)
+#endif
+
+#if defined(TULIP_PERFSTATS)
+#define TULIP_PERFMERGE(sc, member) \
+ do { (sc)->tulip_perfstats[TULIP_PERF_TOTAL].member \
+ += (sc)->tulip_perfstats[TULIP_PERF_CURRENT].member; \
+ (sc)->tulip_perfstats[TULIP_PERF_PREVIOUS].member \
+ = (sc)->tulip_perfstats[TULIP_PERF_CURRENT].member; \
+ (sc)->tulip_perfstats[TULIP_PERF_CURRENT].member = 0; } while (0)
+#define TULIP_PERFSTART(name) const tulip_cycle_t perfstart_ ## name = TULIP_PERFREAD();
+#define TULIP_PERFEND(name) do { \
+ (sc)->tulip_curperfstats.perf_ ## name ## _cycles += TULIP_PERFDIFF(perfstart_ ## name, TULIP_PERFREAD()); \
+ (sc)->tulip_curperfstats.perf_ ## name ++; \
+ } while (0)
+#if defined(__i386__)
+typedef u_quad_t tulip_cycle_t;
+static __inline__ tulip_cycle_t
+TULIP_PERFREAD(
+ void)
+{
+ tulip_cycle_t x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+#define TULIP_PERFDIFF(s, f) ((f) - (s))
+#elif defined(__alpha__)
+typedef unsigned long tulip_cycle_t;
+static __inline__ tulip_cycle_t
+TULIP_PERFREAD(
+ void)
+{
+ tulip_cycle_t x;
+ __asm__ volatile ("rpcc %0" : "=r" (x));
+ return x;
+}
+#define TULIP_PERFDIFF(s, f) ((unsigned int) ((f) - (s)))
+#endif
+#else
+#define TULIP_PERFSTART(name)
+#define TULIP_PERFEND(name) do { } while (0)
+#define TULIP_PERFMERGE(s,n) do { } while (0)
+#endif /* TULIP_PERFSTATS */
+
+#define TULIP_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- Little Endian */
+#define TULIP_MAX_TXSEG 30
+
+#define TULIP_ADDREQUAL(a1, a2) \
+ (((u_int16_t *)a1)[0] == ((u_int16_t *)a2)[0] \
+ && ((u_int16_t *)a1)[1] == ((u_int16_t *)a2)[1] \
+ && ((u_int16_t *)a1)[2] == ((u_int16_t *)a2)[2])
+#define TULIP_ADDRBRDCST(a1) \
+ (((u_int16_t *)a1)[0] == 0xFFFFU \
+ && ((u_int16_t *)a1)[1] == 0xFFFFU \
+ && ((u_int16_t *)a1)[2] == 0xFFFFU)
+
+#endif /* !defined(_DEVAR_H) */
diff --git a/sys/pci/if_en_pci.c b/sys/pci/if_en_pci.c
new file mode 100644
index 0000000..4b99da7
--- /dev/null
+++ b/sys/pci/if_en_pci.c
@@ -0,0 +1,485 @@
+/* $NetBSD: if_en_pci.c,v 1.1 1996/06/22 02:00:31 chuck Exp $ */
+
+/*
+ *
+ * Copyright (c) 1996 Charles D. Cranor and Washington University.
+ * 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 Charles D. Cranor and
+ * Washington University.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ *
+ * i f _ e n _ p c i . c
+ *
+ * author: Chuck Cranor <chuck@ccrc.wustl.edu>
+ * started: spring, 1996.
+ *
+ * FreeBSD PCI glue for the eni155p card.
+ * thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <net/if.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/en/midwayreg.h>
+#include <dev/en/midwayvar.h>
+
+/*
+ * prototypes
+ */
+
+static int en_pci_probe(device_t);
+static int en_pci_attach(device_t);
+static int en_pci_detach(device_t);
+static int en_pci_shutdown(device_t);
+
+/*
+ * local structures
+ */
+
+struct en_pci_softc {
+ /* bus independent stuff */
+ struct en_softc esc; /* includes "device" structure */
+
+ /* freebsd newbus glue */
+ struct resource *res; /* resource descriptor for registers */
+ struct resource *irq; /* resource descriptor for interrupt */
+ void *ih; /* interrupt handle */
+};
+
+#if !defined(MIDWAY_ENIONLY)
+static void eni_get_macaddr(device_t, struct en_pci_softc *);
+#endif
+#if !defined(MIDWAY_ADPONLY)
+static void adp_get_macaddr(struct en_pci_softc *);
+#endif
+
+/*
+ * local defines (PCI specific stuff)
+ */
+
+/*
+ * address of config base memory address register in PCI config space
+ * (this is card specific)
+ */
+
+#define PCI_CBMA 0x10
+
+/*
+ * tonga (pci bridge). ENI cards only!
+ */
+
+#define EN_TONGA 0x60 /* PCI config addr of tonga reg */
+
+#define TONGA_SWAP_DMA 0x80 /* endian swap control */
+#define TONGA_SWAP_BYTE 0x40
+#define TONGA_SWAP_WORD 0x20
+
+/*
+ * adaptec pci bridge. ADP cards only!
+ */
+
+#define ADP_PCIREG 0x050040 /* PCI control register */
+
+#define ADP_PCIREG_RESET 0x1 /* reset card */
+#define ADP_PCIREG_IENABLE 0x2 /* interrupt enable */
+#define ADP_PCIREG_SWAP_WORD 0x4 /* swap byte on slave access */
+#define ADP_PCIREG_SWAP_DMA 0x8 /* swap byte on DMA */
+
+#define PCI_VENDOR_EFFICIENTNETS 0x111a /* Efficent Networks */
+#define PCI_PRODUCT_EFFICIENTNETS_ENI155PF 0x0000 /* ENI-155P ATM */
+#define PCI_PRODUCT_EFFICIENTNETS_ENI155PA 0x0002 /* ENI-155P ATM */
+#define PCI_VENDOR_ADP 0x9004 /* adaptec */
+#define PCI_PRODUCT_ADP_AIC5900 0x5900
+#define PCI_PRODUCT_ADP_AIC5905 0x5905
+#define PCI_VENDOR(x) ((x) & 0xFFFF)
+#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
+
+#if !defined(MIDWAY_ENIONLY)
+
+static void adp_busreset(void *);
+
+/*
+ * bus specific reset function [ADP only!]
+ */
+
+static void adp_busreset(v)
+
+void *v;
+
+{
+ struct en_softc *sc = (struct en_softc *) v;
+ u_int32_t dummy;
+
+ bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, ADP_PCIREG_RESET);
+ DELAY(1000); /* let it reset */
+ dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
+ bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
+ (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA|ADP_PCIREG_IENABLE));
+ dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
+ if ((dummy & (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA)) !=
+ (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA))
+ printf("adp_busreset: Adaptec ATM did NOT reset!\n");
+}
+#endif
+
+/***********************************************************************/
+
+/*
+ * autoconfig stuff
+ */
+
+static int
+en_pci_probe(device_t dev)
+{
+ switch (pci_get_vendor(dev)) {
+#if !defined(MIDWAY_ADPONLY)
+ case PCI_VENDOR_EFFICIENTNETS:
+ switch (pci_get_device(dev)) {
+ case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
+ case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
+ device_set_desc(dev, "Efficient Networks ENI-155p");
+ return 0;
+ }
+ break;
+#endif
+#if !defined(MIDWAY_ENIONLY)
+ case PCI_VENDOR_ADP:
+ switch (pci_get_device(dev)) {
+ case PCI_PRODUCT_ADP_AIC5900:
+ case PCI_PRODUCT_ADP_AIC5905:
+ device_set_desc(dev, "Adaptec 155 ATM");
+ return 0;
+ }
+ break;
+#endif
+ }
+ return ENXIO;
+}
+
+static int
+en_pci_attach(device_t dev)
+{
+ struct en_softc *sc;
+ struct en_pci_softc *scp;
+ u_long val;
+ int rid, s, unit, error = 0;
+
+ sc = device_get_softc(dev);
+ scp = (struct en_pci_softc *)sc;
+ bzero(scp, sizeof(*scp)); /* zero */
+
+ s = splimp();
+
+ /*
+ * Enable bus mastering.
+ */
+ val = pci_read_config(dev, PCIR_COMMAND, 2);
+ val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCIR_COMMAND, val, 2);
+
+ /*
+ * Map control/status registers.
+ */
+ rid = PCI_CBMA;
+ scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!scp->res) {
+ device_printf(dev, "could not map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->en_memt = rman_get_bustag(scp->res);
+ sc->en_base = rman_get_bushandle(scp->res);
+
+ /*
+ * Allocate our interrupt.
+ */
+ rid = 0;
+ scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (scp->irq == NULL) {
+ device_printf(dev, "could not map interrupt\n");
+ bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
+ en_intr, sc, &scp->ih);
+ if (error) {
+ device_printf(dev, "could not setup irq\n");
+ bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
+ goto fail;
+ }
+ sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
+
+ unit = device_get_unit(dev);
+ snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), "en%d", unit);
+ sc->enif.if_unit = unit;
+ sc->enif.if_name = "en";
+
+ /* figure out if we are an adaptec card or not */
+ sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
+
+ /*
+ * set up pci bridge
+ */
+#if !defined(MIDWAY_ENIONLY)
+ if (sc->is_adaptec) {
+ adp_get_macaddr(scp);
+ sc->en_busreset = adp_busreset;
+ adp_busreset(sc);
+ }
+#endif
+
+#if !defined(MIDWAY_ADPONLY)
+ if (!sc->is_adaptec) {
+ eni_get_macaddr(dev, scp);
+ sc->en_busreset = NULL;
+ pci_write_config(dev, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD), 4);
+ }
+#endif
+
+ /*
+ * done PCI specific stuff
+ */
+
+ en_attach(sc);
+
+ splx(s);
+
+ return 0;
+
+ fail:
+ splx(s);
+ return error;
+}
+
+static int
+en_pci_detach(device_t dev)
+{
+ struct en_softc *sc = device_get_softc(dev);
+ struct en_pci_softc *scp = (struct en_pci_softc *)sc;
+ int s;
+
+ s = splimp();
+
+ /*
+ * Close down routes etc.
+ */
+ if_detach(&sc->enif);
+
+ /*
+ * Stop DMA and drop transmit queue.
+ */
+ en_reset(sc);
+
+ /*
+ * Deallocate resources.
+ */
+ bus_teardown_intr(dev, scp->irq, scp->ih);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
+
+#ifdef notyet
+ /*
+ * Free all the driver internal resources
+ */
+#endif
+
+ splx(s);
+
+ return 0;
+}
+
+static int
+en_pci_shutdown(device_t dev)
+{
+ struct en_pci_softc *psc = (struct en_pci_softc *)device_get_softc(dev);
+
+ en_reset(&psc->esc);
+ DELAY(10); /* is this necessary? */
+ return (0);
+}
+
+#if !defined(MIDWAY_ENIONLY)
+
+#if defined(sparc)
+#define bus_space_read_1(t, h, o) \
+ ((void)t, (*(volatile u_int8_t *)((h) + (o))))
+#endif
+
+static void
+adp_get_macaddr(scp)
+ struct en_pci_softc *scp;
+{
+ struct en_softc * sc = (struct en_softc *)scp;
+ int lcv;
+
+ for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
+ sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
+ MID_ADPMACOFF + lcv);
+}
+
+#endif /* MIDWAY_ENIONLY */
+
+#if !defined(MIDWAY_ADPONLY)
+
+/*
+ * Read station (MAC) address from serial EEPROM.
+ * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
+ */
+#define EN_PROM_MAGIC 0x0c
+#define EN_PROM_DATA 0x02
+#define EN_PROM_CLK 0x01
+#define EN_ESI 64
+
+static void
+eni_get_macaddr(device_t dev, struct en_pci_softc *scp)
+{
+ struct en_softc * sc = (struct en_softc *)scp;
+ int i, j, address, status;
+ u_int32_t data, t_data;
+ u_int8_t tmp;
+
+ t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
+
+ data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
+ pci_write_config(dev, EN_TONGA, data, 4);
+
+ for (i = 0; i < sizeof(sc->macaddr); i ++){
+ /* start operation */
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data &= ~EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data &= ~EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ /* send address with serial line */
+ address = ((i + EN_ESI) << 1) + 1;
+ for ( j = 7 ; j >= 0 ; j --){
+ data = (address >> j) & 1 ? data | EN_PROM_DATA :
+ data & ~EN_PROM_DATA;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data &= ~EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ }
+ /* get ack */
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data = pci_read_config(dev, EN_TONGA, 4);
+ status = data & EN_PROM_DATA;
+ data &= ~EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+
+ tmp = 0;
+
+ for ( j = 7 ; j >= 0 ; j --){
+ tmp <<= 1;
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data = pci_read_config(dev, EN_TONGA, 4);
+ if(data & EN_PROM_DATA) tmp |= 1;
+ data &= ~EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ }
+ /* get ack */
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data = pci_read_config(dev, EN_TONGA, 4);
+ status = data & EN_PROM_DATA;
+ data &= ~EN_PROM_CLK ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_DATA ;
+ pci_write_config(dev, EN_TONGA, data, 4);
+
+ sc->macaddr[i] = tmp;
+ }
+ /* stop operation */
+ data &= ~EN_PROM_DATA;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_CLK;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ data |= EN_PROM_DATA;
+ pci_write_config(dev, EN_TONGA, data, 4);
+ pci_write_config(dev, EN_TONGA, t_data, 4);
+}
+
+#endif /* !MIDWAY_ADPONLY */
+
+static device_method_t en_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, en_pci_probe),
+ DEVMETHOD(device_attach, en_pci_attach),
+ DEVMETHOD(device_detach, en_pci_detach),
+ DEVMETHOD(device_shutdown, en_pci_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t en_driver = {
+ "en",
+ en_methods,
+ sizeof(struct en_pci_softc),
+};
+
+static devclass_t en_devclass;
+
+DRIVER_MODULE(if_en, pci, en_driver, en_devclass, 0, 0);
+
diff --git a/sys/pci/if_mn.c b/sys/pci/if_mn.c
new file mode 100644
index 0000000..8d19e22
--- /dev/null
+++ b/sys/pci/if_mn.c
@@ -0,0 +1,1470 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id: if_mn.c,v 1.1 1999/02/01 13:06:40 phk Exp $
+ *
+ * Driver for Siemens reference design card "Easy321-R1".
+ *
+ * This card contains a FALC54 E1/T1 framer and a MUNICH32X 32-channel HDLC
+ * controller.
+ *
+ * The driver supports E1 mode with up to 31 channels. We send CRC4 but don't
+ * check it coming in.
+ *
+ * The FALC54 and MUNICH32X have far too many registers and weird modes for
+ * comfort, so I have not bothered typing it all into a "fooreg.h" file,
+ * you will (badly!) need the documentation anyway if you want to mess with
+ * this gadget.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Stuff to describe the MUNIC32X and FALC54 chips.
+ */
+
+#define M32_CHAN 32 /* We have 32 channels */
+#define M32_TS 32 /* We have 32 timeslots */
+
+#define NG_MN_NODE_TYPE "mn"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#include "pci_if.h"
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+
+
+static int mn_maxlatency = 1000;
+SYSCTL_INT(_debug, OID_AUTO, mn_maxlatency, CTLFLAG_RW,
+ &mn_maxlatency, 0,
+ "The number of milliseconds a packet is allowed to spend in the output queue. "
+ "If the output queue is longer than this number of milliseconds when the packet "
+ "arrives for output, the packet will be dropped."
+);
+
+#ifndef NMN
+/* Most machines don't support more than 4 busmaster PCI slots, if even that many */
+#define NMN 4
+#endif
+
+/* From: PEB 20321 data sheet, p187, table 22 */
+struct m32xreg {
+ u_int32_t conf, cmd, stat, imask;
+ u_int32_t fill10, piqba, piql, fill1c;
+ u_int32_t mode1, mode2, ccba, txpoll;
+ u_int32_t tiqba, tiql, riqba, riql;
+ u_int32_t lconf, lccba, fill48, ltran;
+ u_int32_t ltiqba, ltiql, lriqba, lriql;
+ u_int32_t lreg0, lreg1, lreg2, lreg3;
+ u_int32_t lreg4, lreg5, lre6, lstat;
+ u_int32_t gpdir, gpdata, gpod, fill8c;
+ u_int32_t ssccon, sscbr, ssctb, sscrb;
+ u_int32_t ssccse, sscim, fillab, fillac;
+ u_int32_t iomcon1, iomcon2, iomstat, fillbc;
+ u_int32_t iomcit0, iomcit1, iomcir0, iomcir1;
+ u_int32_t iomtmo, iomrmo, filld8, filldc;
+ u_int32_t mbcmd, mbdata1, mbdata2, mbdata3;
+ u_int32_t mbdata4, mbdata5, mbdata6, mbdata7;
+};
+
+/* From: PEB 2254 data sheet, p80, table 10 */
+struct f54wreg {
+ u_int16_t xfifo;
+ u_int8_t cmdr, mode, rah1, rah2, ral1, ral2;
+ u_int8_t ipc, ccr1, ccr3, pre, rtr1, rtr2, rtr3, rtr4;
+ u_int8_t ttr1, ttr2, ttr3, ttr4, imr0, imr1, imr2, imr3;
+ u_int8_t imr4, fill19, fmr0, fmr1, fmr2, loop, xsw, xsp;
+ u_int8_t xc0, xc1, rc0, rc1, xpm0, xpm1, xpm2, tswm;
+ u_int8_t test1, idle, xsa4, xsa5, xsa6, xsa7, xsa8, fmr3;
+ u_int8_t icb1, icb2, icb3, icb4, lim0, lim1, pcd, pcr;
+ u_int8_t lim2, fill39[7];
+ u_int8_t fill40[8];
+ u_int8_t fill48[8];
+ u_int8_t fill50[8];
+ u_int8_t fill58[8];
+ u_int8_t dec, fill61, test2, fill63[5];
+ u_int8_t fill68[8];
+ u_int8_t xs[16];
+};
+
+/* From: PEB 2254 data sheet, p117, table 10 */
+struct f54rreg {
+ u_int16_t rfifo;
+ u_int8_t fill2, mode, rah1, rah2, ral1, ral2;
+ u_int8_t ipc, ccr1, ccr3, pre, rtr1, rtr2, rtr3, rtr4;
+ u_int8_t ttr1, ttr2, ttr3, ttr4, imr0, imr1, imr2, imr3;
+ u_int8_t imr4, fill19, fmr0, fmr1, fmr2, loop, xsw, xsp;
+ u_int8_t xc0, xc1, rc0, rc1, xpm0, xpm1, xpm2, tswm;
+ u_int8_t test, idle, xsa4, xsa5, xsa6, xsa7, xsa8, fmr13;
+ u_int8_t icb1, icb2, icb3, icb4, lim0, lim1, pcd, pcr;
+ u_int8_t lim2, fill39[7];
+ u_int8_t fill40[8];
+ u_int8_t fill48[4], frs0, frs1, rsw, rsp;
+ u_int16_t fec, cvc, cec1, ebc;
+ u_int16_t cec2, cec3;
+ u_int8_t rsa4, rsa5, rsa6, rsa7;
+ u_int8_t rsa8, rsa6s, tsr0, tsr1, sis, rsis;
+ u_int16_t rbc;
+ u_int8_t isr0, isr1, isr2, isr3, fill6c, fill6d, gis, vstr;
+ u_int8_t rs[16];
+};
+
+/* Transmit & receive descriptors */
+struct trxd {
+ u_int32_t flags;
+ vm_offset_t next;
+ vm_offset_t data;
+ u_int32_t status; /* only used for receive */
+ struct mbuf *m; /* software use only */
+ struct trxd *vnext; /* software use only */
+};
+
+/* Channel specification */
+struct cspec {
+ u_int32_t flags;
+ vm_offset_t rdesc;
+ vm_offset_t tdesc;
+ u_int32_t itbs;
+};
+
+struct m32_mem {
+ vm_offset_t csa;
+ u_int32_t ccb;
+ u_int32_t reserve1[2];
+ u_int32_t ts[M32_TS];
+ struct cspec cs[M32_CHAN];
+ vm_offset_t crxd[M32_CHAN];
+ vm_offset_t ctxd[M32_CHAN];
+};
+
+struct softc;
+struct sockaddr;
+struct rtentry;
+
+static int mn_probe (device_t self);
+static int mn_attach (device_t self);
+static void mn_create_channel(struct softc *sc, int chan);
+static int mn_reset(struct softc *sc);
+static struct trxd * mn_alloc_desc(void);
+static void mn_free_desc(struct trxd *dp);
+static void mn_intr(void *xsc);
+static u_int32_t mn_parse_ts(const char *s, int *nbit);
+#ifdef notyet
+static void m32_dump(struct softc *sc);
+static void f54_dump(struct softc *sc);
+static void mn_fmt_ts(char *p, u_int32_t ts);
+#endif /* notyet */
+static void f54_init(struct softc *sc);
+
+static ng_constructor_t ngmn_constructor;
+static ng_rcvmsg_t ngmn_rcvmsg;
+static ng_shutdown_t ngmn_shutdown;
+static ng_newhook_t ngmn_newhook;
+static ng_connect_t ngmn_connect;
+static ng_rcvdata_t ngmn_rcvdata;
+static ng_disconnect_t ngmn_disconnect;
+
+static struct ng_type mntypestruct = {
+ NG_ABI_VERSION,
+ NG_MN_NODE_TYPE,
+ NULL,
+ ngmn_constructor,
+ ngmn_rcvmsg,
+ ngmn_shutdown,
+ ngmn_newhook,
+ NULL,
+ ngmn_connect,
+ ngmn_rcvdata,
+ ngmn_disconnect,
+ NULL
+};
+
+static MALLOC_DEFINE(M_MN, "mn", "Mx driver related");
+
+#define NIQB 64
+
+struct schan {
+ enum {DOWN, UP} state;
+ struct softc *sc;
+ int chan;
+ u_int32_t ts;
+ char name[8];
+ struct trxd *r1, *rl;
+ struct trxd *x1, *xl;
+ hook_p hook;
+
+ time_t last_recv;
+ time_t last_rxerr;
+ time_t last_xmit;
+
+ u_long rx_error;
+
+ u_long short_error;
+ u_long crc_error;
+ u_long dribble_error;
+ u_long long_error;
+ u_long abort_error;
+ u_long overflow_error;
+
+ int last_error;
+ int prev_error;
+
+ u_long tx_pending;
+ u_long tx_limit;
+};
+
+enum framing {WHOKNOWS, E1, E1U, T1, T1U};
+
+struct softc {
+ int unit;
+ device_t dev;
+ struct resource *irq;
+ void *intrhand;
+ enum framing framing;
+ int nhooks;
+ void *m0v, *m1v;
+ vm_offset_t m0p, m1p;
+ struct m32xreg *m32x;
+ struct f54wreg *f54w;
+ struct f54rreg *f54r;
+ struct m32_mem m32_mem;
+ u_int32_t tiqb[NIQB];
+ u_int32_t riqb[NIQB];
+ u_int32_t piqb[NIQB];
+ u_int32_t ltiqb[NIQB];
+ u_int32_t lriqb[NIQB];
+ char name[8];
+ u_int32_t falc_irq, falc_state, framer_state;
+ struct schan *ch[M32_CHAN];
+ char nodename[NG_NODELEN + 1];
+ node_p node;
+
+ u_long cnt_fec;
+ u_long cnt_cvc;
+ u_long cnt_cec1;
+ u_long cnt_ebc;
+ u_long cnt_cec2;
+ u_long cnt_cec3;
+ u_long cnt_rbc;
+};
+
+static int
+ngmn_constructor(node_p node)
+{
+
+ return (EINVAL);
+}
+
+static int
+ngmn_shutdown(node_p nodep)
+{
+
+ return (EINVAL);
+}
+
+static void
+ngmn_config(node_p node, char *set, char *ret)
+{
+ struct softc *sc;
+ enum framing wframing;
+
+ sc = NG_NODE_PRIVATE(node);
+
+ if (set != NULL) {
+ if (!strncmp(set, "line ", 5)) {
+ wframing = sc->framing;
+ if (!strcmp(set, "line e1")) {
+ wframing = E1;
+ } else if (!strcmp(set, "line e1u")) {
+ wframing = E1U;
+ } else {
+ strcat(ret, "ENOGROK\n");
+ return;
+ }
+ if (wframing == sc->framing)
+ return;
+ if (sc->nhooks > 0) {
+ sprintf(ret, "Cannot change line when %d hooks open\n", sc->nhooks);
+ return;
+ }
+ sc->framing = wframing;
+#if 1
+ f54_init(sc);
+#else
+ mn_reset(sc);
+#endif
+ } else {
+ printf("%s CONFIG SET [%s]\n", sc->nodename, set);
+ strcat(ret, "ENOGROK\n");
+ return;
+ }
+ }
+
+}
+
+static int
+ngmn_rcvmsg(node_p node, item_p item, hook_p lasthook)
+{
+ struct softc *sc;
+ struct ng_mesg *resp = NULL;
+ struct schan *sch;
+ char *s, *r;
+ int pos, i;
+ struct ng_mesg *msg;
+
+ NGI_GET_MSG(item, msg);
+ sc = NG_NODE_PRIVATE(node);
+
+ if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
+ NG_FREE_ITEM(item);
+ NG_FREE_MSG(msg);
+ return (EINVAL);
+ }
+
+ if (msg->header.cmd != NGM_TEXT_CONFIG &&
+ msg->header.cmd != NGM_TEXT_STATUS) {
+ NG_FREE_ITEM(item);
+ NG_FREE_MSG(msg);
+ return (EINVAL);
+ }
+
+ NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) + NG_TEXTRESPONSE,
+ M_NOWAIT);
+ if (resp == NULL) {
+ NG_FREE_ITEM(item);
+ NG_FREE_MSG(msg);
+ return (ENOMEM);
+ }
+
+ if (msg->header.arglen)
+ s = (char *)msg->data;
+ else
+ s = NULL;
+ r = (char *)resp->data;
+ *r = '\0';
+
+ if (msg->header.cmd == NGM_TEXT_CONFIG) {
+ ngmn_config(node, s, r);
+ resp->header.arglen = strlen(r) + 1;
+ FREE(msg, M_NETGRAPH);
+ return (0);
+ }
+ pos = 0;
+ pos += sprintf(pos + r,"Framer status %b;\n", sc->framer_state, "\20"
+ "\40LOS\37AIS\36LFA\35RRA"
+ "\34AUXP\33NMF\32LMFA\31frs0.0"
+ "\30frs1.7\27TS16RA\26TS16LOS\25TS16AIS"
+ "\24TS16LFA\23frs1.2\22XLS\21XLO"
+ "\20RS1\17rsw.6\16RRA\15RY0"
+ "\14RY1\13RY2\12RY3\11RY4"
+ "\10SI1\7SI2\6rsp.5\5rsp.4"
+ "\4rsp.3\3RSIF\2RS13\1RS15");
+ pos += sprintf(pos + r," Framing errors: %lu", sc->cnt_fec);
+ pos += sprintf(pos + r," Code Violations: %lu\n", sc->cnt_cvc);
+
+ pos += sprintf(pos + r," Falc State %b;\n", sc->falc_state, "\20"
+ "\40LOS\37AIS\36LFA\35RRA"
+ "\34AUXP\33NMF\32LMFA\31frs0.0"
+ "\30frs1.7\27TS16RA\26TS16LOS\25TS16AIS"
+ "\24TS16LFA\23frs1.2\22XLS\21XLO"
+ "\20RS1\17rsw.6\16RRA\15RY0"
+ "\14RY1\13RY2\12RY3\11RY4"
+ "\10SI1\7SI2\6rsp.5\5rsp.4"
+ "\4rsp.3\3RSIF\2RS13\1RS15");
+ pos += sprintf(pos + r, " Falc IRQ %b\n", sc->falc_irq, "\20"
+ "\40RME\37RFS\36T8MS\35RMB\34CASC\33CRC4\32SA6SC\31RPF"
+ "\30b27\27RDO\26ALLS\25XDU\24XMB\23b22\22XLSC\21XPR"
+ "\20FAR\17LFA\16MFAR\15T400MS\14AIS\13LOS\12RAR\11RA"
+ "\10ES\7SEC\6LMFA16\5AIS16\4RA16\3API\2SLN\1SLP");
+ for (i = 0; i < M32_CHAN; i++) {
+ if (!sc->ch[i])
+ continue;
+ sch = sc->ch[i];
+
+ pos += sprintf(r + pos, " Chan %d <%s> ",
+ i, NG_HOOK_NAME(sch->hook));
+
+ pos += sprintf(r + pos, " Last Rx: ");
+ if (sch->last_recv)
+ pos += sprintf(r + pos, "%lu s",
+ (unsigned long)(time_second - sch->last_recv));
+ else
+ pos += sprintf(r + pos, "never");
+
+ pos += sprintf(r + pos, ", last RxErr: ");
+ if (sch->last_rxerr)
+ pos += sprintf(r + pos, "%lu s",
+ (unsigned long)(time_second - sch->last_rxerr));
+ else
+ pos += sprintf(r + pos, "never");
+
+ pos += sprintf(r + pos, ", last Tx: ");
+ if (sch->last_xmit)
+ pos += sprintf(r + pos, "%lu s\n",
+ (unsigned long)(time_second - sch->last_xmit));
+ else
+ pos += sprintf(r + pos, "never\n");
+
+ pos += sprintf(r + pos, " RX error(s) %lu", sch->rx_error);
+ pos += sprintf(r + pos, " Short: %lu", sch->short_error);
+ pos += sprintf(r + pos, " CRC: %lu", sch->crc_error);
+ pos += sprintf(r + pos, " Mod8: %lu", sch->dribble_error);
+ pos += sprintf(r + pos, " Long: %lu", sch->long_error);
+ pos += sprintf(r + pos, " Abort: %lu", sch->abort_error);
+ pos += sprintf(r + pos, " Overflow: %lu\n", sch->overflow_error);
+
+ pos += sprintf(r + pos, " Last error: %b Prev error: %b\n",
+ sch->last_error, "\20\7SHORT\5CRC\4MOD8\3LONG\2ABORT\1OVERRUN",
+ sch->prev_error, "\20\7SHORT\5CRC\4MOD8\3LONG\2ABORT\1OVERRUN");
+ pos += sprintf(r + pos, " Xmit bytes pending %ld\n",
+ sch->tx_pending);
+ }
+ resp->header.arglen = pos + 1;
+
+ /* Take care of synchronous response, if any */
+ NG_RESPOND_MSG(i, node, item, resp);
+ NG_FREE_MSG(msg);
+ return (0);
+}
+
+static int
+ngmn_newhook(node_p node, hook_p hook, const char *name)
+{
+ u_int32_t ts, chan;
+ struct softc *sc;
+ int nbit;
+
+ sc = NG_NODE_PRIVATE(node);
+
+ if (name[0] != 't' || name[1] != 's')
+ return (EINVAL);
+
+ ts = mn_parse_ts(name + 2, &nbit);
+ printf("%d bits %x\n", nbit, ts);
+ if (sc->framing == E1 && (ts & 1))
+ return (EINVAL);
+ if (sc->framing == E1U && nbit != 32)
+ return (EINVAL);
+ if (ts == 0)
+ return (EINVAL);
+ if (sc->framing == E1)
+ chan = ffs(ts) - 1;
+ else
+ chan = 1;
+ if (!sc->ch[chan])
+ mn_create_channel(sc, chan);
+ else if (sc->ch[chan]->state == UP)
+ return (EBUSY);
+ sc->ch[chan]->ts = ts;
+ sc->ch[chan]->hook = hook;
+ sc->ch[chan]->tx_limit = nbit * 8;
+ NG_HOOK_SET_PRIVATE(hook, sc->ch[chan]);
+ sc->nhooks++;
+ return(0);
+}
+
+
+static struct trxd *mn_desc_free;
+
+static struct trxd *
+mn_alloc_desc(void)
+{
+ struct trxd *dp;
+
+ dp = mn_desc_free;
+ if (dp)
+ mn_desc_free = dp->vnext;
+ else
+ dp = (struct trxd *)malloc(sizeof *dp, M_MN, M_NOWAIT);
+ return (dp);
+}
+
+static void
+mn_free_desc(struct trxd *dp)
+{
+ dp->vnext = mn_desc_free;
+ mn_desc_free = dp;
+}
+
+static u_int32_t
+mn_parse_ts(const char *s, int *nbit)
+{
+ unsigned r;
+ int i, j;
+ char *p;
+
+ r = 0;
+ j = -1;
+ *nbit = 0;
+ while(*s) {
+ i = strtol(s, &p, 0);
+ if (i < 0 || i > 31)
+ return (0);
+ while (j != -1 && j < i) {
+ r |= 1 << j++;
+ (*nbit)++;
+ }
+ j = -1;
+ r |= 1 << i;
+ (*nbit)++;
+ if (*p == ',') {
+ s = p + 1;
+ continue;
+ } else if (*p == '-') {
+ j = i + 1;
+ s = p + 1;
+ continue;
+ } else if (!*p) {
+ break;
+ } else {
+ return (0);
+ }
+ }
+ return (r);
+}
+
+#ifdef notyet
+static void
+mn_fmt_ts(char *p, u_int32_t ts)
+{
+ char *s;
+ int j;
+
+ s = "";
+ ts &= 0xffffffff;
+ for (j = 0; j < 32; j++) {
+ if (!(ts & (1 << j)))
+ continue;
+ sprintf(p, "%s%d", s, j);
+ p += strlen(p);
+ s = ",";
+ if (!(ts & (1 << (j+1))))
+ continue;
+ for (; j < 32; j++)
+ if (!(ts & (1 << (j+1))))
+ break;
+ sprintf(p, "-%d", j);
+ p += strlen(p);
+ s = ",";
+ }
+}
+#endif /* notyet */
+
+/*
+ * OUTPUT
+ */
+
+static int
+ngmn_rcvdata(hook_p hook, item_p item)
+{
+ struct mbuf *m2;
+ struct trxd *dp, *dp2;
+ struct schan *sch;
+ struct softc *sc;
+ int chan, pitch, len;
+ struct mbuf *m;
+
+ sch = NG_HOOK_PRIVATE(hook);
+ sc = sch->sc;
+ chan = sch->chan;
+
+ if (sch->state != UP) {
+ NG_FREE_ITEM(item);
+ return (0);
+ }
+ NGI_GET_M(item, m);
+ if (sch->tx_pending + m->m_pkthdr.len > sch->tx_limit * mn_maxlatency) {
+ NG_FREE_M(m);
+ NG_FREE_ITEM(item);
+ return (0);
+ }
+ NG_FREE_ITEM(item);
+ pitch = 0;
+ m2 = m;
+ dp2 = sc->ch[chan]->xl;
+ len = m->m_pkthdr.len;
+ while (len) {
+ dp = mn_alloc_desc();
+ if (!dp) {
+ pitch++;
+ m_freem(m);
+ sc->ch[chan]->xl = dp2;
+ dp = dp2->vnext;
+ while (dp) {
+ dp2 = dp->vnext;
+ mn_free_desc(dp);
+ dp = dp2;
+ }
+ sc->ch[chan]->xl->vnext = 0;
+ break;
+ }
+ dp->data = vtophys(m2->m_data);
+ dp->flags = m2->m_len << 16;
+ dp->flags += 1;
+ len -= m2->m_len;
+ dp->next = vtophys(dp);
+ dp->vnext = 0;
+ sc->ch[chan]->xl->next = vtophys(dp);
+ sc->ch[chan]->xl->vnext = dp;
+ sc->ch[chan]->xl = dp;
+ if (!len) {
+ dp->m = m;
+ dp->flags |= 0xc0000000;
+ dp2->flags &= ~0x40000000;
+ } else {
+ dp->m = 0;
+ m2 = m2->m_next;
+ }
+ }
+ if (pitch)
+ printf("%s%d: Short on mem, pitched %d packets\n",
+ sc->name, chan, pitch);
+ else {
+#if 0
+ printf("%d = %d + %d (%p)\n",
+ sch->tx_pending + m->m_pkthdr.len,
+ sch->tx_pending , m->m_pkthdr.len, m);
+#endif
+ sch->tx_pending += m->m_pkthdr.len;
+ sc->m32x->txpoll &= ~(1 << chan);
+ }
+ return (0);
+}
+
+/*
+ * OPEN
+ */
+static int
+ngmn_connect(hook_p hook)
+{
+ int i, nts, chan;
+ struct trxd *dp, *dp2;
+ struct mbuf *m;
+ struct softc *sc;
+ struct schan *sch;
+ u_int32_t u;
+
+ sch = NG_HOOK_PRIVATE(hook);
+ chan = sch->chan;
+ sc = sch->sc;
+
+ if (sch->state == UP)
+ return (0);
+ sch->state = UP;
+
+ /* Count and configure the timeslots for this channel */
+ for (nts = i = 0; i < 32; i++)
+ if (sch->ts & (1 << i)) {
+ sc->m32_mem.ts[i] = 0x00ff00ff |
+ (chan << 24) | (chan << 8);
+ nts++;
+ }
+
+ /* Init the receiver & xmitter to HDLC */
+ sc->m32_mem.cs[chan].flags = 0x80e90006;
+ /* Allocate two buffers per timeslot */
+ if (nts == 32)
+ sc->m32_mem.cs[chan].itbs = 63;
+ else
+ sc->m32_mem.cs[chan].itbs = nts * 2;
+
+ /* Setup a transmit chain with one descriptor */
+ /* XXX: we actually send a 1 byte packet */
+ dp = mn_alloc_desc();
+ MGETHDR(m, M_TRYWAIT, MT_DATA);
+ if (m == NULL)
+ return ENOBUFS;
+ m->m_pkthdr.len = 0;
+ dp->m = m;
+ dp->flags = 0xc0000000 + (1 << 16);
+ dp->next = vtophys(dp);
+ dp->vnext = 0;
+ dp->data = vtophys(sc->name);
+ sc->m32_mem.cs[chan].tdesc = vtophys(dp);
+ sc->ch[chan]->x1 = dp;
+ sc->ch[chan]->xl = dp;
+
+ /* Setup a receive chain with 5 + NTS descriptors */
+
+ dp = mn_alloc_desc();
+ m = NULL;
+ MGETHDR(m, M_TRYWAIT, MT_DATA);
+ if (m == NULL) {
+ mn_free_desc(dp);
+ return (ENOBUFS);
+ }
+ MCLGET(m, M_TRYWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ mn_free_desc(dp);
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ dp->m = m;
+ dp->data = vtophys(m->m_data);
+ dp->flags = 0x40000000;
+ dp->flags += 1600 << 16;
+ dp->next = vtophys(dp);
+ dp->vnext = 0;
+ sc->ch[chan]->rl = dp;
+
+ for (i = 0; i < (nts + 10); i++) {
+ dp2 = dp;
+ dp = mn_alloc_desc();
+ m = NULL;
+ MGETHDR(m, M_TRYWAIT, MT_DATA);
+ if (m == NULL) {
+ mn_free_desc(dp);
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ MCLGET(m, M_TRYWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ mn_free_desc(dp);
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ dp->m = m;
+ dp->data = vtophys(m->m_data);
+ dp->flags = 0x00000000;
+ dp->flags += 1600 << 16;
+ dp->next = vtophys(dp2);
+ dp->vnext = dp2;
+ }
+ sc->m32_mem.cs[chan].rdesc = vtophys(dp);
+ sc->ch[chan]->r1 = dp;
+
+ /* Initialize this channel */
+ sc->m32_mem.ccb = 0x00008000 + (chan << 8);
+ sc->m32x->cmd = 0x1;
+ DELAY(1000);
+ u = sc->m32x->stat;
+ if (!(u & 1))
+ printf("%s: init chan %d stat %08x\n", sc->name, chan, u);
+ sc->m32x->stat = 1;
+ /* probably not at splnet, force outward queueing */
+ NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
+
+ return (0);
+}
+
+/*
+ * CLOSE
+ */
+static int
+ngmn_disconnect(hook_p hook)
+{
+ int chan, i;
+ struct softc *sc;
+ struct schan *sch;
+ struct trxd *dp, *dp2;
+ u_int32_t u;
+
+ sch = NG_HOOK_PRIVATE(hook);
+ chan = sch->chan;
+ sc = sch->sc;
+
+ if (sch->state == DOWN)
+ return (0);
+ sch->state = DOWN;
+
+ /* Set receiver & transmitter off */
+ sc->m32_mem.cs[chan].flags = 0x80920006;
+ sc->m32_mem.cs[chan].itbs = 0;
+
+ /* free the timeslots */
+ for (i = 0; i < 32; i++)
+ if (sc->ch[chan]->ts & (1 << i))
+ sc->m32_mem.ts[i] = 0x20002000;
+
+ /* Initialize this channel */
+ sc->m32_mem.ccb = 0x00008000 + (chan << 8);
+ sc->m32x->cmd = 0x1;
+ DELAY(30);
+ u = sc->m32x->stat;
+ if (!(u & 1))
+ printf("%s: zap chan %d stat %08x\n", sc->name, chan, u);
+ sc->m32x->stat = 1;
+
+ /* Free all receive descriptors and mbufs */
+ for (dp = sc->ch[chan]->r1; dp ; dp = dp2) {
+ if (dp->m)
+ m_freem(dp->m);
+ sc->ch[chan]->r1 = dp2 = dp->vnext;
+ mn_free_desc(dp);
+ }
+
+ /* Free all transmit descriptors and mbufs */
+ for (dp = sc->ch[chan]->x1; dp ; dp = dp2) {
+ if (dp->m) {
+ sc->ch[chan]->tx_pending -= dp->m->m_pkthdr.len;
+ m_freem(dp->m);
+ }
+ sc->ch[chan]->x1 = dp2 = dp->vnext;
+ mn_free_desc(dp);
+ }
+ sc->nhooks--;
+ return(0);
+}
+
+/*
+ * Create a new channel.
+ */
+static void
+mn_create_channel(struct softc *sc, int chan)
+{
+ struct schan *sch;
+
+ sch = sc->ch[chan] = (struct schan *)malloc(sizeof *sc->ch[chan],
+ M_MN, M_WAITOK | M_ZERO);
+ sch->sc = sc;
+ sch->state = DOWN;
+ sch->chan = chan;
+ sprintf(sch->name, "%s%d", sc->name, chan);
+ return;
+}
+
+#ifdef notyet
+/*
+ * Dump Munich32x state
+ */
+static void
+m32_dump(struct softc *sc)
+{
+ u_int32_t *tp4;
+ int i, j;
+
+ printf("mn%d: MUNICH32X dump\n", sc->unit);
+ tp4 = (u_int32_t *)sc->m0v;
+ for(j = 0; j < 64; j += 8) {
+ printf("%02x", j * sizeof *tp4);
+ for(i = 0; i < 8; i++)
+ printf(" %08x", tp4[i+j]);
+ printf("\n");
+ }
+ for(j = 0; j < M32_CHAN; j++) {
+ if (!sc->ch[j])
+ continue;
+ printf("CH%d: state %d ts %08x",
+ j, sc->ch[j]->state, sc->ch[j]->ts);
+ printf(" %08x %08x %08x %08x %08x %08x\n",
+ sc->m32_mem.cs[j].flags,
+ sc->m32_mem.cs[j].rdesc,
+ sc->m32_mem.cs[j].tdesc,
+ sc->m32_mem.cs[j].itbs,
+ sc->m32_mem.crxd[j],
+ sc->m32_mem.ctxd[j] );
+ }
+}
+
+/*
+ * Dump Falch54 state
+ */
+static void
+f54_dump(struct softc *sc)
+{
+ u_int8_t *tp1;
+ int i, j;
+
+ printf("%s: FALC54 dump\n", sc->name);
+ tp1 = (u_int8_t *)sc->m1v;
+ for(j = 0; j < 128; j += 16) {
+ printf("%s: %02x |", sc->name, j * sizeof *tp1);
+ for(i = 0; i < 16; i++)
+ printf(" %02x", tp1[i+j]);
+ printf("\n");
+ }
+}
+#endif /* notyet */
+
+/*
+ * Init Munich32x
+ */
+static void
+m32_init(struct softc *sc)
+{
+
+ sc->m32x->conf = 0x00000000;
+ sc->m32x->mode1 = 0x81048000 + 1600; /* XXX: temp */
+#if 1
+ sc->m32x->mode2 = 0x00000081;
+ sc->m32x->txpoll = 0xffffffff;
+#elif 1
+ sc->m32x->mode2 = 0x00000081;
+ sc->m32x->txpoll = 0xffffffff;
+#else
+ sc->m32x->mode2 = 0x00000101;
+#endif
+ sc->m32x->lconf = 0x6060009B;
+ sc->m32x->imask = 0x00000000;
+}
+
+/*
+ * Init the Falc54
+ */
+static void
+f54_init(struct softc *sc)
+{
+ sc->f54w->ipc = 0x07;
+
+ sc->f54w->xpm0 = 0xbd;
+ sc->f54w->xpm1 = 0x03;
+ sc->f54w->xpm2 = 0x00;
+
+ sc->f54w->imr0 = 0x18; /* RMB, CASC */
+ sc->f54w->imr1 = 0x08; /* XMB */
+ sc->f54w->imr2 = 0x00;
+ sc->f54w->imr3 = 0x38; /* LMFA16, AIS16, RA16 */
+ sc->f54w->imr4 = 0x00;
+
+ sc->f54w->fmr0 = 0xf0; /* X: HDB3, R: HDB3 */
+ sc->f54w->fmr1 = 0x0e; /* Send CRC4, 2Mbit, ECM */
+ if (sc->framing == E1)
+ sc->f54w->fmr2 = 0x03; /* Auto Rem-Alarm, Auto resync */
+ else if (sc->framing == E1U)
+ sc->f54w->fmr2 = 0x33; /* dais, rtm, Auto Rem-Alarm, Auto resync */
+
+ sc->f54w->lim1 = 0xb0; /* XCLK=8kHz, .62V threshold */
+ sc->f54w->pcd = 0x0a;
+ sc->f54w->pcr = 0x15;
+ sc->f54w->xsw = 0x9f; /* fmr4 */
+ if (sc->framing == E1)
+ sc->f54w->xsp = 0x1c; /* fmr5 */
+ else if (sc->framing == E1U)
+ sc->f54w->xsp = 0x3c; /* tt0, fmr5 */
+ sc->f54w->xc0 = 0x07;
+ sc->f54w->xc1 = 0x3d;
+ sc->f54w->rc0 = 0x05;
+ sc->f54w->rc1 = 0x00;
+ sc->f54w->cmdr = 0x51;
+}
+
+static int
+mn_reset(struct softc *sc)
+{
+ u_int32_t u;
+ int i;
+
+ sc->m32x->ccba = vtophys(&sc->m32_mem.csa);
+ sc->m32_mem.csa = vtophys(&sc->m32_mem.ccb);
+
+ bzero(sc->tiqb, sizeof sc->tiqb);
+ sc->m32x->tiqba = vtophys(&sc->tiqb);
+ sc->m32x->tiql = NIQB / 16 - 1;
+
+ bzero(sc->riqb, sizeof sc->riqb);
+ sc->m32x->riqba = vtophys(&sc->riqb);
+ sc->m32x->riql = NIQB / 16 - 1;
+
+ bzero(sc->ltiqb, sizeof sc->ltiqb);
+ sc->m32x->ltiqba = vtophys(&sc->ltiqb);
+ sc->m32x->ltiql = NIQB / 16 - 1;
+
+ bzero(sc->lriqb, sizeof sc->lriqb);
+ sc->m32x->lriqba = vtophys(&sc->lriqb);
+ sc->m32x->lriql = NIQB / 16 - 1;
+
+ bzero(sc->piqb, sizeof sc->piqb);
+ sc->m32x->piqba = vtophys(&sc->piqb);
+ sc->m32x->piql = NIQB / 16 - 1;
+
+ m32_init(sc);
+ f54_init(sc);
+
+ u = sc->m32x->stat;
+ sc->m32x->stat = u;
+ sc->m32_mem.ccb = 0x4;
+ sc->m32x->cmd = 0x1;
+ DELAY(1000);
+ u = sc->m32x->stat;
+ sc->m32x->stat = u;
+
+ /* set all timeslots to known state */
+ for (i = 0; i < 32; i++)
+ sc->m32_mem.ts[i] = 0x20002000;
+
+ if (!(u & 1)) {
+ printf(
+"mn%d: WARNING: Controller failed the PCI bus-master test.\n"
+"mn%d: WARNING: Use a PCI slot which can support bus-master cards.\n",
+ sc->unit, sc->unit);
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * FALC54 interrupt handling
+ */
+static void
+f54_intr(struct softc *sc)
+{
+ unsigned g, u, s;
+
+ g = sc->f54r->gis;
+ u = sc->f54r->isr0 << 24;
+ u |= sc->f54r->isr1 << 16;
+ u |= sc->f54r->isr2 << 8;
+ u |= sc->f54r->isr3;
+ sc->falc_irq = u;
+ /* don't chat about the 1 sec heart beat */
+ if (u & ~0x40) {
+#if 0
+ printf("%s*: FALC54 IRQ GIS:%02x %b\n", sc->name, g, u, "\20"
+ "\40RME\37RFS\36T8MS\35RMB\34CASC\33CRC4\32SA6SC\31RPF"
+ "\30b27\27RDO\26ALLS\25XDU\24XMB\23b22\22XLSC\21XPR"
+ "\20FAR\17LFA\16MFAR\15T400MS\14AIS\13LOS\12RAR\11RA"
+ "\10ES\7SEC\6LMFA16\5AIS16\4RA16\3API\2SLN\1SLP");
+#endif
+ s = sc->f54r->frs0 << 24;
+ s |= sc->f54r->frs1 << 16;
+ s |= sc->f54r->rsw << 8;
+ s |= sc->f54r->rsp;
+ sc->falc_state = s;
+
+ s &= ~0x01844038; /* undefined or static bits */
+ s &= ~0x00009fc7; /* bits we don't care about */
+ s &= ~0x00780000; /* XXX: TS16 related */
+ s &= ~0x06000000; /* XXX: Multiframe related */
+#if 0
+ printf("%s*: FALC54 Status %b\n", sc->name, s, "\20"
+ "\40LOS\37AIS\36LFA\35RRA\34AUXP\33NMF\32LMFA\31frs0.0"
+ "\30frs1.7\27TS16RA\26TS16LOS\25TS16AIS\24TS16LFA\23frs1.2\22XLS\21XLO"
+ "\20RS1\17rsw.6\16RRA\15RY0\14RY1\13RY2\12RY3\11RY4"
+ "\10SI1\7SI2\6rsp.5\5rsp.4\4rsp.3\3RSIF\2RS13\1RS15");
+#endif
+ if (s != sc->framer_state) {
+#if 0
+ for (i = 0; i < M32_CHAN; i++) {
+ if (!sc->ch[i])
+ continue;
+ sp = &sc->ch[i]->ifsppp;
+ if (!(sp->pp_if.if_flags & IFF_UP))
+ continue;
+ if (s)
+ timeout((timeout_t *)sp->pp_down, sp, 1 * hz);
+ else
+ timeout((timeout_t *)sp->pp_up, sp, 1 * hz);
+ }
+#endif
+ sc->framer_state = s;
+ }
+ }
+ /* Once per second check error counters */
+ /* XXX: not clear if this is actually ok */
+ if (!(u & 0x40))
+ return;
+ sc->cnt_fec += sc->f54r->fec;
+ sc->cnt_cvc += sc->f54r->cvc;
+ sc->cnt_cec1 += sc->f54r->cec1;
+ sc->cnt_ebc += sc->f54r->ebc;
+ sc->cnt_cec2 += sc->f54r->cec2;
+ sc->cnt_cec3 += sc->f54r->cec3;
+ sc->cnt_rbc += sc->f54r->rbc;
+}
+
+/*
+ * Transmit interrupt for one channel
+ */
+static void
+mn_tx_intr(struct softc *sc, u_int32_t vector)
+{
+ u_int32_t chan;
+ struct trxd *dp;
+ struct mbuf *m;
+
+ chan = vector & 0x1f;
+ if (!sc->ch[chan])
+ return;
+ if (sc->ch[chan]->state != UP) {
+ printf("%s: tx_intr when not UP\n", sc->name);
+ return;
+ }
+ for (;;) {
+ dp = sc->ch[chan]->x1;
+ if (vtophys(dp) == sc->m32_mem.ctxd[chan])
+ return;
+ m = dp->m;
+ if (m) {
+#if 0
+ printf("%d = %d - %d (%p)\n",
+ sc->ch[chan]->tx_pending - m->m_pkthdr.len,
+ sc->ch[chan]->tx_pending , m->m_pkthdr.len, m);
+#endif
+ sc->ch[chan]->tx_pending -= m->m_pkthdr.len;
+ m_freem(m);
+ }
+ sc->ch[chan]->last_xmit = time_second;
+ sc->ch[chan]->x1 = dp->vnext;
+ mn_free_desc(dp);
+ }
+}
+
+/*
+ * Receive interrupt for one channel
+ */
+static void
+mn_rx_intr(struct softc *sc, u_int32_t vector)
+{
+ u_int32_t chan, err;
+ struct trxd *dp;
+ struct mbuf *m;
+ struct schan *sch;
+
+ chan = vector & 0x1f;
+ if (!sc->ch[chan])
+ return;
+ sch = sc->ch[chan];
+ if (sch->state != UP) {
+ printf("%s: rx_intr when not UP\n", sc->name);
+ return;
+ }
+ vector &= ~0x1f;
+ if (vector == 0x30000b00)
+ sch->rx_error++;
+ for (;;) {
+ dp = sch->r1;
+ if (vtophys(dp) == sc->m32_mem.crxd[chan])
+ return;
+ m = dp->m;
+ dp->m = 0;
+ m->m_pkthdr.len = m->m_len = (dp->status >> 16) & 0x1fff;
+ err = (dp->status >> 8) & 0xff;
+ if (!err) {
+ int error;
+ NG_SEND_DATA_ONLY(error, sch->hook, m);
+ sch->last_recv = time_second;
+ /* we could be down by now... */
+ if (sch->state != UP)
+ return;
+ } else if (err & 0x40) {
+ sch->short_error++;
+ } else if (err & 0x10) {
+ sch->crc_error++;
+ } else if (err & 0x08) {
+ sch->dribble_error++;
+ } else if (err & 0x04) {
+ sch->long_error++;
+ } else if (err & 0x02) {
+ sch->abort_error++;
+ } else if (err & 0x01) {
+ sch->overflow_error++;
+ }
+ if (err) {
+ sch->last_rxerr = time_second;
+ sch->prev_error = sch->last_error;
+ sch->last_error = err;
+ }
+
+ sc->ch[chan]->r1 = dp->vnext;
+
+ /* Replenish desc + mbuf supplies */
+ if (!m) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ mn_free_desc(dp);
+ return; /* ENOBUFS */
+ }
+ MCLGET(m, M_DONTWAIT);
+ if((m->m_flags & M_EXT) == 0) {
+ mn_free_desc(dp);
+ m_freem(m);
+ return; /* ENOBUFS */
+ }
+ }
+ dp->m = m;
+ dp->data = vtophys(m->m_data);
+ dp->flags = 0x40000000;
+ dp->flags += 1600 << 16;
+ dp->next = vtophys(dp);
+ dp->vnext = 0;
+ sc->ch[chan]->rl->next = vtophys(dp);
+ sc->ch[chan]->rl->vnext = dp;
+ sc->ch[chan]->rl->flags &= ~0x40000000;
+ sc->ch[chan]->rl = dp;
+ }
+}
+
+
+/*
+ * Interupt handler
+ */
+
+static void
+mn_intr(void *xsc)
+{
+ struct softc *sc;
+ u_int32_t stat, lstat, u;
+ int i, j;
+
+ sc = xsc;
+ stat = sc->m32x->stat;
+ lstat = sc->m32x->lstat;
+#if 0
+ if (!stat && !(lstat & 2))
+ return;
+#endif
+
+ if (stat & ~0xc200) {
+ printf("%s: I stat=%08x lstat=%08x\n", sc->name, stat, lstat);
+ }
+
+ if ((stat & 0x200) || (lstat & 2))
+ f54_intr(sc);
+
+ for (j = i = 0; i < 64; i ++) {
+ u = sc->riqb[i];
+ if (u) {
+ sc->riqb[i] = 0;
+ mn_rx_intr(sc, u);
+ if ((u & ~0x1f) == 0x30000800 || (u & ~0x1f) == 0x30000b00)
+ continue;
+ u &= ~0x30000400; /* bits we don't care about */
+ if ((u & ~0x1f) == 0x00000900)
+ continue;
+ if (!(u & ~0x1f))
+ continue;
+ if (!j)
+ printf("%s*: RIQB:", sc->name);
+ printf(" [%d]=%08x", i, u);
+ j++;
+ }
+ }
+ if (j)
+ printf("\n");
+
+ for (j = i = 0; i < 64; i ++) {
+ u = sc->tiqb[i];
+ if (u) {
+ sc->tiqb[i] = 0;
+ mn_tx_intr(sc, u);
+ if ((u & ~0x1f) == 0x20000800)
+ continue;
+ u &= ~0x20000000; /* bits we don't care about */
+ if (!u)
+ continue;
+ if (!j)
+ printf("%s*: TIQB:", sc->name);
+ printf(" [%d]=%08x", i, u);
+ j++;
+ }
+ }
+ if (j)
+ printf("\n");
+ sc->m32x->stat = stat;
+}
+
+static void
+mn_timeout(void *xsc)
+{
+ static int round = 0;
+ struct softc *sc;
+
+ mn_intr(xsc);
+ sc = xsc;
+ timeout(mn_timeout, xsc, 10 * hz);
+ round++;
+ if (round == 2) {
+ sc->m32_mem.ccb = 0x00008004;
+ sc->m32x->cmd = 0x1;
+ } else if (round > 2) {
+ printf("%s: timeout\n", sc->name);
+ }
+}
+
+/*
+ * PCI initialization stuff
+ */
+
+static int
+mn_probe (device_t self)
+{
+ u_int id = pci_get_devid(self);
+
+ if (sizeof (struct m32xreg) != 256) {
+ printf("MN: sizeof(struct m32xreg) = %d, should have been 256\n", sizeof (struct m32xreg));
+ return (ENXIO);
+ }
+ if (sizeof (struct f54rreg) != 128) {
+ printf("MN: sizeof(struct f54rreg) = %d, should have been 128\n", sizeof (struct f54rreg));
+ return (ENXIO);
+ }
+ if (sizeof (struct f54wreg) != 128) {
+ printf("MN: sizeof(struct f54wreg) = %d, should have been 128\n", sizeof (struct f54wreg));
+ return (ENXIO);
+ }
+
+ if (id != 0x2101110a)
+ return (ENXIO);
+
+ device_set_desc_copy(self, "Munich32X E1/T1 HDLC Controller");
+ return (0);
+}
+
+static int
+mn_attach (device_t self)
+{
+ struct softc *sc;
+ u_int32_t u;
+ u_int32_t ver;
+ static int once;
+ int rid, error;
+ struct resource *res;
+
+ if (!once) {
+ if (ng_newtype(&mntypestruct))
+ printf("ng_newtype failed\n");
+ once++;
+ }
+
+ sc = (struct softc *)malloc(sizeof *sc, M_MN, M_WAITOK | M_ZERO);
+ device_set_softc(self, sc);
+
+ sc->dev = self;
+ sc->unit = device_get_unit(self);
+ sc->framing = E1;
+ sprintf(sc->name, "mn%d", sc->unit);
+
+ rid = PCIR_MAPS;
+ res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res == NULL) {
+ device_printf(self, "Could not map memory\n");
+ return ENXIO;
+ }
+ sc->m0v = rman_get_virtual(res);
+ sc->m0p = rman_get_start(res);
+
+ rid = PCIR_MAPS + 4;
+ res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res == NULL) {
+ device_printf(self, "Could not map memory\n");
+ return ENXIO;
+ }
+ sc->m1v = rman_get_virtual(res);
+ sc->m1p = rman_get_start(res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->irq = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0,
+ 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->irq == NULL) {
+ printf("couldn't map interrupt\n");
+ return(ENXIO);
+ }
+
+ error = bus_setup_intr(self, sc->irq, INTR_TYPE_NET, mn_intr, sc, &sc->intrhand);
+
+ if (error) {
+ printf("couldn't set up irq\n");
+ return(ENXIO);
+ }
+
+ u = pci_read_config(self, PCIR_COMMAND, 1);
+ printf("%x\n", u);
+ pci_write_config(self, PCIR_COMMAND, u | PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN, 1);
+#if 0
+ pci_write_config(self, PCIR_COMMAND, 0x02800046, 4);
+#endif
+ u = pci_read_config(self, PCIR_COMMAND, 1);
+ printf("%x\n", u);
+
+ ver = pci_get_revid(self);
+
+ sc->m32x = (struct m32xreg *) sc->m0v;
+ sc->f54w = (struct f54wreg *) sc->m1v;
+ sc->f54r = (struct f54rreg *) sc->m1v;
+
+ /* We must reset before poking at FALC54 registers */
+ u = mn_reset(sc);
+ if (!u)
+ return (0);
+
+ printf("mn%d: Munich32X", sc->unit);
+ switch (ver) {
+ case 0x13:
+ printf(" Rev 2.2");
+ break;
+ default:
+ printf(" Rev 0x%x\n", ver);
+ }
+ printf(", Falc54");
+ switch (sc->f54r->vstr) {
+ case 0:
+ printf(" Rev < 1.3\n");
+ break;
+ case 1:
+ printf(" Rev 1.3\n");
+ break;
+ case 2:
+ printf(" Rev 1.4\n");
+ break;
+ case 0x10:
+ printf("-LH Rev 1.1\n");
+ break;
+ case 0x13:
+ printf("-LH Rev 1.3\n");
+ break;
+ default:
+ printf(" Rev 0x%x\n", sc->f54r->vstr);
+ }
+
+ if (ng_make_node_common(&mntypestruct, &sc->node) != 0) {
+ printf("ng_make_node_common failed\n");
+ return (0);
+ }
+ NG_NODE_SET_PRIVATE(sc->node, sc);
+ sprintf(sc->nodename, "%s%d", NG_MN_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ NG_NODE_UNREF(sc->node);
+ return (0);
+ }
+
+ return (0);
+}
+
+
+static device_method_t mn_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mn_probe),
+ DEVMETHOD(device_attach, mn_attach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ {0, 0}
+};
+
+static driver_t mn_driver = {
+ "mn",
+ mn_methods,
+ 0
+};
+
+static devclass_t mn_devclass;
+
+DRIVER_MODULE(mn, pci, mn_driver, mn_devclass, 0, 0);
diff --git a/sys/pci/if_pcn.c b/sys/pci/if_pcn.c
new file mode 100644
index 0000000..f027900
--- /dev/null
+++ b/sys/pci/if_pcn.c
@@ -0,0 +1,1434 @@
+/*
+ * Copyright (c) 2000 Berkeley Software Design, Inc.
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@osd.bsdi.com>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * AMD Am79c972 fast ethernet PCI NIC driver. Datatheets are available
+ * from http://www.amd.com.
+ *
+ * Written by Bill Paul <wpaul@osd.bsdi.com>
+ */
+
+/*
+ * The AMD PCnet/PCI controllers are more advanced and functional
+ * versions of the venerable 7990 LANCE. The PCnet/PCI chips retain
+ * backwards compatibility with the LANCE and thus can be made
+ * to work with older LANCE drivers. This is in fact how the
+ * PCnet/PCI chips were supported in FreeBSD originally. The trouble
+ * is that the PCnet/PCI devices offer several performance enhancements
+ * which can't be exploited in LANCE compatibility mode. Chief among
+ * these enhancements is the ability to perform PCI DMA operations
+ * using 32-bit addressing (which eliminates the need for ISA
+ * bounce-buffering), and special receive buffer alignment (which
+ * allows the receive handler to pass packets to the upper protocol
+ * layers without copying on both the x86 and alpha platforms).
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define PCN_USEIOSPACE
+
+#include <pci/if_pcnreg.h>
+
+MODULE_DEPEND(pcn, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct pcn_type pcn_devs[] = {
+ { PCN_VENDORID, PCN_DEVICEID_PCNET, "AMD PCnet/PCI 10/100BaseTX" },
+ { PCN_VENDORID, PCN_DEVICEID_HOME, "AMD PCnet/Home HomePNA" },
+ { 0, 0, NULL }
+};
+
+static u_int32_t pcn_csr_read (struct pcn_softc *, int);
+static u_int16_t pcn_csr_read16 (struct pcn_softc *, int);
+static u_int16_t pcn_bcr_read16 (struct pcn_softc *, int);
+static void pcn_csr_write (struct pcn_softc *, int, int);
+static u_int32_t pcn_bcr_read (struct pcn_softc *, int);
+static void pcn_bcr_write (struct pcn_softc *, int, int);
+
+static int pcn_probe (device_t);
+static int pcn_attach (device_t);
+static int pcn_detach (device_t);
+
+static int pcn_newbuf (struct pcn_softc *, int, struct mbuf *);
+static int pcn_encap (struct pcn_softc *,
+ struct mbuf *, u_int32_t *);
+static void pcn_rxeof (struct pcn_softc *);
+static void pcn_txeof (struct pcn_softc *);
+static void pcn_intr (void *);
+static void pcn_tick (void *);
+static void pcn_start (struct ifnet *);
+static int pcn_ioctl (struct ifnet *, u_long, caddr_t);
+static void pcn_init (void *);
+static void pcn_stop (struct pcn_softc *);
+static void pcn_watchdog (struct ifnet *);
+static void pcn_shutdown (device_t);
+static int pcn_ifmedia_upd (struct ifnet *);
+static void pcn_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static int pcn_miibus_readreg (device_t, int, int);
+static int pcn_miibus_writereg (device_t, int, int, int);
+static void pcn_miibus_statchg (device_t);
+
+static void pcn_setfilt (struct ifnet *);
+static void pcn_setmulti (struct pcn_softc *);
+static u_int32_t pcn_crc (caddr_t);
+static void pcn_reset (struct pcn_softc *);
+static int pcn_list_rx_init (struct pcn_softc *);
+static int pcn_list_tx_init (struct pcn_softc *);
+
+#ifdef PCN_USEIOSPACE
+#define PCN_RES SYS_RES_IOPORT
+#define PCN_RID PCN_PCI_LOIO
+#else
+#define PCN_RES SYS_RES_MEMORY
+#define PCN_RID PCN_PCI_LOMEM
+#endif
+
+static device_method_t pcn_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pcn_probe),
+ DEVMETHOD(device_attach, pcn_attach),
+ DEVMETHOD(device_detach, pcn_detach),
+ DEVMETHOD(device_shutdown, pcn_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, pcn_miibus_readreg),
+ DEVMETHOD(miibus_writereg, pcn_miibus_writereg),
+ DEVMETHOD(miibus_statchg, pcn_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t pcn_driver = {
+ "pcn",
+ pcn_methods,
+ sizeof(struct pcn_softc)
+};
+
+static devclass_t pcn_devclass;
+
+DRIVER_MODULE(if_pcn, pci, pcn_driver, pcn_devclass, 0, 0);
+DRIVER_MODULE(miibus, pcn, miibus_driver, miibus_devclass, 0, 0);
+
+#define PCN_CSR_SETBIT(sc, reg, x) \
+ pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) | (x))
+
+#define PCN_CSR_CLRBIT(sc, reg, x) \
+ pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) & ~(x))
+
+#define PCN_BCR_SETBIT(sc, reg, x) \
+ pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) | (x))
+
+#define PCN_BCR_CLRBIT(sc, reg, x) \
+ pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) & ~(x))
+
+static u_int32_t pcn_csr_read(sc, reg)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, PCN_IO32_RAP, reg);
+ return(CSR_READ_4(sc, PCN_IO32_RDP));
+}
+
+static u_int16_t pcn_csr_read16(sc, reg)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_2(sc, PCN_IO16_RAP, reg);
+ return(CSR_READ_2(sc, PCN_IO16_RDP));
+}
+
+static void pcn_csr_write(sc, reg, val)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, PCN_IO32_RAP, reg);
+ CSR_WRITE_4(sc, PCN_IO32_RDP, val);
+ return;
+}
+
+static u_int32_t pcn_bcr_read(sc, reg)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, PCN_IO32_RAP, reg);
+ return(CSR_READ_4(sc, PCN_IO32_BDP));
+}
+
+static u_int16_t pcn_bcr_read16(sc, reg)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_2(sc, PCN_IO16_RAP, reg);
+ return(CSR_READ_2(sc, PCN_IO16_BDP));
+}
+
+static void pcn_bcr_write(sc, reg, val)
+ struct pcn_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, PCN_IO32_RAP, reg);
+ CSR_WRITE_4(sc, PCN_IO32_BDP, val);
+ return;
+}
+
+static int pcn_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct pcn_softc *sc;
+ int val;
+
+ sc = device_get_softc(dev);
+
+ if (sc->pcn_phyaddr && phy > sc->pcn_phyaddr)
+ return(0);
+
+ pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5));
+ val = pcn_bcr_read(sc, PCN_BCR_MIIDATA) & 0xFFFF;
+ if (val == 0xFFFF)
+ return(0);
+
+ sc->pcn_phyaddr = phy;
+
+ return(val);
+}
+
+static int pcn_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct pcn_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5));
+ pcn_bcr_write(sc, PCN_BCR_MIIDATA, data);
+
+ return(0);
+}
+
+static void pcn_miibus_statchg(dev)
+ device_t dev;
+{
+ struct pcn_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->pcn_miibus);
+
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ PCN_BCR_SETBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN);
+ } else {
+ PCN_BCR_CLRBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN);
+ }
+
+ return;
+}
+
+#define DC_POLY 0xEDB88320
+
+static u_int32_t pcn_crc(addr)
+ caddr_t addr;
+{
+ u_int32_t idx, bit, data, crc;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0);
+ }
+
+ return ((crc >> 26) & 0x3F);
+}
+
+static void pcn_setmulti(sc)
+ struct pcn_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ u_int32_t h, i;
+ u_int16_t hashes[4] = { 0, 0, 0, 0 };
+
+ ifp = &sc->arpcom.ac_if;
+
+ PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ for (i = 0; i < 4; i++)
+ pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0xFFFF);
+ PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ for (i = 0; i < 4; i++)
+ pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = pcn_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ hashes[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ for (i = 0; i < 4; i++)
+ pcn_csr_write(sc, PCN_CSR_MAR0 + i, hashes[i]);
+
+ PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
+
+ return;
+}
+
+static void pcn_reset(sc)
+ struct pcn_softc *sc;
+{
+ /*
+ * Issue a reset by reading from the RESET register.
+ * Note that we don't know if the chip is operating in
+ * 16-bit or 32-bit mode at this point, so we attempt
+ * to reset the chip both ways. If one fails, the other
+ * will succeed.
+ */
+ CSR_READ_2(sc, PCN_IO16_RESET);
+ CSR_READ_4(sc, PCN_IO32_RESET);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ /* Select 32-bit (DWIO) mode */
+ CSR_WRITE_4(sc, PCN_IO32_RDP, 0);
+
+ /* Select software style 3. */
+ pcn_bcr_write(sc, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI_BURST);
+
+ return;
+}
+
+/*
+ * Probe for an AMD chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int pcn_probe(dev)
+ device_t dev;
+{
+ struct pcn_type *t;
+ struct pcn_softc *sc;
+ int rid;
+ u_int32_t chip_id;
+
+ t = pcn_devs;
+ sc = device_get_softc(dev);
+
+ while(t->pcn_name != NULL) {
+ if ((pci_get_vendor(dev) == t->pcn_vid) &&
+ (pci_get_device(dev) == t->pcn_did)) {
+ /*
+ * Temporarily map the I/O space
+ * so we can read the chip ID register.
+ */
+ rid = PCN_RID;
+ sc->pcn_res = bus_alloc_resource(dev, PCN_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (sc->pcn_res == NULL) {
+ device_printf(dev,
+ "couldn't map ports/memory\n");
+ return(ENXIO);
+ }
+ sc->pcn_btag = rman_get_bustag(sc->pcn_res);
+ sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res);
+ mtx_init(&sc->pcn_mtx,
+ device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ PCN_LOCK(sc);
+ /*
+ * Note: we can *NOT* put the chip into
+ * 32-bit mode yet. The lnc driver will only
+ * work in 16-bit mode, and once the chip
+ * goes into 32-bit mode, the only way to
+ * get it out again is with a hardware reset.
+ * So if pcn_probe() is called before the
+ * lnc driver's probe routine, the chip will
+ * be locked into 32-bit operation and the lnc
+ * driver will be unable to attach to it.
+ * Note II: if the chip happens to already
+ * be in 32-bit mode, we still need to check
+ * the chip ID, but first we have to detect
+ * 32-bit mode using only 16-bit operations.
+ * The safest way to do this is to read the
+ * PCI subsystem ID from BCR23/24 and compare
+ * that with the value read from PCI config
+ * space.
+ */
+ chip_id = pcn_bcr_read16(sc, PCN_BCR_PCISUBSYSID);
+ chip_id <<= 16;
+ chip_id |= pcn_bcr_read16(sc, PCN_BCR_PCISUBVENID);
+ /*
+ * Note III: the test for 0x10001000 is a hack to
+ * pacify VMware, who's pseudo-PCnet interface is
+ * broken. Reading the subsystem register from PCI
+ * config space yeilds 0x00000000 while reading the
+ * same value from I/O space yeilds 0x10001000. It's
+ * not supposed to be that way.
+ */
+ if (chip_id == pci_read_config(dev,
+ PCIR_SUBVEND_0, 4) || chip_id == 0x10001000) {
+ /* We're in 16-bit mode. */
+ chip_id = pcn_csr_read16(sc, PCN_CSR_CHIPID1);
+ chip_id <<= 16;
+ chip_id |= pcn_csr_read16(sc, PCN_CSR_CHIPID0);
+ } else {
+ /* We're in 32-bit mode. */
+ chip_id = pcn_csr_read(sc, PCN_CSR_CHIPID1);
+ chip_id <<= 16;
+ chip_id |= pcn_csr_read(sc, PCN_CSR_CHIPID0);
+ }
+ bus_release_resource(dev, PCN_RES,
+ PCN_RID, sc->pcn_res);
+ PCN_UNLOCK(sc);
+ mtx_destroy(&sc->pcn_mtx);
+ chip_id >>= 12;
+ sc->pcn_type = chip_id & PART_MASK;
+ switch(sc->pcn_type) {
+ case Am79C971:
+ case Am79C972:
+ case Am79C973:
+ case Am79C975:
+ case Am79C976:
+ case Am79C978:
+ break;
+ default:
+ return(ENXIO);
+ break;
+ }
+ device_set_desc(dev, t->pcn_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int pcn_attach(dev)
+ device_t dev;
+{
+ u_int32_t eaddr[2];
+ u_int32_t command;
+ struct pcn_softc *sc;
+ struct ifnet *ifp;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+
+ /* Initialize our mutex. */
+ mtx_init(&sc->pcn_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ PCN_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, PCN_PCI_LOIO, 4);
+ membase = pci_read_config(dev, PCN_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, PCN_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("pcn%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, PCN_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, PCN_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, PCN_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef PCN_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("pcn%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("pcn%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;;
+ goto fail;
+ }
+#endif
+
+ rid = PCN_RID;
+ sc->pcn_res = bus_alloc_resource(dev, PCN_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->pcn_res == NULL) {
+ printf("pcn%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->pcn_btag = rman_get_bustag(sc->pcn_res);
+ sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->pcn_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->pcn_irq == NULL) {
+ printf("pcn%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->pcn_irq, INTR_TYPE_NET,
+ pcn_intr, sc, &sc->pcn_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_res);
+ bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res);
+ printf("pcn%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Reset the adapter. */
+ pcn_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ eaddr[0] = CSR_READ_4(sc, PCN_IO32_APROM00);
+ eaddr[1] = CSR_READ_4(sc, PCN_IO32_APROM01);
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ /*
+ * An AMD chip was detected. Inform the world.
+ */
+ printf("pcn%d: Ethernet address: %6D\n", unit,
+ sc->arpcom.ac_enaddr, ":");
+
+ sc->pcn_unit = unit;
+ callout_handle_init(&sc->pcn_stat_ch);
+
+ sc->pcn_ldata = contigmalloc(sizeof(struct pcn_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->pcn_ldata == NULL) {
+ printf("pcn%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->pcn_irq, sc->pcn_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_irq);
+ bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res);
+ error = ENXIO;
+ goto fail;
+ }
+ bzero(sc->pcn_ldata, sizeof(struct pcn_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "pcn";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = pcn_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = pcn_start;
+ ifp->if_watchdog = pcn_watchdog;
+ ifp->if_init = pcn_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = PCN_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ if (mii_phy_probe(dev, &sc->pcn_miibus,
+ pcn_ifmedia_upd, pcn_ifmedia_sts)) {
+ printf("pcn%d: MII without any PHY!\n", sc->pcn_unit);
+ bus_teardown_intr(dev, sc->pcn_irq, sc->pcn_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_irq);
+ bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ callout_handle_init(&sc->pcn_stat_ch);
+ PCN_UNLOCK(sc);
+ return(0);
+
+fail:
+ PCN_UNLOCK(sc);
+ mtx_destroy(&sc->pcn_mtx);
+
+ return(error);
+}
+
+static int pcn_detach(dev)
+ device_t dev;
+{
+ struct pcn_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ PCN_LOCK(sc);
+
+ pcn_reset(sc);
+ pcn_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ if (sc->pcn_miibus != NULL) {
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->pcn_miibus);
+ }
+
+ bus_teardown_intr(dev, sc->pcn_irq, sc->pcn_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_irq);
+ bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res);
+
+ contigfree(sc->pcn_ldata, sizeof(struct pcn_list_data), M_DEVBUF);
+ PCN_UNLOCK(sc);
+
+ mtx_destroy(&sc->pcn_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int pcn_list_tx_init(sc)
+ struct pcn_softc *sc;
+{
+ struct pcn_list_data *ld;
+ struct pcn_ring_data *cd;
+ int i;
+
+ cd = &sc->pcn_cdata;
+ ld = sc->pcn_ldata;
+
+ for (i = 0; i < PCN_TX_LIST_CNT; i++) {
+ cd->pcn_tx_chain[i] = NULL;
+ ld->pcn_tx_list[i].pcn_tbaddr = 0;
+ ld->pcn_tx_list[i].pcn_txctl = 0;
+ ld->pcn_tx_list[i].pcn_txstat = 0;
+ }
+
+ cd->pcn_tx_prod = cd->pcn_tx_cons = cd->pcn_tx_cnt = 0;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them.
+ */
+static int pcn_list_rx_init(sc)
+ struct pcn_softc *sc;
+{
+ struct pcn_list_data *ld;
+ struct pcn_ring_data *cd;
+ int i;
+
+ ld = sc->pcn_ldata;
+ cd = &sc->pcn_cdata;
+
+ for (i = 0; i < PCN_RX_LIST_CNT; i++) {
+ if (pcn_newbuf(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ }
+
+ cd->pcn_rx_prod = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int pcn_newbuf(sc, idx, m)
+ struct pcn_softc *sc;
+ int idx;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct pcn_rx_desc *c;
+
+ c = &sc->pcn_ldata->pcn_rx_list[idx];
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+
+ sc->pcn_cdata.pcn_rx_chain[idx] = m_new;
+ c->pcn_rbaddr = vtophys(mtod(m_new, caddr_t));
+ c->pcn_bufsz = (~(PCN_RXLEN) + 1) & PCN_RXLEN_BUFSZ;
+ c->pcn_bufsz |= PCN_RXLEN_MBO;
+ c->pcn_rxstat = PCN_RXSTAT_STP|PCN_RXSTAT_ENP|PCN_RXSTAT_OWN;
+
+ return(0);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void pcn_rxeof(sc)
+ struct pcn_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct pcn_rx_desc *cur_rx;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+ i = sc->pcn_cdata.pcn_rx_prod;
+
+ while(PCN_OWN_RXDESC(&sc->pcn_ldata->pcn_rx_list[i])) {
+ cur_rx = &sc->pcn_ldata->pcn_rx_list[i];
+ m = sc->pcn_cdata.pcn_rx_chain[i];
+ sc->pcn_cdata.pcn_rx_chain[i] = NULL;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (cur_rx->pcn_rxstat & PCN_RXSTAT_ERR) {
+ ifp->if_ierrors++;
+ pcn_newbuf(sc, i, m);
+ PCN_INC(i, PCN_RX_LIST_CNT);
+ continue;
+ }
+
+ if (pcn_newbuf(sc, i, NULL)) {
+ /* Ran out of mbufs; recycle this one. */
+ pcn_newbuf(sc, i, m);
+ ifp->if_ierrors++;
+ PCN_INC(i, PCN_RX_LIST_CNT);
+ continue;
+ }
+
+ PCN_INC(i, PCN_RX_LIST_CNT);
+
+ /* No errors; receive the packet. */
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+ m->m_len = m->m_pkthdr.len =
+ cur_rx->pcn_rxlen - ETHER_CRC_LEN;
+ m->m_pkthdr.rcvif = ifp;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc->pcn_cdata.pcn_rx_prod = i;
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void pcn_txeof(sc)
+ struct pcn_softc *sc;
+{
+ struct pcn_tx_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ u_int32_t idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ idx = sc->pcn_cdata.pcn_tx_cons;
+ while (idx != sc->pcn_cdata.pcn_tx_prod) {
+ cur_tx = &sc->pcn_ldata->pcn_tx_list[idx];
+
+ if (!PCN_OWN_TXDESC(cur_tx))
+ break;
+
+ if (!(cur_tx->pcn_txctl & PCN_TXCTL_ENP)) {
+ sc->pcn_cdata.pcn_tx_cnt--;
+ PCN_INC(idx, PCN_TX_LIST_CNT);
+ continue;
+ }
+
+ if (cur_tx->pcn_txctl & PCN_TXCTL_ERR) {
+ ifp->if_oerrors++;
+ if (cur_tx->pcn_txstat & PCN_TXSTAT_EXDEF)
+ ifp->if_collisions++;
+ if (cur_tx->pcn_txstat & PCN_TXSTAT_RTRY)
+ ifp->if_collisions++;
+ }
+
+ ifp->if_collisions +=
+ cur_tx->pcn_txstat & PCN_TXSTAT_TRC;
+
+ ifp->if_opackets++;
+ if (sc->pcn_cdata.pcn_tx_chain[idx] != NULL) {
+ m_freem(sc->pcn_cdata.pcn_tx_chain[idx]);
+ sc->pcn_cdata.pcn_tx_chain[idx] = NULL;
+ }
+
+ sc->pcn_cdata.pcn_tx_cnt--;
+ PCN_INC(idx, PCN_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->pcn_cdata.pcn_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void pcn_tick(xsc)
+ void *xsc;
+{
+ struct pcn_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+ PCN_LOCK(sc);
+
+ mii = device_get_softc(sc->pcn_miibus);
+ mii_tick(mii);
+
+ /* link just died */
+ if (sc->pcn_link & !(mii->mii_media_status & IFM_ACTIVE))
+ sc->pcn_link = 0;
+
+ /* link just came up, restart */
+ if (!sc->pcn_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->pcn_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ pcn_start(ifp);
+ }
+
+ sc->pcn_stat_ch = timeout(pcn_tick, sc, hz);
+
+ PCN_UNLOCK(sc);
+
+ return;
+}
+
+static void pcn_intr(arg)
+ void *arg;
+{
+ struct pcn_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+
+ /* Supress unwanted interrupts */
+ if (!(ifp->if_flags & IFF_UP)) {
+ pcn_stop(sc);
+ return;
+ }
+
+ CSR_WRITE_4(sc, PCN_IO32_RAP, PCN_CSR_CSR);
+
+ while ((status = CSR_READ_4(sc, PCN_IO32_RDP)) & PCN_CSR_INTR) {
+ CSR_WRITE_4(sc, PCN_IO32_RDP, status);
+
+ if (status & PCN_CSR_RINT)
+ pcn_rxeof(sc);
+
+ if (status & PCN_CSR_TINT)
+ pcn_txeof(sc);
+
+ if (status & PCN_CSR_ERR) {
+ pcn_init(sc);
+ break;
+ }
+ }
+
+ if (ifp->if_snd.ifq_head != NULL)
+ pcn_start(ifp);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int pcn_encap(sc, m_head, txidx)
+ struct pcn_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct pcn_tx_desc *f = NULL;
+ struct mbuf *m;
+ int frag, cur, cnt = 0;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if ((PCN_TX_LIST_CNT -
+ (sc->pcn_cdata.pcn_tx_cnt + cnt)) < 2)
+ return(ENOBUFS);
+ f = &sc->pcn_ldata->pcn_tx_list[frag];
+ f->pcn_txctl = (~(m->m_len) + 1) & PCN_TXCTL_BUFSZ;
+ f->pcn_txctl |= PCN_TXCTL_MBO;
+ f->pcn_tbaddr = vtophys(mtod(m, vm_offset_t));
+ if (cnt == 0)
+ f->pcn_txctl |= PCN_TXCTL_STP;
+ else
+ f->pcn_txctl |= PCN_TXCTL_OWN;
+ cur = frag;
+ PCN_INC(frag, PCN_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->pcn_cdata.pcn_tx_chain[cur] = m_head;
+ sc->pcn_ldata->pcn_tx_list[cur].pcn_txctl |=
+ PCN_TXCTL_ENP|PCN_TXCTL_ADD_FCS|PCN_TXCTL_MORE_LTINT;
+ sc->pcn_ldata->pcn_tx_list[*txidx].pcn_txctl |= PCN_TXCTL_OWN;
+ sc->pcn_cdata.pcn_tx_cnt += cnt;
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+static void pcn_start(ifp)
+ struct ifnet *ifp;
+{
+ struct pcn_softc *sc;
+ struct mbuf *m_head = NULL;
+ u_int32_t idx;
+
+ sc = ifp->if_softc;
+
+ PCN_LOCK(sc);
+
+ if (!sc->pcn_link) {
+ PCN_UNLOCK(sc);
+ return;
+ }
+
+ idx = sc->pcn_cdata.pcn_tx_prod;
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ PCN_UNLOCK(sc);
+ return;
+ }
+
+ while(sc->pcn_cdata.pcn_tx_chain[idx] == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (pcn_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+
+ }
+
+ /* Transmit */
+ sc->pcn_cdata.pcn_tx_prod = idx;
+ pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ PCN_UNLOCK(sc);
+
+ return;
+}
+
+static void pcn_setfilt(ifp)
+ struct ifnet *ifp;
+{
+ struct pcn_softc *sc;
+
+ sc = ifp->if_softc;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC);
+ } else {
+ PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC);
+ }
+
+ /* Set the capture broadcast bit to capture broadcast frames. */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD);
+ } else {
+ PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD);
+ }
+
+ return;
+}
+
+static void pcn_init(xsc)
+ void *xsc;
+{
+ struct pcn_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii = NULL;
+
+ PCN_LOCK(sc);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ pcn_stop(sc);
+ pcn_reset(sc);
+
+ mii = device_get_softc(sc->pcn_miibus);
+
+ /* Set MAC address */
+ pcn_csr_write(sc, PCN_CSR_PAR0,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
+ pcn_csr_write(sc, PCN_CSR_PAR1,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
+ pcn_csr_write(sc, PCN_CSR_PAR2,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
+
+ /* Init circular RX list. */
+ if (pcn_list_rx_init(sc) == ENOBUFS) {
+ printf("pcn%d: initialization failed: no "
+ "memory for rx buffers\n", sc->pcn_unit);
+ pcn_stop(sc);
+ PCN_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ pcn_list_tx_init(sc);
+
+ /* Set up the mode register. */
+ pcn_csr_write(sc, PCN_CSR_MODE, PCN_PORT_MII);
+
+ /* Set up RX filter. */
+ pcn_setfilt(ifp);
+
+ /*
+ * Load the multicast filter.
+ */
+ pcn_setmulti(sc);
+
+ /*
+ * Load the addresses of the RX and TX lists.
+ */
+ pcn_csr_write(sc, PCN_CSR_RXADDR0,
+ vtophys(&sc->pcn_ldata->pcn_rx_list[0]) & 0xFFFF);
+ pcn_csr_write(sc, PCN_CSR_RXADDR1,
+ (vtophys(&sc->pcn_ldata->pcn_rx_list[0]) >> 16) & 0xFFFF);
+ pcn_csr_write(sc, PCN_CSR_TXADDR0,
+ vtophys(&sc->pcn_ldata->pcn_tx_list[0]) & 0xFFFF);
+ pcn_csr_write(sc, PCN_CSR_TXADDR1,
+ (vtophys(&sc->pcn_ldata->pcn_tx_list[0]) >> 16) & 0xFFFF);
+
+ /* Set the RX and TX ring sizes. */
+ pcn_csr_write(sc, PCN_CSR_RXRINGLEN, (~PCN_RX_LIST_CNT) + 1);
+ pcn_csr_write(sc, PCN_CSR_TXRINGLEN, (~PCN_TX_LIST_CNT) + 1);
+
+ /* We're not using the initialization block. */
+ pcn_csr_write(sc, PCN_CSR_IAB1, 0);
+
+ /* Enable fast suspend mode. */
+ PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE);
+
+ /*
+ * Enable burst read and write. Also set the no underflow
+ * bit. This will avoid transmit underruns in certain
+ * conditions while still providing decent performance.
+ */
+ PCN_BCR_SETBIT(sc, PCN_BCR_BUSCTL, PCN_BUSCTL_NOUFLOW|
+ PCN_BUSCTL_BREAD|PCN_BUSCTL_BWRITE);
+
+ /* Enable graceful recovery from underflow. */
+ PCN_CSR_SETBIT(sc, PCN_CSR_IMR, PCN_IMR_DXSUFLO);
+
+ /* Enable auto-padding of short TX frames. */
+ PCN_CSR_SETBIT(sc, PCN_CSR_TFEAT, PCN_TFEAT_PAD_TX);
+
+ /* Disable MII autoneg (we handle this ourselves). */
+ PCN_BCR_SETBIT(sc, PCN_BCR_MIICTL, PCN_MIICTL_DANAS);
+
+ if (sc->pcn_type == Am79C978)
+ pcn_bcr_write(sc, PCN_BCR_PHYSEL,
+ PCN_PHYSEL_PCNET|PCN_PHY_HOMEPNA);
+
+ /* Enable interrupts and start the controller running. */
+ pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_INTEN|PCN_CSR_START);
+
+ mii_mediachg(mii);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->pcn_stat_ch = timeout(pcn_tick, sc, hz);
+ PCN_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int pcn_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct pcn_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->pcn_miibus);
+
+ sc->pcn_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void pcn_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct pcn_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ mii = device_get_softc(sc->pcn_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int pcn_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct pcn_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii = NULL;
+ int error = 0;
+
+ PCN_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->pcn_if_flags & IFF_PROMISC)) {
+ PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1,
+ PCN_EXTCTL1_SPND);
+ pcn_setfilt(ifp);
+ PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1,
+ PCN_EXTCTL1_SPND);
+ pcn_csr_write(sc, PCN_CSR_CSR,
+ PCN_CSR_INTEN|PCN_CSR_START);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->pcn_if_flags & IFF_PROMISC) {
+ PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1,
+ PCN_EXTCTL1_SPND);
+ pcn_setfilt(ifp);
+ PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1,
+ PCN_EXTCTL1_SPND);
+ pcn_csr_write(sc, PCN_CSR_CSR,
+ PCN_CSR_INTEN|PCN_CSR_START);
+ } else if (!(ifp->if_flags & IFF_RUNNING))
+ pcn_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ pcn_stop(sc);
+ }
+ sc->pcn_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ pcn_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->pcn_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ PCN_UNLOCK(sc);
+
+ return(error);
+}
+
+static void pcn_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct pcn_softc *sc;
+
+ sc = ifp->if_softc;
+
+ PCN_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("pcn%d: watchdog timeout\n", sc->pcn_unit);
+
+ pcn_stop(sc);
+ pcn_reset(sc);
+ pcn_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ pcn_start(ifp);
+
+ PCN_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void pcn_stop(sc)
+ struct pcn_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+ PCN_LOCK(sc);
+ ifp->if_timer = 0;
+
+ untimeout(pcn_tick, sc, sc->pcn_stat_ch);
+ PCN_CSR_SETBIT(sc, PCN_CSR_CSR, PCN_CSR_STOP);
+ sc->pcn_link = 0;
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < PCN_RX_LIST_CNT; i++) {
+ if (sc->pcn_cdata.pcn_rx_chain[i] != NULL) {
+ m_freem(sc->pcn_cdata.pcn_rx_chain[i]);
+ sc->pcn_cdata.pcn_rx_chain[i] = NULL;
+ }
+ }
+ bzero((char *)&sc->pcn_ldata->pcn_rx_list,
+ sizeof(sc->pcn_ldata->pcn_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < PCN_TX_LIST_CNT; i++) {
+ if (sc->pcn_cdata.pcn_tx_chain[i] != NULL) {
+ m_freem(sc->pcn_cdata.pcn_tx_chain[i]);
+ sc->pcn_cdata.pcn_tx_chain[i] = NULL;
+ }
+ }
+
+ bzero((char *)&sc->pcn_ldata->pcn_tx_list,
+ sizeof(sc->pcn_ldata->pcn_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ PCN_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void pcn_shutdown(dev)
+ device_t dev;
+{
+ struct pcn_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ PCN_LOCK(sc);
+ pcn_reset(sc);
+ pcn_stop(sc);
+ PCN_UNLOCK(sc);
+
+ return;
+}
diff --git a/sys/pci/if_pcnreg.h b/sys/pci/if_pcnreg.h
new file mode 100644
index 0000000..79ef531
--- /dev/null
+++ b/sys/pci/if_pcnreg.h
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2000 Berkeley Software Design, Inc.
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@ee.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * I/O map in 16-bit mode. To switch to 32-bit mode,
+ * you need to perform a 32-bit write to the RDP register
+ * (writing a 0 is recommended).
+ */
+#define PCN_IO16_APROM00 0x00
+#define PCN_IO16_APROM01 0x02
+#define PCN_IO16_APROM02 0x04
+#define PCN_IO16_APROM03 0x06
+#define PCN_IO16_APROM04 0x08
+#define PCN_IO16_APROM05 0x0A
+#define PCN_IO16_APROM06 0x0C
+#define PCN_IO16_APROM07 0x0E
+#define PCN_IO16_RDP 0x10
+#define PCN_IO16_RAP 0x12
+#define PCN_IO16_RESET 0x14
+#define PCN_IO16_BDP 0x16
+
+/*
+ * I/O map in 32-bit mode.
+ */
+#define PCN_IO32_APROM00 0x00
+#define PCN_IO32_APROM01 0x04
+#define PCN_IO32_APROM02 0x08
+#define PCN_IO32_APROM03 0x0C
+#define PCN_IO32_RDP 0x10
+#define PCN_IO32_RAP 0x14
+#define PCN_IO32_RESET 0x18
+#define PCN_IO32_BDP 0x1C
+
+/*
+ * CSR registers
+ */
+#define PCN_CSR_CSR 0x00
+#define PCN_CSR_IAB0 0x01
+#define PCN_CSR_IAB1 0x02
+#define PCN_CSR_IMR 0x03
+#define PCN_CSR_TFEAT 0x04
+#define PCN_CSR_EXTCTL1 0x05
+#define PCN_CSR_DTBLLEN 0x06
+#define PCN_CSR_EXTCTL2 0x07
+#define PCN_CSR_MAR0 0x08
+#define PCN_CSR_MAR1 0x09
+#define PCN_CSR_MAR2 0x0A
+#define PCN_CSR_MAR3 0x0B
+#define PCN_CSR_PAR0 0x0C
+#define PCN_CSR_PAR1 0x0D
+#define PCN_CSR_PAR2 0x0E
+#define PCN_CSR_MODE 0x0F
+#define PCN_CSR_RXADDR0 0x18
+#define PCN_CSR_RXADDR1 0x19
+#define PCN_CSR_TXADDR0 0x1E
+#define PCN_CSR_TXADDR1 0x1F
+#define PCN_CSR_TXPOLL 0x2F
+#define PCN_CSR_RXPOLL 0x31
+#define PCN_CSR_RXRINGLEN 0x4C
+#define PCN_CSR_TXRINGLEN 0x4E
+#define PCN_CSR_DMACTL 0x50
+#define PCN_CSR_BUSTIMER 0x52
+#define PCN_CSR_MEMERRTIMEO 0x64
+#define PCN_CSR_ONNOWMISC 0x74
+#define PCN_CSR_ADVFEAT 0x7A
+#define PCN_CSR_MACCFG 0x7D
+#define PCN_CSR_CHIPID0 0x58
+#define PCN_CSR_CHIPID1 0x59
+
+/*
+ * Control and status register (CSR0)
+ */
+#define PCN_CSR_INIT 0x0001
+#define PCN_CSR_START 0x0002
+#define PCN_CSR_STOP 0x0004
+#define PCN_CSR_TX 0x0008
+#define PCN_CSR_TXON 0x0010
+#define PCN_CSR_RXON 0x0020
+#define PCN_CSR_INTEN 0x0040
+#define PCN_CSR_INTR 0x0080
+#define PCN_CSR_IDONE 0x0100
+#define PCN_CSR_TINT 0x0200
+#define PCN_CSR_RINT 0x0400
+#define PCN_CSR_MERR 0x0800
+#define PCN_CSR_MISS 0x1000
+#define PCN_CSR_CERR 0x2000
+#define PCN_CSR_ERR 0x8000
+
+/*
+ * Interrupt masks and deferral control (CSR3)
+ */
+#define PCN_IMR_BSWAP 0x0004
+#define PCN_IMR_ENMBA 0x0008 /* enable modified backoff alg */
+#define PCN_IMR_DXMT2PD 0x0010
+#define PCN_IMR_LAPPEN 0x0020 /* lookahead packet processing enb */
+#define PCN_IMR_DXSUFLO 0x0040 /* disable TX stop on underflow */
+#define PCN_IMR_IDONE 0x0100
+#define PCN_IMR_TINT 0x0200
+#define PCN_IMR_RINT 0x0400
+#define PCN_IMR_MERR 0x0800
+#define PCN_IMR_MISS 0x1000
+
+/*
+ * Test and features control (CSR4)
+ */
+#define PCN_TFEAT_TXSTRTMASK 0x0004
+#define PCN_TFEAT_TXSTRT 0x0008
+#define PCN_TFEAT_RXCCOFLOWM 0x0010 /* Rx collision counter oflow */
+#define PCN_TFEAT_RXCCOFLOW 0x0020
+#define PCN_TFEAT_UINT 0x0040
+#define PCN_TFEAT_UINTREQ 0x0080
+#define PCN_TFEAT_MISSOFLOWM 0x0100
+#define PCN_TFEAT_MISSOFLOW 0x0200
+#define PCN_TFEAT_STRIP_FCS 0x0400
+#define PCN_TFEAT_PAD_TX 0x0800
+#define PCN_TFEAT_TXDPOLL 0x1000
+#define PCN_TFEAT_DMAPLUS 0x4000
+
+/*
+ * Extended control and interrupt 1 (CSR5)
+ */
+#define PCN_EXTCTL1_SPND 0x0001 /* suspend */
+#define PCN_EXTCTL1_MPMODE 0x0002 /* magic packet mode */
+#define PCN_EXTCTL1_MPENB 0x0004 /* magic packet enable */
+#define PCN_EXTCTL1_MPINTEN 0x0008 /* magic packet interrupt enable */
+#define PCN_EXTCTL1_MPINT 0x0010 /* magic packet interrupt */
+#define PCN_EXTCTL1_MPPLBA 0x0020 /* magic packet phys. logical bcast */
+#define PCN_EXTCTL1_EXDEFEN 0x0040 /* excessive deferral interrupt enb. */
+#define PCN_EXTCTL1_EXDEF 0x0080 /* excessive deferral interrupt */
+#define PCN_EXTCTL1_SINTEN 0x0400 /* system interrupt enable */
+#define PCN_EXTCTL1_SINT 0x0800 /* system interrupt */
+#define PCN_EXTCTL1_LTINTEN 0x4000 /* last TX interrupt enb */
+#define PCN_EXTCTL1_TXOKINTD 0x8000 /* TX OK interrupt disable */
+
+/*
+ * RX/TX descriptor len (CSR6)
+ */
+#define PCN_DTBLLEN_RLEN 0x0F00
+#define PCN_DTBLLEN_TLEN 0xF000
+
+/*
+ * Extended control and interrupt 2 (CSR7)
+ */
+#define PCN_EXTCTL2_MIIPDTINTE 0x0001
+#define PCN_EXTCTL2_MIIPDTINT 0x0002
+#define PCN_EXTCTL2_MCCIINTE 0x0004
+#define PCN_EXTCTL2_MCCIINT 0x0008
+#define PCN_EXTCTL2_MCCINTE 0x0010
+#define PCN_EXTCTL2_MCCINT 0x0020
+#define PCN_EXTCTL2_MAPINTE 0x0040
+#define PCN_EXTCTL2_MAPINT 0x0080
+#define PCN_EXTCTL2_MREINTE 0x0100
+#define PCN_EXTCTL2_MREINT 0x0200
+#define PCN_EXTCTL2_STINTE 0x0400
+#define PCN_EXTCTL2_STINT 0x0800
+#define PCN_EXTCTL2_RXDPOLL 0x1000
+#define PCN_EXTCTL2_RDMD 0x2000
+#define PCN_EXTCTL2_RXFRTG 0x4000
+#define PCN_EXTCTL2_FASTSPNDE 0x8000
+
+
+/*
+ * Mode (CSR15)
+ */
+#define PCN_MODE_RXD 0x0001 /* RX disable */
+#define PCN_MODE_TXD 0x0002 /* TX disable */
+#define PCN_MODE_LOOP 0x0004 /* loopback enable */
+#define PCN_MODE_TXCRCD 0x0008
+#define PCN_MODE_FORCECOLL 0x0010
+#define PCN_MODE_RETRYD 0x0020
+#define PCN_MODE_INTLOOP 0x0040
+#define PCN_MODE_PORTSEL 0x0180
+#define PCN_MODE_RXVPAD 0x2000
+#define PCN_MODE_RXNOBROAD 0x4000
+#define PCN_MODE_PROMISC 0x8000
+
+#define PCN_PORT_GPSI 0x0100
+#define PCN_PORT_MII 0x0180
+
+/*
+ * Chip ID values.
+ */
+/* CSR88-89: Chip ID masks */
+#define AMD_MASK 0x003
+#define PART_MASK 0xffff
+#define Am79C960 0x0003
+#define Am79C961 0x2260
+#define Am79C961A 0x2261
+#define Am79C965 0x2430
+#define Am79C970 0x0242
+#define Am79C970A 0x2621
+#define Am79C971 0x2623
+#define Am79C972 0x2624
+#define Am79C973 0x2625
+#define Am79C978 0x2626
+#define Am79C975 0x2627
+#define Am79C976 0x2628
+
+/*
+ * Advanced feature control (CSR122)
+ */
+#define PCN_AFC_RXALIGN 0x0001
+
+/*
+ * BCR (bus control) registers
+ */
+#define PCN_BCR_MISCCFG 0x02
+#define PCN_BCR_LED0 0x04
+#define PCN_BCR_LED1 0x05
+#define PCN_BCR_LED2 0x06
+#define PCN_BCR_LED3 0x07
+#define PCN_BCR_DUPLEX 0x09
+#define PCN_BCR_BUSCTL 0x12
+#define PCN_BCR_EECTL 0x13
+#define PCN_BCR_SSTYLE 0x14
+#define PCN_BCR_PCILAT 0x16
+#define PCN_BCR_PCISUBVENID 0x17
+#define PCN_BCR_PCISUBSYSID 0x18
+#define PCN_BCR_SRAMSIZE 0x19
+#define PCN_BCR_SRAMBOUND 0x1A
+#define PCN_BCR_SRAMCTL 0x1B
+#define PCN_BCR_MIICTL 0x20
+#define PCN_BCR_MIIADDR 0x21
+#define PCN_BCR_MIIDATA 0x22
+#define PCN_BCR_PCIVENID 0x23
+#define PCN_BCR_PCIPCAP 0x24
+#define PCN_BCR_DATA0 0x25
+#define PCN_BCR_DATA1 0x26
+#define PCN_BCR_DATA2 0x27
+#define PCN_BCR_DATA3 0x28
+#define PCN_BCR_DATA4 0x29
+#define PCN_BCR_DATA5 0x2A
+#define PCN_BCR_DATA6 0x2B
+#define PCN_BCR_DATA7 0x2C
+#define PCN_BCR_ONNOWPAT0 0x2D
+#define PCN_BCR_ONNOWPAT1 0x2E
+#define PCN_BCR_ONNOWPAT2 0x2F
+#define PCN_BCR_PHYSEL 0x31
+
+/*
+ * Full duplex control (BCR9)
+ */
+#define PCN_DUPLEX_FDEN 0x0001 /* Full-duplex enable */
+#define PCN_DUPLEX_FDRPAD 0x0004 /* Full-duplex runt pkt accept dis. */
+
+/*
+ * Burst and bus control register (BCR18)
+ */
+#define PCN_BUSCTL_BWRITE 0x0020
+#define PCN_BUSCTL_BREAD 0x0040
+#define PCN_BUSCTL_DWIO 0x0080
+#define PCN_BUSCTL_EXTREQ 0x0100
+#define PCN_BUSCTL_MEMCMD 0x0200
+#define PCN_BUSCTL_NOUFLOW 0x0800
+#define PCN_BUSCTL_ROMTMG 0xF000
+
+/*
+ * EEPROM control (BCR19)
+ */
+#define PCN_EECTL_EDATA 0x0001
+#define PCN_EECTL_ECLK 0x0002
+#define PCN_EECTL_EECS 0x0004
+#define PCN_EECTL_EEN 0x0100
+#define PCN_EECTL_EEDET 0x2000
+#define PCN_EECTL_PREAD 0x4000
+#define PCN_EECTL_PVALID 0x8000
+
+/*
+ * Software style (BCR20)
+ */
+#define PCN_SSTYLE_APERREN 0x0400 /* advanced parity error checking */
+#define PCN_SSTYLE_SSIZE32 0x0100
+#define PCN_SSTYLE_SWSTYLE 0x00FF
+
+#define PCN_SWSTYLE_LANCE 0x0000
+#define PCN_SWSTYLE_PCNETPCI 0x0102
+#define PCN_SWSTYLE_PCNETPCI_BURST 0x0103
+
+/*
+ * MII control and status (BCR32)
+ */
+#define PCN_MIICTL_MIILP 0x0002 /* MII internal loopback */
+#define PCN_MIICTL_XPHYSP 0x0008 /* external PHY speed */
+#define PCN_MIICTL_XPHYFD 0x0010 /* external PHY full duplex */
+#define PCN_MIICTL_XPHYANE 0x0020 /* external phy auto-neg enable */
+#define PCN_MIICTL_XPHYRST 0x0040 /* external PHY reset */
+#define PCN_MIICTL_DANAS 0x0080 /* disable auto-neg auto-setup */
+#define PCN_MIICTL_APDW 0x0700 /* auto-poll dwell time */
+#define PCN_MIICTL_APEP 0x0100 /* auto-poll external PHY */
+#define PCN_MIICTL_FMDC 0x3000 /* data clock speed */
+#define PCN_MIICTL_MIIPD 0x4000 /* PHY detect */
+#define PCN_MIICTL_ANTST 0x8000 /* Manufacturing test */
+
+/*
+ * MII address register (BCR33)
+ */
+#define PCN_MIIADDR_REGAD 0x001F
+#define PCN_MIIADDR_PHYADD 0x03E0
+
+/*
+ * MII data register (BCR34)
+ */
+#define PCN_MIIDATA_MIIMD 0xFFFF
+
+/*
+ * PHY selection (BCR49) (HomePNA NIC only)
+ */
+#define PCN_PHYSEL_PHYSEL 0x0003
+#define PCN_PHYSEL_DEFAULT 0x0300
+#define PCN_PHYSEL_PCNET 0x8000
+
+#define PCN_PHY_10BT 0x0000
+#define PCN_PHY_HOMEPNA 0x0001
+#define PCN_PHY_EXTERNAL 0x0002
+
+struct pcn_rx_desc {
+ u_int16_t pcn_rxlen;
+ u_int16_t pcn_rsvd0;
+ u_int16_t pcn_bufsz;
+ u_int16_t pcn_rxstat;
+ u_int32_t pcn_rbaddr;
+ u_int32_t pcn_uspace;
+};
+
+#define PCN_RXSTAT_BPE 0x0080 /* bus parity error */
+#define PCN_RXSTAT_ENP 0x0100 /* end of packet */
+#define PCN_RXSTAT_STP 0x0200 /* start of packet */
+#define PCN_RXSTAT_BUFF 0x0400 /* buffer error */
+#define PCN_RXSTAT_CRC 0x0800 /* CRC error */
+#define PCN_RXSTAT_OFLOW 0x1000 /* rx overrun */
+#define PCN_RXSTAT_FRAM 0x2000 /* framing error */
+#define PCN_RXSTAT_ERR 0x4000 /* error summary */
+#define PCN_RXSTAT_OWN 0x8000
+
+#define PCN_RXLEN_MBO 0xF000
+#define PCN_RXLEN_BUFSZ 0x0FFF
+
+#define PCN_OWN_RXDESC(x) (((x)->pcn_rxstat & PCN_RXSTAT_OWN) == 0)
+
+struct pcn_tx_desc {
+ u_int32_t pcn_txstat;
+ u_int32_t pcn_txctl;
+ u_int32_t pcn_tbaddr;
+ u_int32_t pcn_uspace;
+};
+
+#define PCN_TXSTAT_TRC 0x0000000F /* transmit retries */
+#define PCN_TXSTAT_RTRY 0x04000000 /* retry */
+#define PCN_TXSTAT_LCAR 0x08000000 /* lost carrier */
+#define PCN_TXSTAT_LCOL 0x10000000 /* late collision */
+#define PCN_TXSTAT_EXDEF 0x20000000 /* excessive deferrals */
+#define PCN_TXSTAT_UFLOW 0x40000000 /* transmit underrun */
+#define PCN_TXSTAT_BUFF 0x80000000 /* buffer error */
+
+#define PCN_TXCTL_OWN 0x80000000
+#define PCN_TXCTL_ERR 0x40000000 /* error summary */
+#define PCN_TXCTL_ADD_FCS 0x20000000 /* add FCS to pkt */
+#define PCN_TXCTL_MORE_LTINT 0x10000000
+#define PCN_TXCTL_ONE 0x08000000
+#define PCN_TXCTL_DEF 0x04000000
+#define PCN_TXCTL_STP 0x02000000
+#define PCN_TXCTL_ENP 0x01000000
+#define PCN_TXCTL_BPE 0x00800000
+#define PCN_TXCTL_MBO 0x0000F000
+#define PCN_TXCTL_BUFSZ 0x00000FFF
+
+#define PCN_OWN_TXDESC(x) (((x)->pcn_txctl & PCN_TXCTL_OWN) == 0)
+
+#define PCN_RX_LIST_CNT 64
+#define PCN_TX_LIST_CNT 256
+
+struct pcn_list_data {
+ struct pcn_rx_desc pcn_rx_list[PCN_RX_LIST_CNT];
+ struct pcn_tx_desc pcn_tx_list[PCN_TX_LIST_CNT];
+};
+
+struct pcn_ring_data {
+ struct mbuf *pcn_rx_chain[PCN_RX_LIST_CNT];
+ struct mbuf *pcn_tx_chain[PCN_TX_LIST_CNT];
+ int pcn_rx_prod;
+ int pcn_tx_prod;
+ int pcn_tx_cons;
+ int pcn_tx_cnt;
+};
+
+/*
+ * AMD PCI vendor ID.
+ */
+#define PCN_VENDORID 0x1022
+
+/*
+ * AMD PCnet/PCI device IDs
+ */
+#define PCN_DEVICEID_PCNET 0x2000
+#define PCN_DEVICEID_HOME 0x2001
+
+struct pcn_type {
+ u_int16_t pcn_vid;
+ u_int16_t pcn_did;
+ char *pcn_name;
+};
+
+struct pcn_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t pcn_bhandle;
+ bus_space_tag_t pcn_btag;
+ struct resource *pcn_res;
+ struct resource *pcn_irq;
+ void *pcn_intrhand;
+ device_t pcn_miibus;
+ u_int8_t pcn_unit;
+ u_int8_t pcn_link;
+ u_int8_t pcn_phyaddr;
+ int pcn_if_flags;
+ int pcn_type;
+ struct pcn_list_data *pcn_ldata;
+ struct pcn_ring_data pcn_cdata;
+ struct callout_handle pcn_stat_ch;
+ struct mtx pcn_mtx;
+};
+
+#define PCN_LOCK(_sc) mtx_lock(&(_sc)->pcn_mtx)
+#define PCN_UNLOCK(_sc) mtx_unlock(&(_sc)->pcn_mtx)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->pcn_btag, sc->pcn_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->pcn_btag, sc->pcn_bhandle, reg)
+
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->pcn_btag, sc->pcn_bhandle, reg, val)
+
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->pcn_btag, sc->pcn_bhandle, reg)
+
+
+#define PCN_TIMEOUT 1000
+#define ETHER_ALIGN 2
+#define PCN_RXLEN 1536
+#define PCN_MIN_FRAMELEN 60
+#define PCN_INC(x, y) (x) = (x + 1) % y
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define PCN_PCI_VENDOR_ID 0x00
+#define PCN_PCI_DEVICE_ID 0x02
+#define PCN_PCI_COMMAND 0x04
+#define PCN_PCI_STATUS 0x06
+#define PCN_PCI_REVID 0x08
+#define PCN_PCI_CLASSCODE 0x09
+#define PCN_PCI_CACHELEN 0x0C
+#define PCN_PCI_LATENCY_TIMER 0x0D
+#define PCN_PCI_HEADER_TYPE 0x0E
+#define PCN_PCI_LOIO 0x10
+#define PCN_PCI_LOMEM 0x14
+#define PCN_PCI_BIOSROM 0x30
+#define PCN_PCI_INTLINE 0x3C
+#define PCN_PCI_INTPIN 0x3D
+#define PCN_PCI_MINGNT 0x3E
+#define PCN_PCI_MINLAT 0x0F
+#define PCN_PCI_RESETOPT 0x48
+#define PCN_PCI_EEPROM_DATA 0x4C
+
+/* power management registers */
+#define PCN_PCI_CAPID 0x50 /* 8 bits */
+#define PCN_PCI_NEXTPTR 0x51 /* 8 bits */
+#define PCN_PCI_PWRMGMTCAP 0x52 /* 16 bits */
+#define PCN_PCI_PWRMGMTCTRL 0x54 /* 16 bits */
+
+#define PCN_PSTATE_MASK 0x0003
+#define PCN_PSTATE_D0 0x0000
+#define PCN_PSTATE_D1 0x0001
+#define PCN_PSTATE_D2 0x0002
+#define PCN_PSTATE_D3 0x0003
+#define PCN_PME_EN 0x0010
+#define PCN_PME_STATUS 0x8000
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c
new file mode 100644
index 0000000..99ef4dd
--- /dev/null
+++ b/sys/pci/if_rl.c
@@ -0,0 +1,1904 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * RealTek 8129/8139 PCI NIC driver
+ *
+ * Supports several extremely cheap PCI 10/100 adapters based on
+ * the RealTek chipset. Datasheets can be obtained from
+ * www.realtek.com.tw.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The RealTek 8139 PCI NIC redefines the meaning of 'low end.' This is
+ * probably the worst PCI ethernet controller ever made, with the possible
+ * exception of the FEAST chip made by SMC. The 8139 supports bus-master
+ * DMA, but it has a terrible interface that nullifies any performance
+ * gains that bus-master DMA usually offers.
+ *
+ * For transmission, the chip offers a series of four TX descriptor
+ * registers. Each transmit frame must be in a contiguous buffer, aligned
+ * on a longword (32-bit) boundary. This means we almost always have to
+ * do mbuf copies in order to transmit a frame, except in the unlikely
+ * case where a) the packet fits into a single mbuf, and b) the packet
+ * is 32-bit aligned within the mbuf's data area. The presence of only
+ * four descriptor registers means that we can never have more than four
+ * packets queued for transmission at any one time.
+ *
+ * Reception is not much better. The driver has to allocate a single large
+ * buffer area (up to 64K in size) into which the chip will DMA received
+ * frames. Because we don't know where within this region received packets
+ * will begin or end, we have no choice but to copy data from the buffer
+ * area into mbufs in order to pass the packets up to the higher protocol
+ * levels.
+ *
+ * It's impossible given this rotten design to really achieve decent
+ * performance at 100Mbps, unless you happen to have a 400Mhz PII or
+ * some equally overmuscled CPU to drive it.
+ *
+ * On the bright side, the 8139 does have a built-in PHY, although
+ * rather than using an MDIO serial interface like most other NICs, the
+ * PHY registers are directly accessible through the 8139's register
+ * space. The 8139 supports autonegotiation, as well as a 64-bit multicast
+ * filter.
+ *
+ * The 8129 chip is an older version of the 8139 that uses an external PHY
+ * chip. The 8129 has a serial MDIO interface for accessing the MII where
+ * the 8139 lets you directly access the on-board PHY registers. We need
+ * to select which interface to use depending on the chip type.
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+MODULE_DEPEND(rl, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+/*
+ * Default to using PIO access for this driver. On SMP systems,
+ * there appear to be problems with memory mapped mode: it looks like
+ * doing too many memory mapped access back to back in rapid succession
+ * can hang the bus. I'm inclined to blame this on crummy design/construction
+ * on the part of RealTek. Memory mapped mode does appear to work on
+ * uniprocessor systems though.
+ */
+#define RL_USEIOSPACE
+
+#include <pci/if_rlreg.h>
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct rl_type rl_devs[] = {
+ { RT_VENDORID, RT_DEVICEID_8129,
+ "RealTek 8129 10/100BaseTX" },
+ { RT_VENDORID, RT_DEVICEID_8139,
+ "RealTek 8139 10/100BaseTX" },
+ { RT_VENDORID, RT_DEVICEID_8138,
+ "RealTek 8139 10/100BaseTX CardBus" },
+ { ACCTON_VENDORID, ACCTON_DEVICEID_5030,
+ "Accton MPX 5030/5038 10/100BaseTX" },
+ { DELTA_VENDORID, DELTA_DEVICEID_8139,
+ "Delta Electronics 8139 10/100BaseTX" },
+ { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139,
+ "Addtron Technolgy 8139 10/100BaseTX" },
+ { DLINK_VENDORID, DLINK_DEVICEID_530TXPLUS,
+ "D-Link DFE-530TX+ 10/100BaseTX" },
+ { DLINK_VENDORID, DLINK_DEVICEID_690TXD,
+ "D-Link DFE-690TXD 10/100BaseTX" },
+ { NORTEL_VENDORID, ACCTON_DEVICEID_5030,
+ "Nortel Networks 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int rl_probe (device_t);
+static int rl_attach (device_t);
+static int rl_detach (device_t);
+
+static int rl_encap (struct rl_softc *, struct mbuf * );
+
+static void rl_rxeof (struct rl_softc *);
+static void rl_txeof (struct rl_softc *);
+static void rl_intr (void *);
+static void rl_tick (void *);
+static void rl_start (struct ifnet *);
+static int rl_ioctl (struct ifnet *, u_long, caddr_t);
+static void rl_init (void *);
+static void rl_stop (struct rl_softc *);
+static void rl_watchdog (struct ifnet *);
+static int rl_suspend (device_t);
+static int rl_resume (device_t);
+static void rl_shutdown (device_t);
+static int rl_ifmedia_upd (struct ifnet *);
+static void rl_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void rl_eeprom_putbyte (struct rl_softc *, int);
+static void rl_eeprom_getword (struct rl_softc *, int, u_int16_t *);
+static void rl_read_eeprom (struct rl_softc *, caddr_t, int, int, int);
+static void rl_mii_sync (struct rl_softc *);
+static void rl_mii_send (struct rl_softc *, u_int32_t, int);
+static int rl_mii_readreg (struct rl_softc *, struct rl_mii_frame *);
+static int rl_mii_writereg (struct rl_softc *, struct rl_mii_frame *);
+
+static int rl_miibus_readreg (device_t, int, int);
+static int rl_miibus_writereg (device_t, int, int, int);
+static void rl_miibus_statchg (device_t);
+
+static u_int8_t rl_calchash (caddr_t);
+static void rl_setmulti (struct rl_softc *);
+static void rl_reset (struct rl_softc *);
+static int rl_list_tx_init (struct rl_softc *);
+
+static void rl_dma_map_rxbuf (void *, bus_dma_segment_t *, int, int);
+static void rl_dma_map_txbuf (void *, bus_dma_segment_t *, int, int);
+
+#ifdef RL_USEIOSPACE
+#define RL_RES SYS_RES_IOPORT
+#define RL_RID RL_PCI_LOIO
+#else
+#define RL_RES SYS_RES_MEMORY
+#define RL_RID RL_PCI_LOMEM
+#endif
+
+static device_method_t rl_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rl_probe),
+ DEVMETHOD(device_attach, rl_attach),
+ DEVMETHOD(device_detach, rl_detach),
+ DEVMETHOD(device_suspend, rl_suspend),
+ DEVMETHOD(device_resume, rl_resume),
+ DEVMETHOD(device_shutdown, rl_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, rl_miibus_readreg),
+ DEVMETHOD(miibus_writereg, rl_miibus_writereg),
+ DEVMETHOD(miibus_statchg, rl_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t rl_driver = {
+ "rl",
+ rl_methods,
+ sizeof(struct rl_softc)
+};
+
+static devclass_t rl_devclass;
+
+DRIVER_MODULE(if_rl, pci, rl_driver, rl_devclass, 0, 0);
+DRIVER_MODULE(if_rl, cardbus, rl_driver, rl_devclass, 0, 0);
+DRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0);
+
+#define EE_SET(x) \
+ CSR_WRITE_1(sc, RL_EECMD, \
+ CSR_READ_1(sc, RL_EECMD) | x)
+
+#define EE_CLR(x) \
+ CSR_WRITE_1(sc, RL_EECMD, \
+ CSR_READ_1(sc, RL_EECMD) & ~x)
+
+static void
+rl_dma_map_rxbuf(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg, error;
+{
+ struct rl_softc *sc;
+
+ sc = arg;
+ CSR_WRITE_4(sc, RL_RXADDR, segs->ds_addr & 0xFFFFFFFF);
+
+ return;
+}
+
+static void
+rl_dma_map_txbuf(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg, error;
+{
+ struct rl_softc *sc;
+
+ sc = arg;
+ CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), segs->ds_addr & 0xFFFFFFFF);
+
+ return;
+}
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void rl_eeprom_putbyte(sc, addr)
+ struct rl_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ d = addr | sc->rl_eecmd_read;
+
+ /*
+ * Feed in each bit and strobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ EE_SET(RL_EE_DATAIN);
+ } else {
+ EE_CLR(RL_EE_DATAIN);
+ }
+ DELAY(100);
+ EE_SET(RL_EE_CLK);
+ DELAY(150);
+ EE_CLR(RL_EE_CLK);
+ DELAY(100);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void rl_eeprom_getword(sc, addr, dest)
+ struct rl_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);
+
+ /*
+ * Send address of word we want to read.
+ */
+ rl_eeprom_putbyte(sc, addr);
+
+ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ EE_SET(RL_EE_CLK);
+ DELAY(100);
+ if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT)
+ word |= i;
+ EE_CLR(RL_EE_CLK);
+ DELAY(100);
+ }
+
+ /* Turn off EEPROM access mode. */
+ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void rl_read_eeprom(sc, dest, off, cnt, swap)
+ struct rl_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ rl_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+
+/*
+ * MII access routines are provided for the 8129, which
+ * doesn't have a built-in PHY. For the 8139, we fake things
+ * up by diverting rl_phy_readreg()/rl_phy_writereg() to the
+ * direct access PHY registers.
+ */
+#define MII_SET(x) \
+ CSR_WRITE_1(sc, RL_MII, \
+ CSR_READ_1(sc, RL_MII) | x)
+
+#define MII_CLR(x) \
+ CSR_WRITE_1(sc, RL_MII, \
+ CSR_READ_1(sc, RL_MII) & ~x)
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void rl_mii_sync(sc)
+ struct rl_softc *sc;
+{
+ register int i;
+
+ MII_SET(RL_MII_DIR|RL_MII_DATAOUT);
+
+ for (i = 0; i < 32; i++) {
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void rl_mii_send(sc, bits, cnt)
+ struct rl_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ MII_CLR(RL_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ MII_SET(RL_MII_DATAOUT);
+ } else {
+ MII_CLR(RL_MII_DATAOUT);
+ }
+ DELAY(1);
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ MII_SET(RL_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int rl_mii_readreg(sc, frame)
+ struct rl_softc *sc;
+ struct rl_mii_frame *frame;
+
+{
+ int i, ack;
+
+ RL_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = RL_MII_STARTDELIM;
+ frame->mii_opcode = RL_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ CSR_WRITE_2(sc, RL_MII, 0);
+
+ /*
+ * Turn on data xmit.
+ */
+ MII_SET(RL_MII_DIR);
+
+ rl_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ rl_mii_send(sc, frame->mii_stdelim, 2);
+ rl_mii_send(sc, frame->mii_opcode, 2);
+ rl_mii_send(sc, frame->mii_phyaddr, 5);
+ rl_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ MII_CLR((RL_MII_CLK|RL_MII_DATAOUT));
+ DELAY(1);
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ MII_CLR(RL_MII_DIR);
+
+ /* Check for ack */
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+ ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN;
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+
+ RL_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int rl_mii_writereg(sc, frame)
+ struct rl_softc *sc;
+ struct rl_mii_frame *frame;
+
+{
+ RL_LOCK(sc);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = RL_MII_STARTDELIM;
+ frame->mii_opcode = RL_MII_WRITEOP;
+ frame->mii_turnaround = RL_MII_TURNAROUND;
+
+ /*
+ * Turn on data output.
+ */
+ MII_SET(RL_MII_DIR);
+
+ rl_mii_sync(sc);
+
+ rl_mii_send(sc, frame->mii_stdelim, 2);
+ rl_mii_send(sc, frame->mii_opcode, 2);
+ rl_mii_send(sc, frame->mii_phyaddr, 5);
+ rl_mii_send(sc, frame->mii_regaddr, 5);
+ rl_mii_send(sc, frame->mii_turnaround, 2);
+ rl_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ MII_SET(RL_MII_CLK);
+ DELAY(1);
+ MII_CLR(RL_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ MII_CLR(RL_MII_DIR);
+
+ RL_UNLOCK(sc);
+
+ return(0);
+}
+
+static int rl_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct rl_softc *sc;
+ struct rl_mii_frame frame;
+ u_int16_t rval = 0;
+ u_int16_t rl8139_reg = 0;
+
+ sc = device_get_softc(dev);
+ RL_LOCK(sc);
+
+ if (sc->rl_type == RL_8139) {
+ /* Pretend the internal PHY is only at address 0 */
+ if (phy) {
+ RL_UNLOCK(sc);
+ return(0);
+ }
+ switch(reg) {
+ case MII_BMCR:
+ rl8139_reg = RL_BMCR;
+ break;
+ case MII_BMSR:
+ rl8139_reg = RL_BMSR;
+ break;
+ case MII_ANAR:
+ rl8139_reg = RL_ANAR;
+ break;
+ case MII_ANER:
+ rl8139_reg = RL_ANER;
+ break;
+ case MII_ANLPAR:
+ rl8139_reg = RL_LPAR;
+ break;
+ case MII_PHYIDR1:
+ case MII_PHYIDR2:
+ RL_UNLOCK(sc);
+ return(0);
+ break;
+ /*
+ * Allow the rlphy driver to read the media status
+ * register. If we have a link partner which does not
+ * support NWAY, this is the register which will tell
+ * us the results of parallel detection.
+ */
+ case RL_MEDIASTAT:
+ rval = CSR_READ_1(sc, RL_MEDIASTAT);
+ RL_UNLOCK(sc);
+ return(rval);
+ break;
+ default:
+ printf("rl%d: bad phy register\n", sc->rl_unit);
+ RL_UNLOCK(sc);
+ return(0);
+ }
+ rval = CSR_READ_2(sc, rl8139_reg);
+ RL_UNLOCK(sc);
+ return(rval);
+ }
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ rl_mii_readreg(sc, &frame);
+ RL_UNLOCK(sc);
+
+ return(frame.mii_data);
+}
+
+static int rl_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct rl_softc *sc;
+ struct rl_mii_frame frame;
+ u_int16_t rl8139_reg = 0;
+
+ sc = device_get_softc(dev);
+ RL_LOCK(sc);
+
+ if (sc->rl_type == RL_8139) {
+ /* Pretend the internal PHY is only at address 0 */
+ if (phy) {
+ RL_UNLOCK(sc);
+ return(0);
+ }
+ switch(reg) {
+ case MII_BMCR:
+ rl8139_reg = RL_BMCR;
+ break;
+ case MII_BMSR:
+ rl8139_reg = RL_BMSR;
+ break;
+ case MII_ANAR:
+ rl8139_reg = RL_ANAR;
+ break;
+ case MII_ANER:
+ rl8139_reg = RL_ANER;
+ break;
+ case MII_ANLPAR:
+ rl8139_reg = RL_LPAR;
+ break;
+ case MII_PHYIDR1:
+ case MII_PHYIDR2:
+ RL_UNLOCK(sc);
+ return(0);
+ break;
+ default:
+ printf("rl%d: bad phy register\n", sc->rl_unit);
+ RL_UNLOCK(sc);
+ return(0);
+ }
+ CSR_WRITE_2(sc, rl8139_reg, data);
+ RL_UNLOCK(sc);
+ return(0);
+ }
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ rl_mii_writereg(sc, &frame);
+
+ RL_UNLOCK(sc);
+ return(0);
+}
+
+static void rl_miibus_statchg(dev)
+ device_t dev;
+{
+ return;
+}
+
+/*
+ * Calculate CRC of a multicast group address, return the upper 6 bits.
+ */
+static u_int8_t rl_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return(crc >> 26);
+}
+
+/*
+ * Program the 64-bit multicast hash filter.
+ */
+static void rl_setmulti(sc)
+ struct rl_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+ u_int32_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ rxfilt = CSR_READ_4(sc, RL_RXCFG);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= RL_RXCFG_RX_MULTI;
+ CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
+ CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF);
+ CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, RL_MAR0, 0);
+ CSR_WRITE_4(sc, RL_MAR4, 0);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ mcnt++;
+ }
+
+ if (mcnt)
+ rxfilt |= RL_RXCFG_RX_MULTI;
+ else
+ rxfilt &= ~RL_RXCFG_RX_MULTI;
+
+ CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
+ CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
+
+ return;
+}
+
+static void rl_reset(sc)
+ struct rl_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET);
+
+ for (i = 0; i < RL_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET))
+ break;
+ }
+ if (i == RL_TIMEOUT)
+ printf("rl%d: reset never completed!\n", sc->rl_unit);
+
+ return;
+}
+
+/*
+ * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int rl_probe(dev)
+ device_t dev;
+{
+ struct rl_type *t;
+
+ t = rl_devs;
+
+ while(t->rl_name != NULL) {
+ if ((pci_get_vendor(dev) == t->rl_vid) &&
+ (pci_get_device(dev) == t->rl_did)) {
+ device_set_desc(dev, t->rl_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int rl_attach(dev)
+ device_t dev;
+{
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct rl_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t rl_did = 0;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct rl_softc));
+
+ mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ RL_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, RL_PCI_LOIO, 4);
+ membase = pci_read_config(dev, RL_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, RL_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("rl%d: chip is is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, RL_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, RL_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, RL_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef RL_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("rl%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("rl%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = RL_RID;
+ sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->rl_res == NULL) {
+ printf ("rl%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Detect the Realtek 8139B. For some reason, this chip is very
+ * unstable when left to autoselect the media
+ * The best workaround is to set the device to the required
+ * media type or to set it to the 10 Meg speed.
+ */
+
+ if ((rman_get_end(sc->rl_res)-rman_get_start(sc->rl_res))==0xff) {
+ printf("rl%d: Realtek 8139B detected. Warning, this may be unstable in autoselect mode\n", unit);
+ }
+
+ sc->rl_btag = rman_get_bustag(sc->rl_res);
+ sc->rl_bhandle = rman_get_bushandle(sc->rl_res);
+
+ rid = 0;
+ sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->rl_irq == NULL) {
+ printf("rl%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET,
+ rl_intr, sc, &sc->rl_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+ printf("rl%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ callout_handle_init(&sc->rl_stat_ch);
+
+ /* Reset the adapter. */
+ rl_reset(sc);
+ sc->rl_eecmd_read = RL_EECMD_READ_6BIT;
+ rl_read_eeprom(sc, (caddr_t)&rl_did, 0, 1, 0);
+ if (rl_did != 0x8129)
+ sc->rl_eecmd_read = RL_EECMD_READ_8BIT;
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0);
+
+ /*
+ * A RealTek chip was detected. Inform the world.
+ */
+ printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->rl_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ /*
+ * Now read the exact device type from the EEPROM to find
+ * out if it's an 8129 or 8139.
+ */
+ rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0);
+
+ if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 ||
+ rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139 ||
+ rl_did == RT_DEVICEID_8138 || rl_did == DLINK_DEVICEID_530TXPLUS ||
+ rl_did == DLINK_DEVICEID_690TXD)
+ sc->rl_type = RL_8139;
+ else if (rl_did == RT_DEVICEID_8129)
+ sc->rl_type = RL_8129;
+ else {
+ printf("rl%d: unknown device ID: %x\n", unit, rl_did);
+ bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Allocate the parent bus DMA tag appropriate for PCI.
+ */
+#define RL_NSEG_NEW 32
+ error = bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, RL_NSEG_NEW, /* maxsize, nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ &sc->rl_parent_tag);
+
+ /*
+ * Now allocate a tag for the DMA descriptor lists.
+ * All of our lists are allocated as a contiguous block
+ * of memory.
+ */
+ error = bus_dma_tag_create(sc->rl_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ RL_RXBUFLEN + 1518, 1, /* maxsize,nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ 0, /* flags */
+ &sc->rl_tag);
+
+ /*
+ * Now allocate a chunk of DMA-able memory based on the
+ * tag we just created.
+ */
+ error = bus_dmamem_alloc(sc->rl_tag,
+ (void **)&sc->rl_cdata.rl_rx_buf, BUS_DMA_NOWAIT,
+ &sc->rl_cdata.rl_rx_dmamap);
+
+ if (sc->rl_cdata.rl_rx_buf == NULL) {
+ printf("rl%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+ bus_dma_tag_destroy(sc->rl_tag);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Leave a few bytes before the start of the RX ring buffer. */
+ sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf;
+ sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t);
+
+ /* Do MII setup */
+ if (mii_phy_probe(dev, &sc->rl_miibus,
+ rl_ifmedia_upd, rl_ifmedia_sts)) {
+ printf("rl%d: MII without any phy!\n", sc->rl_unit);
+ bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+ bus_dmamem_free(sc->rl_tag,
+ sc->rl_cdata.rl_rx_buf, sc->rl_cdata.rl_rx_dmamap);
+ bus_dma_tag_destroy(sc->rl_tag);
+ error = ENXIO;
+ goto fail;
+ }
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "rl";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = rl_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = rl_start;
+ ifp->if_watchdog = rl_watchdog;
+ ifp->if_init = rl_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ RL_UNLOCK(sc);
+ return(0);
+
+fail:
+ RL_UNLOCK(sc);
+ mtx_destroy(&sc->rl_mtx);
+ return(error);
+}
+
+static int rl_detach(dev)
+ device_t dev;
+{
+ struct rl_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ RL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+ rl_stop(sc);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->rl_miibus);
+
+ bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+ bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
+
+ bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap);
+ bus_dmamem_free(sc->rl_tag, sc->rl_cdata.rl_rx_buf,
+ sc->rl_cdata.rl_rx_dmamap);
+ bus_dma_tag_destroy(sc->rl_tag);
+ bus_dma_tag_destroy(sc->rl_parent_tag);
+
+ RL_UNLOCK(sc);
+ mtx_destroy(&sc->rl_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int rl_list_tx_init(sc)
+ struct rl_softc *sc;
+{
+ struct rl_chain_data *cd;
+ int i;
+
+ cd = &sc->rl_cdata;
+ for (i = 0; i < RL_TX_LIST_CNT; i++) {
+ cd->rl_tx_chain[i] = NULL;
+ CSR_WRITE_4(sc,
+ RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000);
+ }
+
+ sc->rl_cdata.cur_tx = 0;
+ sc->rl_cdata.last_tx = 0;
+
+ return(0);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ *
+ * You know there's something wrong with a PCI bus-master chip design
+ * when you have to use m_devget().
+ *
+ * The receive operation is badly documented in the datasheet, so I'll
+ * attempt to document it here. The driver provides a buffer area and
+ * places its base address in the RX buffer start address register.
+ * The chip then begins copying frames into the RX buffer. Each frame
+ * is preceded by a 32-bit RX status word which specifies the length
+ * of the frame and certain other status bits. Each frame (starting with
+ * the status word) is also 32-bit aligned. The frame length is in the
+ * first 16 bits of the status word; the lower 15 bits correspond with
+ * the 'rx status register' mentioned in the datasheet.
+ *
+ * Note: to make the Alpha happy, the frame payload needs to be aligned
+ * on a 32-bit boundary. To achieve this, we pass RL_ETHER_ALIGN (2 bytes)
+ * as the offset argument to m_devget().
+ */
+static void rl_rxeof(sc)
+ struct rl_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ int total_len = 0;
+ u_int32_t rxstat;
+ caddr_t rxbufpos;
+ int wrap = 0;
+ u_int16_t cur_rx;
+ u_int16_t limit;
+ u_int16_t rx_bytes = 0, max_bytes;
+
+ ifp = &sc->arpcom.ac_if;
+
+ bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+
+ cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN;
+
+ /* Do not try to read past this point. */
+ limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN;
+
+ if (limit < cur_rx)
+ max_bytes = (RL_RXBUFLEN - cur_rx) + limit;
+ else
+ max_bytes = limit - cur_rx;
+
+ while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) {
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif /* DEVICE_POLLING */
+ rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx;
+ rxstat = *(u_int32_t *)rxbufpos;
+
+ /*
+ * Here's a totally undocumented fact for you. When the
+ * RealTek chip is in the process of copying a packet into
+ * RAM for you, the length will be 0xfff0. If you spot a
+ * packet header with this value, you need to stop. The
+ * datasheet makes absolutely no mention of this and
+ * RealTek should be shot for this.
+ */
+ if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED)
+ break;
+
+ if (!(rxstat & RL_RXSTAT_RXOK)) {
+ ifp->if_ierrors++;
+ rl_init(sc);
+ return;
+ }
+
+ /* No errors; receive the packet. */
+ total_len = rxstat >> 16;
+ rx_bytes += total_len + 4;
+
+ /*
+ * XXX The RealTek chip includes the CRC with every
+ * received frame, and there's no way to turn this
+ * behavior off (at least, I can't find anything in
+ * the manual that explains how to do it) so we have
+ * to trim off the CRC manually.
+ */
+ total_len -= ETHER_CRC_LEN;
+
+ /*
+ * Avoid trying to read more bytes than we know
+ * the chip has prepared for us.
+ */
+ if (rx_bytes > max_bytes)
+ break;
+
+ rxbufpos = sc->rl_cdata.rl_rx_buf +
+ ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN);
+
+ if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN))
+ rxbufpos = sc->rl_cdata.rl_rx_buf;
+
+ wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos;
+
+ if (total_len > wrap) {
+ m = m_devget(rxbufpos, total_len, RL_ETHER_ALIGN, ifp,
+ NULL);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ } else {
+ m_copyback(m, wrap, total_len - wrap,
+ sc->rl_cdata.rl_rx_buf);
+ }
+ cur_rx = (total_len - wrap + ETHER_CRC_LEN);
+ } else {
+ m = m_devget(rxbufpos, total_len, RL_ETHER_ALIGN, ifp,
+ NULL);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ }
+ cur_rx += total_len + 4 + ETHER_CRC_LEN;
+ }
+
+ /*
+ * Round up to 32-bit boundary.
+ */
+ cur_rx = (cur_rx + 3) & ~3;
+ CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16);
+
+ if (m == NULL)
+ continue;
+
+ eh = mtod(m, struct ether_header *);
+ ifp->if_ipackets++;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+static void rl_txeof(sc)
+ struct rl_softc *sc;
+{
+ struct ifnet *ifp;
+ u_int32_t txstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been uploaded.
+ */
+ do {
+ txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc));
+ if (!(txstat & (RL_TXSTAT_TX_OK|
+ RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT)))
+ break;
+
+ ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24;
+
+ if (RL_LAST_TXMBUF(sc) != NULL) {
+ bus_dmamap_unload(sc->rl_tag, RL_LAST_DMAMAP(sc));
+ bus_dmamap_destroy(sc->rl_tag, RL_LAST_DMAMAP(sc));
+ m_freem(RL_LAST_TXMBUF(sc));
+ RL_LAST_TXMBUF(sc) = NULL;
+ }
+ if (txstat & RL_TXSTAT_TX_OK)
+ ifp->if_opackets++;
+ else {
+ int oldthresh;
+ ifp->if_oerrors++;
+ if ((txstat & RL_TXSTAT_TXABRT) ||
+ (txstat & RL_TXSTAT_OUTOFWIN))
+ CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
+ oldthresh = sc->rl_txthresh;
+ /* error recovery */
+ rl_reset(sc);
+ rl_init(sc);
+ /*
+ * If there was a transmit underrun,
+ * bump the TX threshold.
+ */
+ if (txstat & RL_TXSTAT_TX_UNDERRUN)
+ sc->rl_txthresh = oldthresh + 32;
+ return;
+ }
+ RL_INC(sc->rl_cdata.last_tx);
+ ifp->if_flags &= ~IFF_OACTIVE;
+ } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx);
+
+ return;
+}
+
+static void rl_tick(xsc)
+ void *xsc;
+{
+ struct rl_softc *sc;
+ struct mii_data *mii;
+
+ sc = xsc;
+ RL_LOCK(sc);
+ mii = device_get_softc(sc->rl_miibus);
+
+ mii_tick(mii);
+
+ sc->rl_stat_ch = timeout(rl_tick, sc, hz);
+ RL_UNLOCK(sc);
+
+ return;
+}
+
+#ifdef DEVICE_POLLING
+static void
+rl_poll (struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct rl_softc *sc = ifp->if_softc;
+
+ RL_LOCK(sc);
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ CSR_WRITE_2(sc, RL_IMR, RL_INTRS);
+ goto done;
+ }
+
+ sc->rxcycles = count;
+ rl_rxeof(sc);
+ rl_txeof(sc);
+ if (ifp->if_snd.ifq_head != NULL)
+ rl_start(ifp);
+
+ if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
+ u_int16_t status;
+
+ status = CSR_READ_2(sc, RL_ISR);
+ if (status)
+ CSR_WRITE_2(sc, RL_ISR, status);
+
+ /*
+ * XXX check behaviour on receiver stalls.
+ */
+
+ if (status & RL_ISR_SYSTEM_ERR) {
+ rl_reset(sc);
+ rl_init(sc);
+ }
+ }
+done:
+ RL_UNLOCK(sc);
+}
+#endif /* DEVICE_POLLING */
+
+static void rl_intr(arg)
+ void *arg;
+{
+ struct rl_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t status;
+
+ sc = arg;
+
+ if (sc->suspended) {
+ return;
+ }
+
+ RL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING)
+ goto done;
+ if (ether_poll_register(rl_poll, ifp)) { /* ok, disable interrupts */
+ CSR_WRITE_2(sc, RL_IMR, 0x0000);
+ rl_poll(ifp, 0, 1);
+ goto done;
+ }
+#endif /* DEVICE_POLLING */
+
+ for (;;) {
+
+ status = CSR_READ_2(sc, RL_ISR);
+ if (status)
+ CSR_WRITE_2(sc, RL_ISR, status);
+
+ if ((status & RL_INTRS) == 0)
+ break;
+
+ if (status & RL_ISR_RX_OK)
+ rl_rxeof(sc);
+
+ if (status & RL_ISR_RX_ERR)
+ rl_rxeof(sc);
+
+ if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR))
+ rl_txeof(sc);
+
+ if (status & RL_ISR_SYSTEM_ERR) {
+ rl_reset(sc);
+ rl_init(sc);
+ }
+
+ }
+
+ if (ifp->if_snd.ifq_head != NULL)
+ rl_start(ifp);
+
+#ifdef DEVICE_POLLING
+done:
+#endif
+ RL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int rl_encap(sc, m_head)
+ struct rl_softc *sc;
+ struct mbuf *m_head;
+{
+ struct mbuf *m_new = NULL;
+
+ /*
+ * The RealTek is brain damaged and wants longword-aligned
+ * TX buffers, plus we can only have one fragment buffer
+ * per packet. We have to copy pretty much all the time.
+ */
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(1);
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+
+ /* Pad frames to at least 60 bytes. */
+ if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) {
+ /*
+ * Make security concious people happy: zero out the
+ * bytes in the pad area, since we don't know what
+ * this mbuf cluster buffer's previous user might
+ * have left in it.
+ */
+ bzero(mtod(m_head, char *) + m_head->m_pkthdr.len,
+ RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
+ m_head->m_pkthdr.len +=
+ (RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
+ m_head->m_len = m_head->m_pkthdr.len;
+ }
+
+ RL_CUR_TXMBUF(sc) = m_head;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine.
+ */
+
+static void rl_start(ifp)
+ struct ifnet *ifp;
+{
+ struct rl_softc *sc;
+ struct mbuf *m_head = NULL;
+
+ sc = ifp->if_softc;
+ RL_LOCK(sc);
+
+ while(RL_CUR_TXMBUF(sc) == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (rl_encap(sc, m_head)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, RL_CUR_TXMBUF(sc));
+
+ /*
+ * Transmit the frame.
+ */
+ bus_dmamap_create(sc->rl_tag, 0, &RL_CUR_DMAMAP(sc));
+ bus_dmamap_load(sc->rl_tag, RL_CUR_DMAMAP(sc),
+ mtod(RL_CUR_TXMBUF(sc), void *),
+ RL_CUR_TXMBUF(sc)->m_pkthdr.len, rl_dma_map_txbuf, sc, 0);
+ bus_dmamap_sync(sc->rl_tag, RL_CUR_DMAMAP(sc),
+ BUS_DMASYNC_PREREAD);
+ CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc),
+ RL_TXTHRESH(sc->rl_txthresh) |
+ RL_CUR_TXMBUF(sc)->m_pkthdr.len);
+
+ RL_INC(sc->rl_cdata.cur_tx);
+ }
+
+ /*
+ * We broke out of the loop because all our TX slots are
+ * full. Mark the NIC as busy until it drains some of the
+ * packets from the queue.
+ */
+ if (RL_CUR_TXMBUF(sc) != NULL)
+ ifp->if_flags |= IFF_OACTIVE;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ RL_UNLOCK(sc);
+
+ return;
+}
+
+static void rl_init(xsc)
+ void *xsc;
+{
+ struct rl_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+ int i;
+ u_int32_t rxcfg = 0;
+
+ RL_LOCK(sc);
+ mii = device_get_softc(sc->rl_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ rl_stop(sc);
+
+ /* Init our MAC address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Init the RX buffer pointer register. */
+ bus_dmamap_load(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
+ sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN, rl_dma_map_rxbuf, sc, 0);
+ bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Init TX descriptors. */
+ rl_list_tx_init(sc);
+
+ /*
+ * Enable transmit and receive.
+ */
+ CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
+
+ /*
+ * Set the initial TX and RX configuration.
+ */
+ CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
+ CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG);
+
+ /* Set the individual bit to receive frames for this host only. */
+ rxcfg = CSR_READ_4(sc, RL_RXCFG);
+ rxcfg |= RL_RXCFG_RX_INDIV;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ rxcfg |= RL_RXCFG_RX_ALLPHYS;
+ CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+ } else {
+ rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
+ CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+ }
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ rxcfg |= RL_RXCFG_RX_BROAD;
+ CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+ } else {
+ rxcfg &= ~RL_RXCFG_RX_BROAD;
+ CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+ }
+
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ rl_setmulti(sc);
+
+#ifdef DEVICE_POLLING
+ /*
+ * Disable interrupts if we are polling.
+ */
+ if (ifp->if_ipending & IFF_POLLING)
+ CSR_WRITE_2(sc, RL_IMR, 0);
+ else /* otherwise ... */
+#endif /* DEVICE_POLLING */
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_2(sc, RL_IMR, RL_INTRS);
+
+ /* Set initial TX threshold */
+ sc->rl_txthresh = RL_TX_THRESH_INIT;
+
+ /* Start RX/TX process. */
+ CSR_WRITE_4(sc, RL_MISSEDPKT, 0);
+
+ /* Enable receiver and transmitter. */
+ CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
+
+ mii_mediachg(mii);
+
+ CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->rl_stat_ch = timeout(rl_tick, sc, hz);
+ RL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int rl_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct rl_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->rl_miibus);
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void rl_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct rl_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->rl_miibus);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int rl_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct rl_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ RL_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ rl_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ rl_stop(sc);
+ }
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ rl_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->rl_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ RL_UNLOCK(sc);
+
+ return(error);
+}
+
+static void rl_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct rl_softc *sc;
+
+ sc = ifp->if_softc;
+ RL_LOCK(sc);
+ printf("rl%d: watchdog timeout\n", sc->rl_unit);
+ ifp->if_oerrors++;
+
+ rl_txeof(sc);
+ rl_rxeof(sc);
+ rl_init(sc);
+ RL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void rl_stop(sc)
+ struct rl_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ RL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(rl_tick, sc, sc->rl_stat_ch);
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif /* DEVICE_POLLING */
+
+ CSR_WRITE_1(sc, RL_COMMAND, 0x00);
+ CSR_WRITE_2(sc, RL_IMR, 0x0000);
+ bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap);
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < RL_TX_LIST_CNT; i++) {
+ if (sc->rl_cdata.rl_tx_chain[i] != NULL) {
+ bus_dmamap_unload(sc->rl_tag,
+ sc->rl_cdata.rl_tx_dmamap[i]);
+ bus_dmamap_destroy(sc->rl_tag,
+ sc->rl_cdata.rl_tx_dmamap[i]);
+ m_freem(sc->rl_cdata.rl_tx_chain[i]);
+ sc->rl_cdata.rl_tx_chain[i] = NULL;
+ CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000);
+ }
+ }
+
+ RL_UNLOCK(sc);
+ return;
+}
+
+/*
+ * Device suspend routine. Stop the interface and save some PCI
+ * settings in case the BIOS doesn't restore them properly on
+ * resume.
+ */
+static int rl_suspend(dev)
+ device_t dev;
+{
+ register int i;
+ struct rl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ rl_stop(sc);
+
+ for (i = 0; i < 5; i++)
+ sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4);
+ sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
+ sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
+ sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
+
+ sc->suspended = 1;
+
+ return (0);
+}
+
+/*
+ * Device resume routine. Restore some PCI settings in case the BIOS
+ * doesn't, re-enable busmastering, and restart the interface if
+ * appropriate.
+ */
+static int rl_resume(dev)
+ device_t dev;
+{
+ register int i;
+ struct rl_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ /* better way to do this? */
+ for (i = 0; i < 5; i++)
+ pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4);
+ pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
+ pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
+ pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
+ pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
+
+ /* reenable busmastering */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, RL_RES);
+
+ /* reinitialize interface if necessary */
+ if (ifp->if_flags & IFF_UP)
+ rl_init(sc);
+
+ sc->suspended = 0;
+
+ return (0);
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void rl_shutdown(dev)
+ device_t dev;
+{
+ struct rl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ rl_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h
new file mode 100644
index 0000000..19b1852
--- /dev/null
+++ b/sys/pci/if_rlreg.h
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * RealTek 8129/8139 register offsets
+ */
+#define RL_IDR0 0x0000 /* ID register 0 (station addr) */
+#define RL_IDR1 0x0001 /* Must use 32-bit accesses (?) */
+#define RL_IDR2 0x0002
+#define RL_IDR3 0x0003
+#define RL_IDR4 0x0004
+#define RL_IDR5 0x0005
+ /* 0006-0007 reserved */
+#define RL_MAR0 0x0008 /* Multicast hash table */
+#define RL_MAR1 0x0009
+#define RL_MAR2 0x000A
+#define RL_MAR3 0x000B
+#define RL_MAR4 0x000C
+#define RL_MAR5 0x000D
+#define RL_MAR6 0x000E
+#define RL_MAR7 0x000F
+
+#define RL_TXSTAT0 0x0010 /* status of TX descriptor 0 */
+#define RL_TXSTAT1 0x0014 /* status of TX descriptor 1 */
+#define RL_TXSTAT2 0x0018 /* status of TX descriptor 2 */
+#define RL_TXSTAT3 0x001C /* status of TX descriptor 3 */
+
+#define RL_TXADDR0 0x0020 /* address of TX descriptor 0 */
+#define RL_TXADDR1 0x0024 /* address of TX descriptor 1 */
+#define RL_TXADDR2 0x0028 /* address of TX descriptor 2 */
+#define RL_TXADDR3 0x002C /* address of TX descriptor 3 */
+
+#define RL_RXADDR 0x0030 /* RX ring start address */
+#define RL_RX_EARLY_BYTES 0x0034 /* RX early byte count */
+#define RL_RX_EARLY_STAT 0x0036 /* RX early status */
+#define RL_COMMAND 0x0037 /* command register */
+#define RL_CURRXADDR 0x0038 /* current address of packet read */
+#define RL_CURRXBUF 0x003A /* current RX buffer address */
+#define RL_IMR 0x003C /* interrupt mask register */
+#define RL_ISR 0x003E /* interrupt status register */
+#define RL_TXCFG 0x0040 /* transmit config */
+#define RL_RXCFG 0x0044 /* receive config */
+#define RL_TIMERCNT 0x0048 /* timer count register */
+#define RL_MISSEDPKT 0x004C /* missed packet counter */
+#define RL_EECMD 0x0050 /* EEPROM command register */
+#define RL_CFG0 0x0051 /* config register #0 */
+#define RL_CFG1 0x0052 /* config register #1 */
+ /* 0053-0057 reserved */
+#define RL_MEDIASTAT 0x0058 /* media status register (8139) */
+ /* 0059-005A reserved */
+#define RL_MII 0x005A /* 8129 chip only */
+#define RL_HALTCLK 0x005B
+#define RL_MULTIINTR 0x005C /* multiple interrupt */
+#define RL_PCIREV 0x005E /* PCI revision value */
+ /* 005F reserved */
+#define RL_TXSTAT_ALL 0x0060 /* TX status of all descriptors */
+
+/* Direct PHY access registers only available on 8139 */
+#define RL_BMCR 0x0062 /* PHY basic mode control */
+#define RL_BMSR 0x0064 /* PHY basic mode status */
+#define RL_ANAR 0x0066 /* PHY autoneg advert */
+#define RL_LPAR 0x0068 /* PHY link partner ability */
+#define RL_ANER 0x006A /* PHY autoneg expansion */
+
+#define RL_DISCCNT 0x006C /* disconnect counter */
+#define RL_FALSECAR 0x006E /* false carrier counter */
+#define RL_NWAYTST 0x0070 /* NWAY test register */
+#define RL_RX_ER 0x0072 /* RX_ER counter */
+#define RL_CSCFG 0x0074 /* CS configuration register */
+
+
+/*
+ * TX config register bits
+ */
+#define RL_TXCFG_CLRABRT 0x00000001 /* retransmit aborted pkt */
+#define RL_TXCFG_MAXDMA 0x00000700 /* max DMA burst size */
+#define RL_TXCFG_CRCAPPEND 0x00010000 /* CRC append (0 = yes) */
+#define RL_TXCFG_LOOPBKTST 0x00060000 /* loopback test */
+#define RL_TXCFG_IFG 0x03000000 /* interframe gap */
+
+#define RL_TXDMA_16BYTES 0x00000000
+#define RL_TXDMA_32BYTES 0x00000100
+#define RL_TXDMA_64BYTES 0x00000200
+#define RL_TXDMA_128BYTES 0x00000300
+#define RL_TXDMA_256BYTES 0x00000400
+#define RL_TXDMA_512BYTES 0x00000500
+#define RL_TXDMA_1024BYTES 0x00000600
+#define RL_TXDMA_2048BYTES 0x00000700
+
+/*
+ * Transmit descriptor status register bits.
+ */
+#define RL_TXSTAT_LENMASK 0x00001FFF
+#define RL_TXSTAT_OWN 0x00002000
+#define RL_TXSTAT_TX_UNDERRUN 0x00004000
+#define RL_TXSTAT_TX_OK 0x00008000
+#define RL_TXSTAT_EARLY_THRESH 0x003F0000
+#define RL_TXSTAT_COLLCNT 0x0F000000
+#define RL_TXSTAT_CARR_HBEAT 0x10000000
+#define RL_TXSTAT_OUTOFWIN 0x20000000
+#define RL_TXSTAT_TXABRT 0x40000000
+#define RL_TXSTAT_CARRLOSS 0x80000000
+
+/*
+ * Interrupt status register bits.
+ */
+#define RL_ISR_RX_OK 0x0001
+#define RL_ISR_RX_ERR 0x0002
+#define RL_ISR_TX_OK 0x0004
+#define RL_ISR_TX_ERR 0x0008
+#define RL_ISR_RX_OVERRUN 0x0010
+#define RL_ISR_PKT_UNDERRUN 0x0020
+#define RL_ISR_FIFO_OFLOW 0x0040 /* 8139 only */
+#define RL_ISR_PCS_TIMEOUT 0x4000 /* 8129 only */
+#define RL_ISR_SYSTEM_ERR 0x8000
+
+#define RL_INTRS \
+ (RL_ISR_TX_OK|RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR| \
+ RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW| \
+ RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR)
+
+/*
+ * Media status register. (8139 only)
+ */
+#define RL_MEDIASTAT_RXPAUSE 0x01
+#define RL_MEDIASTAT_TXPAUSE 0x02
+#define RL_MEDIASTAT_LINK 0x04
+#define RL_MEDIASTAT_SPEED10 0x08
+#define RL_MEDIASTAT_RXFLOWCTL 0x40 /* duplex mode */
+#define RL_MEDIASTAT_TXFLOWCTL 0x80 /* duplex mode */
+
+/*
+ * Receive config register.
+ */
+#define RL_RXCFG_RX_ALLPHYS 0x00000001 /* accept all nodes */
+#define RL_RXCFG_RX_INDIV 0x00000002 /* match filter */
+#define RL_RXCFG_RX_MULTI 0x00000004 /* accept all multicast */
+#define RL_RXCFG_RX_BROAD 0x00000008 /* accept all broadcast */
+#define RL_RXCFG_RX_RUNT 0x00000010
+#define RL_RXCFG_RX_ERRPKT 0x00000020
+#define RL_RXCFG_WRAP 0x00000080
+#define RL_RXCFG_MAXDMA 0x00000700
+#define RL_RXCFG_BUFSZ 0x00001800
+#define RL_RXCFG_FIFOTHRESH 0x0000E000
+#define RL_RXCFG_EARLYTHRESH 0x07000000
+
+#define RL_RXDMA_16BYTES 0x00000000
+#define RL_RXDMA_32BYTES 0x00000100
+#define RL_RXDMA_64BYTES 0x00000200
+#define RL_RXDMA_128BYTES 0x00000300
+#define RL_RXDMA_256BYTES 0x00000400
+#define RL_RXDMA_512BYTES 0x00000500
+#define RL_RXDMA_1024BYTES 0x00000600
+#define RL_RXDMA_UNLIMITED 0x00000700
+
+#define RL_RXBUF_8 0x00000000
+#define RL_RXBUF_16 0x00000800
+#define RL_RXBUF_32 0x00001000
+#define RL_RXBUF_64 0x00001800
+
+#define RL_RXFIFO_16BYTES 0x00000000
+#define RL_RXFIFO_32BYTES 0x00002000
+#define RL_RXFIFO_64BYTES 0x00004000
+#define RL_RXFIFO_128BYTES 0x00006000
+#define RL_RXFIFO_256BYTES 0x00008000
+#define RL_RXFIFO_512BYTES 0x0000A000
+#define RL_RXFIFO_1024BYTES 0x0000C000
+#define RL_RXFIFO_NOTHRESH 0x0000E000
+
+/*
+ * Bits in RX status header (included with RX'ed packet
+ * in ring buffer).
+ */
+#define RL_RXSTAT_RXOK 0x00000001
+#define RL_RXSTAT_ALIGNERR 0x00000002
+#define RL_RXSTAT_CRCERR 0x00000004
+#define RL_RXSTAT_GIANT 0x00000008
+#define RL_RXSTAT_RUNT 0x00000010
+#define RL_RXSTAT_BADSYM 0x00000020
+#define RL_RXSTAT_BROAD 0x00002000
+#define RL_RXSTAT_INDIV 0x00004000
+#define RL_RXSTAT_MULTI 0x00008000
+#define RL_RXSTAT_LENMASK 0xFFFF0000
+
+#define RL_RXSTAT_UNFINISHED 0xFFF0 /* DMA still in progress */
+/*
+ * Command register.
+ */
+#define RL_CMD_EMPTY_RXBUF 0x0001
+#define RL_CMD_TX_ENB 0x0004
+#define RL_CMD_RX_ENB 0x0008
+#define RL_CMD_RESET 0x0010
+
+/*
+ * EEPROM control register
+ */
+#define RL_EE_DATAOUT 0x01 /* Data out */
+#define RL_EE_DATAIN 0x02 /* Data in */
+#define RL_EE_CLK 0x04 /* clock */
+#define RL_EE_SEL 0x08 /* chip select */
+#define RL_EE_MODE (0x40|0x80)
+
+#define RL_EEMODE_OFF 0x00
+#define RL_EEMODE_AUTOLOAD 0x40
+#define RL_EEMODE_PROGRAM 0x80
+#define RL_EEMODE_WRITECFG (0x80|0x40)
+
+/* 9346 EEPROM commands */
+#define RL_EECMD_WRITE 0x140
+#define RL_EECMD_READ_6BIT 0x180
+#define RL_EECMD_READ_8BIT 0x600
+#define RL_EECMD_ERASE 0x1c0
+
+#define RL_EE_ID 0x00
+#define RL_EE_PCI_VID 0x01
+#define RL_EE_PCI_DID 0x02
+/* Location of station address inside EEPROM */
+#define RL_EE_EADDR 0x07
+
+/*
+ * MII register (8129 only)
+ */
+#define RL_MII_CLK 0x01
+#define RL_MII_DATAIN 0x02
+#define RL_MII_DATAOUT 0x04
+#define RL_MII_DIR 0x80 /* 0 == input, 1 == output */
+
+/*
+ * Config 0 register
+ */
+#define RL_CFG0_ROM0 0x01
+#define RL_CFG0_ROM1 0x02
+#define RL_CFG0_ROM2 0x04
+#define RL_CFG0_PL0 0x08
+#define RL_CFG0_PL1 0x10
+#define RL_CFG0_10MBPS 0x20 /* 10 Mbps internal mode */
+#define RL_CFG0_PCS 0x40
+#define RL_CFG0_SCR 0x80
+
+/*
+ * Config 1 register
+ */
+#define RL_CFG1_PWRDWN 0x01
+#define RL_CFG1_SLEEP 0x02
+#define RL_CFG1_IOMAP 0x04
+#define RL_CFG1_MEMMAP 0x08
+#define RL_CFG1_RSVD 0x10
+#define RL_CFG1_DRVLOAD 0x20
+#define RL_CFG1_LED0 0x40
+#define RL_CFG1_FULLDUPLEX 0x40 /* 8129 only */
+#define RL_CFG1_LED1 0x80
+
+/*
+ * The RealTek doesn't use a fragment-based descriptor mechanism.
+ * Instead, there are only four register sets, each or which represents
+ * one 'descriptor.' Basically, each TX descriptor is just a contiguous
+ * packet buffer (32-bit aligned!) and we place the buffer addresses in
+ * the registers so the chip knows where they are.
+ *
+ * We can sort of kludge together the same kind of buffer management
+ * used in previous drivers, but we have to do buffer copies almost all
+ * the time, so it doesn't really buy us much.
+ *
+ * For reception, there's just one large buffer where the chip stores
+ * all received packets.
+ */
+
+#define RL_RX_BUF_SZ RL_RXBUF_64
+#define RL_RXBUFLEN (1 << ((RL_RX_BUF_SZ >> 11) + 13))
+#define RL_TX_LIST_CNT 4
+#define RL_MIN_FRAMELEN 60
+#define RL_TXTHRESH(x) ((x) << 11)
+#define RL_TX_THRESH_INIT 96
+#define RL_RX_FIFOTHRESH RL_RXFIFO_256BYTES
+#define RL_RX_MAXDMA RL_RXDMA_1024BYTES /*RL_RXDMA_UNLIMITED*/
+#define RL_TX_MAXDMA RL_TXDMA_2048BYTES
+
+#define RL_RXCFG_CONFIG (RL_RX_FIFOTHRESH|RL_RX_MAXDMA|RL_RX_BUF_SZ)
+#define RL_TXCFG_CONFIG (RL_TXCFG_IFG|RL_TX_MAXDMA)
+
+#define RL_ETHER_ALIGN 2
+
+struct rl_chain_data {
+ u_int16_t cur_rx;
+ caddr_t rl_rx_buf;
+ caddr_t rl_rx_buf_ptr;
+ bus_dmamap_t rl_rx_dmamap;
+
+ struct mbuf *rl_tx_chain[RL_TX_LIST_CNT];
+ bus_dmamap_t rl_tx_dmamap[RL_TX_LIST_CNT];
+ u_int8_t last_tx;
+ u_int8_t cur_tx;
+};
+
+#define RL_INC(x) (x = (x + 1) % RL_TX_LIST_CNT)
+#define RL_CUR_TXADDR(x) ((x->rl_cdata.cur_tx * 4) + RL_TXADDR0)
+#define RL_CUR_TXSTAT(x) ((x->rl_cdata.cur_tx * 4) + RL_TXSTAT0)
+#define RL_CUR_TXMBUF(x) (x->rl_cdata.rl_tx_chain[x->rl_cdata.cur_tx])
+#define RL_CUR_DMAMAP(x) (x->rl_cdata.rl_tx_dmamap[x->rl_cdata.cur_tx])
+#define RL_LAST_TXADDR(x) ((x->rl_cdata.last_tx * 4) + RL_TXADDR0)
+#define RL_LAST_TXSTAT(x) ((x->rl_cdata.last_tx * 4) + RL_TXSTAT0)
+#define RL_LAST_TXMBUF(x) (x->rl_cdata.rl_tx_chain[x->rl_cdata.last_tx])
+#define RL_LAST_DMAMAP(x) (x->rl_cdata.rl_tx_dmamap[x->rl_cdata.last_tx])
+
+struct rl_type {
+ u_int16_t rl_vid;
+ u_int16_t rl_did;
+ char *rl_name;
+};
+
+struct rl_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define RL_MII_STARTDELIM 0x01
+#define RL_MII_READOP 0x02
+#define RL_MII_WRITEOP 0x01
+#define RL_MII_TURNAROUND 0x02
+
+#define RL_8129 1
+#define RL_8139 2
+
+struct rl_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t rl_bhandle; /* bus space handle */
+ bus_space_tag_t rl_btag; /* bus space tag */
+ struct resource *rl_res;
+ struct resource *rl_irq;
+ void *rl_intrhand;
+ device_t rl_miibus;
+ bus_dma_tag_t rl_parent_tag;
+ bus_dma_tag_t rl_tag;
+ u_int8_t rl_unit; /* interface number */
+ u_int8_t rl_type;
+ int rl_eecmd_read;
+ u_int8_t rl_stats_no_timeout;
+ int rl_txthresh;
+ struct rl_chain_data rl_cdata;
+ struct callout_handle rl_stat_ch;
+ struct mtx rl_mtx;
+ int suspended; /* 0 = normal 1 = suspended */
+#ifdef DEVICE_POLLING
+ int rxcycles;
+#endif
+
+ u_int32_t saved_maps[5]; /* pci data */
+ u_int32_t saved_biosaddr;
+ u_int8_t saved_intline;
+ u_int8_t saved_cachelnsz;
+ u_int8_t saved_lattimer;
+};
+
+#define RL_LOCK(_sc) mtx_lock(&(_sc)->rl_mtx)
+#define RL_UNLOCK(_sc) mtx_unlock(&(_sc)->rl_mtx)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->rl_btag, sc->rl_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->rl_btag, sc->rl_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->rl_btag, sc->rl_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->rl_btag, sc->rl_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->rl_btag, sc->rl_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->rl_btag, sc->rl_bhandle, reg)
+
+#define RL_TIMEOUT 1000
+
+/*
+ * General constants that are fun to know.
+ *
+ * RealTek PCI vendor ID
+ */
+#define RT_VENDORID 0x10EC
+
+/*
+ * RealTek chip device IDs.
+ */
+#define RT_DEVICEID_8129 0x8129
+#define RT_DEVICEID_8138 0x8138
+#define RT_DEVICEID_8139 0x8139
+
+/*
+ * Accton PCI vendor ID
+ */
+#define ACCTON_VENDORID 0x1113
+
+/*
+ * Accton MPX 5030/5038 device ID.
+ */
+#define ACCTON_DEVICEID_5030 0x1211
+
+/*
+ * Nortel PCI vendor ID
+ */
+#define NORTEL_VENDORID 0x126C
+
+/*
+ * Delta Electronics Vendor ID.
+ */
+#define DELTA_VENDORID 0x1500
+
+/*
+ * Delta device IDs.
+ */
+#define DELTA_DEVICEID_8139 0x1360
+
+/*
+ * Addtron vendor ID.
+ */
+#define ADDTRON_VENDORID 0x4033
+
+/*
+ * Addtron device IDs.
+ */
+#define ADDTRON_DEVICEID_8139 0x1360
+
+/*
+ * D-Link vendor ID.
+ */
+#define DLINK_VENDORID 0x1186
+
+/*
+ * D-Link DFE-530TX+ device ID
+ */
+#define DLINK_DEVICEID_530TXPLUS 0x1300
+
+/*
+ * D-Link DFE-690TXD device ID
+ */
+#define DLINK_DEVICEID_690TXD 0x1340
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define RL_PCI_VENDOR_ID 0x00
+#define RL_PCI_DEVICE_ID 0x02
+#define RL_PCI_COMMAND 0x04
+#define RL_PCI_STATUS 0x06
+#define RL_PCI_CLASSCODE 0x09
+#define RL_PCI_LATENCY_TIMER 0x0D
+#define RL_PCI_HEADER_TYPE 0x0E
+#define RL_PCI_LOIO 0x10
+#define RL_PCI_LOMEM 0x14
+#define RL_PCI_BIOSROM 0x30
+#define RL_PCI_INTLINE 0x3C
+#define RL_PCI_INTPIN 0x3D
+#define RL_PCI_MINGNT 0x3E
+#define RL_PCI_MINLAT 0x0F
+#define RL_PCI_RESETOPT 0x48
+#define RL_PCI_EEPROM_DATA 0x4C
+
+#define RL_PCI_CAPID 0x50 /* 8 bits */
+#define RL_PCI_NEXTPTR 0x51 /* 8 bits */
+#define RL_PCI_PWRMGMTCAP 0x52 /* 16 bits */
+#define RL_PCI_PWRMGMTCTRL 0x54 /* 16 bits */
+
+#define RL_PSTATE_MASK 0x0003
+#define RL_PSTATE_D0 0x0000
+#define RL_PSTATE_D1 0x0002
+#define RL_PSTATE_D2 0x0002
+#define RL_PSTATE_D3 0x0003
+#define RL_PME_EN 0x0010
+#define RL_PME_STATUS 0x8000
diff --git a/sys/pci/if_sf.c b/sys/pci/if_sf.c
new file mode 100644
index 0000000..6322a3b
--- /dev/null
+++ b/sys/pci/if_sf.c
@@ -0,0 +1,1537 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD.
+ * Programming manual is available from:
+ * ftp.adaptec.com:/pub/BBS/userguides/aic6915_pg.pdf.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Department of Electical Engineering
+ * Columbia University, New York City
+ */
+
+/*
+ * The Adaptec AIC-6915 "Starfire" is a 64-bit 10/100 PCI ethernet
+ * controller designed with flexibility and reducing CPU load in mind.
+ * The Starfire offers high and low priority buffer queues, a
+ * producer/consumer index mechanism and several different buffer
+ * queue and completion queue descriptor types. Any one of a number
+ * of different driver designs can be used, depending on system and
+ * OS requirements. This driver makes use of type0 transmit frame
+ * descriptors (since BSD fragments packets across an mbuf chain)
+ * and two RX buffer queues prioritized on size (one queue for small
+ * frames that will fit into a single mbuf, another with full size
+ * mbuf clusters for everything else). The producer/consumer indexes
+ * and completion queues are also used.
+ *
+ * One downside to the Starfire has to do with alignment: buffer
+ * queues must be aligned on 256-byte boundaries, and receive buffers
+ * must be aligned on longword boundaries. The receive buffer alignment
+ * causes problems on the Alpha platform, where the packet payload
+ * should be longword aligned. There is no simple way around this.
+ *
+ * For receive filtering, the Starfire offers 16 perfect filter slots
+ * and a 512-bit hash table.
+ *
+ * The Starfire has no internal transceiver, relying instead on an
+ * external MII-based transceiver. Accessing registers on external
+ * PHYs is done through a special register map rather than with the
+ * usual bitbang MDIO method.
+ *
+ * Acesssing the registers on the Starfire is a little tricky. The
+ * Starfire has a 512K internal register space. When programmed for
+ * PCI memory mapped mode, the entire register space can be accessed
+ * directly. However in I/O space mode, only 256 bytes are directly
+ * mapped into PCI I/O space. The other registers can be accessed
+ * indirectly using the SF_INDIRECTIO_ADDR and SF_INDIRECTIO_DATA
+ * registers inside the 256-byte I/O window.
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define SF_USEIOSPACE
+
+#include <pci/if_sfreg.h>
+
+MODULE_DEPEND(sf, miibus, 1, 1, 1);
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static struct sf_type sf_devs[] = {
+ { AD_VENDORID, AD_DEVICEID_STARFIRE,
+ "Adaptec AIC-6915 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int sf_probe (device_t);
+static int sf_attach (device_t);
+static int sf_detach (device_t);
+static void sf_intr (void *);
+static void sf_stats_update (void *);
+static void sf_rxeof (struct sf_softc *);
+static void sf_txeof (struct sf_softc *);
+static int sf_encap (struct sf_softc *,
+ struct sf_tx_bufdesc_type0 *,
+ struct mbuf *);
+static void sf_start (struct ifnet *);
+static int sf_ioctl (struct ifnet *, u_long, caddr_t);
+static void sf_init (void *);
+static void sf_stop (struct sf_softc *);
+static void sf_watchdog (struct ifnet *);
+static void sf_shutdown (device_t);
+static int sf_ifmedia_upd (struct ifnet *);
+static void sf_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+static void sf_reset (struct sf_softc *);
+static int sf_init_rx_ring (struct sf_softc *);
+static void sf_init_tx_ring (struct sf_softc *);
+static int sf_newbuf (struct sf_softc *,
+ struct sf_rx_bufdesc_type0 *,
+ struct mbuf *);
+static void sf_setmulti (struct sf_softc *);
+static int sf_setperf (struct sf_softc *, int, caddr_t);
+static int sf_sethash (struct sf_softc *, caddr_t, int);
+#ifdef notdef
+static int sf_setvlan (struct sf_softc *, int, u_int32_t);
+#endif
+
+static u_int8_t sf_read_eeprom (struct sf_softc *, int);
+static u_int32_t sf_calchash (caddr_t);
+
+static int sf_miibus_readreg (device_t, int, int);
+static int sf_miibus_writereg (device_t, int, int, int);
+static void sf_miibus_statchg (device_t);
+
+static u_int32_t csr_read_4 (struct sf_softc *, int);
+static void csr_write_4 (struct sf_softc *, int, u_int32_t);
+static void sf_txthresh_adjust (struct sf_softc *);
+
+#ifdef SF_USEIOSPACE
+#define SF_RES SYS_RES_IOPORT
+#define SF_RID SF_PCI_LOIO
+#else
+#define SF_RES SYS_RES_MEMORY
+#define SF_RID SF_PCI_LOMEM
+#endif
+
+static device_method_t sf_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, sf_probe),
+ DEVMETHOD(device_attach, sf_attach),
+ DEVMETHOD(device_detach, sf_detach),
+ DEVMETHOD(device_shutdown, sf_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, sf_miibus_readreg),
+ DEVMETHOD(miibus_writereg, sf_miibus_writereg),
+ DEVMETHOD(miibus_statchg, sf_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t sf_driver = {
+ "sf",
+ sf_methods,
+ sizeof(struct sf_softc),
+};
+
+static devclass_t sf_devclass;
+
+DRIVER_MODULE(if_sf, pci, sf_driver, sf_devclass, 0, 0);
+DRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
+
+#define SF_SETBIT(sc, reg, x) \
+ csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
+
+#define SF_CLRBIT(sc, reg, x) \
+ csr_write_4(sc, reg, csr_read_4(sc, reg) & ~x)
+
+static u_int32_t csr_read_4(sc, reg)
+ struct sf_softc *sc;
+ int reg;
+{
+ u_int32_t val;
+
+#ifdef SF_USEIOSPACE
+ CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
+ val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
+#else
+ val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
+#endif
+
+ return(val);
+}
+
+static u_int8_t sf_read_eeprom(sc, reg)
+ struct sf_softc *sc;
+ int reg;
+{
+ u_int8_t val;
+
+ val = (csr_read_4(sc, SF_EEADDR_BASE +
+ (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
+
+ return(val);
+}
+
+static void csr_write_4(sc, reg, val)
+ struct sf_softc *sc;
+ int reg;
+ u_int32_t val;
+{
+#ifdef SF_USEIOSPACE
+ CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
+ CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
+#else
+ CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
+#endif
+ return;
+}
+
+static u_int32_t sf_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return(crc >> 23 & 0x1FF);
+}
+
+/*
+ * Copy the address 'mac' into the perfect RX filter entry at
+ * offset 'idx.' The perfect filter only has 16 entries so do
+ * some sanity tests.
+ */
+static int sf_setperf(sc, idx, mac)
+ struct sf_softc *sc;
+ int idx;
+ caddr_t mac;
+{
+ u_int16_t *p;
+
+ if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
+ return(EINVAL);
+
+ if (mac == NULL)
+ return(EINVAL);
+
+ p = (u_int16_t *)mac;
+
+ csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
+ (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
+ csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
+ (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
+ csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
+ (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
+
+ return(0);
+}
+
+/*
+ * Set the bit in the 512-bit hash table that corresponds to the
+ * specified mac address 'mac.' If 'prio' is nonzero, update the
+ * priority hash table instead of the filter hash table.
+ */
+static int sf_sethash(sc, mac, prio)
+ struct sf_softc *sc;
+ caddr_t mac;
+ int prio;
+{
+ u_int32_t h = 0;
+
+ if (mac == NULL)
+ return(EINVAL);
+
+ h = sf_calchash(mac);
+
+ if (prio) {
+ SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
+ (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
+ } else {
+ SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
+ (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
+ }
+
+ return(0);
+}
+
+#ifdef notdef
+/*
+ * Set a VLAN tag in the receive filter.
+ */
+static int sf_setvlan(sc, idx, vlan)
+ struct sf_softc *sc;
+ int idx;
+ u_int32_t vlan;
+{
+ if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
+ return(EINVAL);
+
+ csr_write_4(sc, SF_RXFILT_HASH_BASE +
+ (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
+
+ return(0);
+}
+#endif
+
+static int sf_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct sf_softc *sc;
+ int i;
+ u_int32_t val = 0;
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < SF_TIMEOUT; i++) {
+ val = csr_read_4(sc, SF_PHY_REG(phy, reg));
+ if (val & SF_MII_DATAVALID)
+ break;
+ }
+
+ if (i == SF_TIMEOUT)
+ return(0);
+
+ if ((val & 0x0000FFFF) == 0xFFFF)
+ return(0);
+
+ return(val & 0x0000FFFF);
+}
+
+static int sf_miibus_writereg(dev, phy, reg, val)
+ device_t dev;
+ int phy, reg, val;
+{
+ struct sf_softc *sc;
+ int i;
+ int busy;
+
+ sc = device_get_softc(dev);
+
+ csr_write_4(sc, SF_PHY_REG(phy, reg), val);
+
+ for (i = 0; i < SF_TIMEOUT; i++) {
+ busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
+ if (!(busy & SF_MII_BUSY))
+ break;
+ }
+
+ return(0);
+}
+
+static void sf_miibus_statchg(dev)
+ device_t dev;
+{
+ struct sf_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->sf_miibus);
+
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
+ csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
+ } else {
+ SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
+ csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
+ }
+
+ return;
+}
+
+static void sf_setmulti(sc)
+ struct sf_softc *sc;
+{
+ struct ifnet *ifp;
+ int i;
+ struct ifmultiaddr *ifma;
+ u_int8_t dummy[] = { 0, 0, 0, 0, 0, 0 };
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* First zot all the existing filters. */
+ for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
+ sf_setperf(sc, i, (char *)&dummy);
+ for (i = SF_RXFILT_HASH_BASE;
+ i < (SF_RXFILT_HASH_MAX + 1); i += 4)
+ csr_write_4(sc, i, 0);
+ SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
+
+ /* Now program new ones. */
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
+ } else {
+ i = 1;
+ TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ /*
+ * Program the first 15 multicast groups
+ * into the perfect filter. For all others,
+ * use the hash table.
+ */
+ if (i < SF_RXFILT_PERFECT_CNT) {
+ sf_setperf(sc, i,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ i++;
+ continue;
+ }
+
+ sf_sethash(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
+ }
+ }
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int sf_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct sf_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->sf_miibus);
+ sc->sf_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void sf_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct sf_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->sf_miibus);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int sf_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct sf_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ SF_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->sf_if_flags & IFF_PROMISC)) {
+ SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->sf_if_flags & IFF_PROMISC) {
+ SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
+ } else if (!(ifp->if_flags & IFF_RUNNING))
+ sf_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ sf_stop(sc);
+ }
+ sc->sf_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ sf_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->sf_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ SF_UNLOCK(sc);
+
+ return(error);
+}
+
+static void sf_reset(sc)
+ struct sf_softc *sc;
+{
+ register int i;
+
+ csr_write_4(sc, SF_GEN_ETH_CTL, 0);
+ SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
+ DELAY(1000);
+ SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
+
+ SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
+
+ for (i = 0; i < SF_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
+ break;
+ }
+
+ if (i == SF_TIMEOUT)
+ printf("sf%d: reset never completed!\n", sc->sf_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+ return;
+}
+
+/*
+ * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ * We also check the subsystem ID so that we can identify exactly which
+ * NIC has been found, if possible.
+ */
+static int sf_probe(dev)
+ device_t dev;
+{
+ struct sf_type *t;
+
+ t = sf_devs;
+
+ while(t->sf_name != NULL) {
+ if ((pci_get_vendor(dev) == t->sf_vid) &&
+ (pci_get_device(dev) == t->sf_did)) {
+ switch((pci_read_config(dev,
+ SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
+ case AD_SUBSYSID_62011_REV0:
+ case AD_SUBSYSID_62011_REV1:
+ device_set_desc(dev,
+ "Adaptec ANA-62011 10/100BaseTX");
+ return(0);
+ break;
+ case AD_SUBSYSID_62022:
+ device_set_desc(dev,
+ "Adaptec ANA-62022 10/100BaseTX");
+ return(0);
+ break;
+ case AD_SUBSYSID_62044_REV0:
+ case AD_SUBSYSID_62044_REV1:
+ device_set_desc(dev,
+ "Adaptec ANA-62044 10/100BaseTX");
+ return(0);
+ break;
+ case AD_SUBSYSID_62020:
+ device_set_desc(dev,
+ "Adaptec ANA-62020 10/100BaseFX");
+ return(0);
+ break;
+ case AD_SUBSYSID_69011:
+ device_set_desc(dev,
+ "Adaptec ANA-69011 10/100BaseTX");
+ return(0);
+ break;
+ default:
+ device_set_desc(dev, t->sf_name);
+ return(0);
+ break;
+ }
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int sf_attach(dev)
+ device_t dev;
+{
+ int i;
+ u_int32_t command;
+ struct sf_softc *sc;
+ struct ifnet *ifp;
+ int unit, rid, error = 0;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct sf_softc));
+
+ mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ SF_LOCK(sc);
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, SF_PCI_LOIO, 4);
+ membase = pci_read_config(dev, SF_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, SF_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("sf%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, SF_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, SF_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, SF_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef SF_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("sf%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("sf%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = SF_RID;
+ sc->sf_res = bus_alloc_resource(dev, SF_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->sf_res == NULL) {
+ printf ("sf%d: couldn't map ports\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->sf_btag = rman_get_bustag(sc->sf_res);
+ sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->sf_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->sf_irq == NULL) {
+ printf("sf%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
+ sf_intr, sc, &sc->sf_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_res);
+ bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
+ printf("sf%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ callout_handle_init(&sc->sf_stat_ch);
+ /* Reset the adapter. */
+ sf_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ sc->arpcom.ac_enaddr[i] =
+ sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
+
+ /*
+ * An Adaptec chip was detected. Inform the world.
+ */
+ printf("sf%d: Ethernet address: %6D\n", unit,
+ sc->arpcom.ac_enaddr, ":");
+
+ sc->sf_unit = unit;
+
+ /* Allocate the descriptor queues. */
+ sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->sf_ldata == NULL) {
+ printf("sf%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
+ bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->sf_ldata, sizeof(struct sf_list_data));
+
+ /* Do MII setup. */
+ if (mii_phy_probe(dev, &sc->sf_miibus,
+ sf_ifmedia_upd, sf_ifmedia_sts)) {
+ printf("sf%d: MII without any phy!\n", sc->sf_unit);
+ contigfree(sc->sf_ldata,sizeof(struct sf_list_data),M_DEVBUF);
+ bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
+ bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "sf";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = sf_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = sf_start;
+ ifp->if_watchdog = sf_watchdog;
+ ifp->if_init = sf_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ SF_UNLOCK(sc);
+ return(0);
+
+fail:
+ SF_UNLOCK(sc);
+ mtx_destroy(&sc->sf_mtx);
+ return(error);
+}
+
+static int sf_detach(dev)
+ device_t dev;
+{
+ struct sf_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ SF_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+ sf_stop(sc);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->sf_miibus);
+
+ bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
+ bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
+
+ contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
+
+ SF_UNLOCK(sc);
+ mtx_destroy(&sc->sf_mtx);
+
+ return(0);
+}
+
+static int sf_init_rx_ring(sc)
+ struct sf_softc *sc;
+{
+ struct sf_list_data *ld;
+ int i;
+
+ ld = sc->sf_ldata;
+
+ bzero((char *)ld->sf_rx_dlist_big,
+ sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
+ bzero((char *)ld->sf_rx_clist,
+ sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
+
+ for (i = 0; i < SF_RX_DLIST_CNT; i++) {
+ if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ }
+
+ return(0);
+}
+
+static void sf_init_tx_ring(sc)
+ struct sf_softc *sc;
+{
+ struct sf_list_data *ld;
+ int i;
+
+ ld = sc->sf_ldata;
+
+ bzero((char *)ld->sf_tx_dlist,
+ sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
+ bzero((char *)ld->sf_tx_clist,
+ sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
+
+ for (i = 0; i < SF_TX_DLIST_CNT; i++)
+ ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
+ for (i = 0; i < SF_TX_CLIST_CNT; i++)
+ ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
+
+ ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
+ sc->sf_tx_cnt = 0;
+
+ return;
+}
+
+static int sf_newbuf(sc, c, m)
+ struct sf_softc *sc;
+ struct sf_rx_bufdesc_type0 *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ c->sf_mbuf = m_new;
+ c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
+ c->sf_valid = 1;
+
+ return(0);
+}
+
+/*
+ * The starfire is programmed to use 'normal' mode for packet reception,
+ * which means we use the consumer/producer model for both the buffer
+ * descriptor queue and the completion descriptor queue. The only problem
+ * with this is that it involves a lot of register accesses: we have to
+ * read the RX completion consumer and producer indexes and the RX buffer
+ * producer index, plus the RX completion consumer and RX buffer producer
+ * indexes have to be updated. It would have been easier if Adaptec had
+ * put each index in a separate register, especially given that the damn
+ * NIC has a 512K register space.
+ *
+ * In spite of all the lovely features that Adaptec crammed into the 6915,
+ * it is marred by one truly stupid design flaw, which is that receive
+ * buffer addresses must be aligned on a longword boundary. This forces
+ * the packet payload to be unaligned, which is suboptimal on the x86 and
+ * completely unuseable on the Alpha. Our only recourse is to copy received
+ * packets into properly aligned buffers before handing them off.
+ */
+
+static void sf_rxeof(sc)
+ struct sf_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct sf_rx_bufdesc_type0 *desc;
+ struct sf_rx_cmpdesc_type3 *cur_rx;
+ u_int32_t rxcons, rxprod;
+ int cmpprodidx, cmpconsidx, bufprodidx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
+ rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
+ cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
+ cmpconsidx = SF_IDX_LO(rxcons);
+ bufprodidx = SF_IDX_LO(rxprod);
+
+ while (cmpconsidx != cmpprodidx) {
+ struct mbuf *m0;
+
+ cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
+ desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
+ m = desc->sf_mbuf;
+ SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
+ SF_INC(bufprodidx, SF_RX_DLIST_CNT);
+
+ if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
+ ifp->if_ierrors++;
+ sf_newbuf(sc, desc, m);
+ continue;
+ }
+
+ m0 = m_devget(mtod(m, char *), cur_rx->sf_len, ETHER_ALIGN,
+ ifp, NULL);
+ sf_newbuf(sc, desc, m);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+
+ eh = mtod(m, struct ether_header *);
+ ifp->if_ipackets++;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ csr_write_4(sc, SF_CQ_CONSIDX,
+ (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
+ csr_write_4(sc, SF_RXDQ_PTR_Q1,
+ (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
+
+ return;
+}
+
+/*
+ * Read the transmit status from the completion queue and release
+ * mbufs. Note that the buffer descriptor index in the completion
+ * descriptor is an offset from the start of the transmit buffer
+ * descriptor list in bytes. This is important because the manual
+ * gives the impression that it should match the producer/consumer
+ * index, which is the offset in 8 byte blocks.
+ */
+static void sf_txeof(sc)
+ struct sf_softc *sc;
+{
+ int txcons, cmpprodidx, cmpconsidx;
+ struct sf_tx_cmpdesc_type1 *cur_cmp;
+ struct sf_tx_bufdesc_type0 *cur_tx;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ txcons = csr_read_4(sc, SF_CQ_CONSIDX);
+ cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
+ cmpconsidx = SF_IDX_HI(txcons);
+
+ while (cmpconsidx != cmpprodidx) {
+ cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
+ cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
+
+ if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
+ ifp->if_opackets++;
+ else {
+ if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
+ sf_txthresh_adjust(sc);
+ ifp->if_oerrors++;
+ }
+
+ sc->sf_tx_cnt--;
+ if (cur_tx->sf_mbuf != NULL) {
+ m_freem(cur_tx->sf_mbuf);
+ cur_tx->sf_mbuf = NULL;
+ } else
+ break;
+ SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
+ }
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ csr_write_4(sc, SF_CQ_CONSIDX,
+ (txcons & ~SF_CQ_CONSIDX_TXQ) |
+ ((cmpconsidx << 16) & 0xFFFF0000));
+
+ return;
+}
+
+static void sf_txthresh_adjust(sc)
+ struct sf_softc *sc;
+{
+ u_int32_t txfctl;
+ u_int8_t txthresh;
+
+ txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
+ txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
+ if (txthresh < 0xFF) {
+ txthresh++;
+ txfctl &= ~SF_TXFRMCTL_TXTHRESH;
+ txfctl |= txthresh;
+#ifdef DIAGNOSTIC
+ printf("sf%d: tx underrun, increasing "
+ "tx threshold to %d bytes\n",
+ sc->sf_unit, txthresh * 4);
+#endif
+ csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
+ }
+
+ return;
+}
+
+static void sf_intr(arg)
+ void *arg;
+{
+ struct sf_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ SF_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
+ SF_UNLOCK(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ csr_write_4(sc, SF_IMR, 0x00000000);
+
+ for (;;) {
+ status = csr_read_4(sc, SF_ISR);
+ if (status)
+ csr_write_4(sc, SF_ISR, status);
+
+ if (!(status & SF_INTRS))
+ break;
+
+ if (status & SF_ISR_RXDQ1_DMADONE)
+ sf_rxeof(sc);
+
+ if (status & SF_ISR_TX_TXDONE ||
+ status & SF_ISR_TX_DMADONE ||
+ status & SF_ISR_TX_QUEUEDONE)
+ sf_txeof(sc);
+
+ if (status & SF_ISR_TX_LOFIFO)
+ sf_txthresh_adjust(sc);
+
+ if (status & SF_ISR_ABNORMALINTR) {
+ if (status & SF_ISR_STATSOFLOW) {
+ untimeout(sf_stats_update, sc,
+ sc->sf_stat_ch);
+ sf_stats_update(sc);
+ } else
+ sf_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ csr_write_4(sc, SF_IMR, SF_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ sf_start(ifp);
+
+ SF_UNLOCK(sc);
+ return;
+}
+
+static void sf_init(xsc)
+ void *xsc;
+{
+ struct sf_softc *sc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ int i;
+
+ sc = xsc;
+ SF_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->sf_miibus);
+
+ sf_stop(sc);
+ sf_reset(sc);
+
+ /* Init all the receive filter registers */
+ for (i = SF_RXFILT_PERFECT_BASE;
+ i < (SF_RXFILT_HASH_MAX + 1); i += 4)
+ csr_write_4(sc, i, 0);
+
+ /* Empty stats counter registers. */
+ for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
+ csr_write_4(sc, SF_STATS_BASE +
+ (i + sizeof(u_int32_t)), 0);
+
+ /* Init our MAC address */
+ csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+ sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
+
+ if (sf_init_rx_ring(sc) == ENOBUFS) {
+ printf("sf%d: initialization failed: no "
+ "memory for rx buffers\n", sc->sf_unit);
+ SF_UNLOCK(sc);
+ return;
+ }
+
+ sf_init_tx_ring(sc);
+
+ csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
+ } else {
+ SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
+ } else {
+ SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
+ }
+
+ /*
+ * Load the multicast filter.
+ */
+ sf_setmulti(sc);
+
+ /* Init the completion queue indexes */
+ csr_write_4(sc, SF_CQ_CONSIDX, 0);
+ csr_write_4(sc, SF_CQ_PRODIDX, 0);
+
+ /* Init the RX completion queue */
+ csr_write_4(sc, SF_RXCQ_CTL_1,
+ vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
+ SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
+
+ /* Init RX DMA control. */
+ SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
+
+ /* Init the RX buffer descriptor queue. */
+ csr_write_4(sc, SF_RXDQ_ADDR_Q1,
+ vtophys(sc->sf_ldata->sf_rx_dlist_big));
+ csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
+ csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
+
+ /* Init the TX completion queue */
+ csr_write_4(sc, SF_TXCQ_CTL,
+ vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
+
+ /* Init the TX buffer descriptor queue. */
+ csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
+ vtophys(sc->sf_ldata->sf_tx_dlist));
+ SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
+ csr_write_4(sc, SF_TXDQ_CTL,
+ SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
+ SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
+
+ /* Enable autopadding of short TX frames. */
+ SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
+
+ /* Enable interrupts. */
+ csr_write_4(sc, SF_IMR, SF_INTRS);
+ SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
+
+ /* Enable the RX and TX engines. */
+ SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
+ SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
+
+ /*mii_mediachg(mii);*/
+ sf_ifmedia_upd(ifp);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
+
+ SF_UNLOCK(sc);
+
+ return;
+}
+
+static int sf_encap(sc, c, m_head)
+ struct sf_softc *sc;
+ struct sf_tx_bufdesc_type0 *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct sf_frag *f = NULL;
+ struct mbuf *m;
+
+ m = m_head;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == SF_MAXFRAGS)
+ break;
+ f = &c->sf_frags[frag];
+ if (frag == 0)
+ f->sf_pktlen = m_head->m_pkthdr.len;
+ f->sf_fraglen = m->m_len;
+ f->sf_addr = vtophys(mtod(m, vm_offset_t));
+ frag++;
+ }
+ }
+
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("sf%d: no memory for tx list", sc->sf_unit);
+ return(1);
+ }
+
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ printf("sf%d: no memory for tx list",
+ sc->sf_unit);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ f = &c->sf_frags[0];
+ f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
+ f->sf_addr = vtophys(mtod(m_head, caddr_t));
+ frag = 1;
+ }
+
+ c->sf_mbuf = m_head;
+ c->sf_id = SF_TX_BUFDESC_ID;
+ c->sf_fragcnt = frag;
+ c->sf_intr = 1;
+ c->sf_caltcp = 0;
+ c->sf_crcen = 1;
+
+ return(0);
+}
+
+static void sf_start(ifp)
+ struct ifnet *ifp;
+{
+ struct sf_softc *sc;
+ struct sf_tx_bufdesc_type0 *cur_tx = NULL;
+ struct mbuf *m_head = NULL;
+ int i, txprod;
+
+ sc = ifp->if_softc;
+ SF_LOCK(sc);
+
+ if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
+ SF_UNLOCK(sc);
+ return;
+ }
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ SF_UNLOCK(sc);
+ return;
+ }
+
+ txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
+ i = SF_IDX_HI(txprod) >> 4;
+
+ if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
+ printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
+ sf_init(sc);
+ txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
+ i = SF_IDX_HI(txprod) >> 4;
+ }
+
+ while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
+ if (sc->sf_tx_cnt >= (SF_TX_DLIST_CNT - 5)) {
+ ifp->if_flags |= IFF_OACTIVE;
+ cur_tx = NULL;
+ break;
+ }
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
+ if (sf_encap(sc, cur_tx, m_head)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ cur_tx = NULL;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+
+ SF_INC(i, SF_TX_DLIST_CNT);
+ sc->sf_tx_cnt++;
+ /*
+ * Don't get the TX DMA queue get too full.
+ */
+ if (sc->sf_tx_cnt > 64)
+ break;
+ }
+
+ if (cur_tx == NULL) {
+ SF_UNLOCK(sc);
+ return;
+ }
+
+ /* Transmit */
+ csr_write_4(sc, SF_TXDQ_PRODIDX,
+ (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
+ ((i << 20) & 0xFFFF0000));
+
+ ifp->if_timer = 5;
+
+ SF_UNLOCK(sc);
+
+ return;
+}
+
+static void sf_stop(sc)
+ struct sf_softc *sc;
+{
+ int i;
+ struct ifnet *ifp;
+
+ SF_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ untimeout(sf_stats_update, sc, sc->sf_stat_ch);
+
+ csr_write_4(sc, SF_GEN_ETH_CTL, 0);
+ csr_write_4(sc, SF_CQ_CONSIDX, 0);
+ csr_write_4(sc, SF_CQ_PRODIDX, 0);
+ csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
+ csr_write_4(sc, SF_RXDQ_CTL_1, 0);
+ csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
+ csr_write_4(sc, SF_TXCQ_CTL, 0);
+ csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
+ csr_write_4(sc, SF_TXDQ_CTL, 0);
+ sf_reset(sc);
+
+ sc->sf_link = 0;
+
+ for (i = 0; i < SF_RX_DLIST_CNT; i++) {
+ if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
+ m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
+ sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
+ }
+ }
+
+ for (i = 0; i < SF_TX_DLIST_CNT; i++) {
+ if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
+ m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
+ sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
+ }
+ }
+
+ ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
+ SF_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Note: it is important that this function not be interrupted. We
+ * use a two-stage register access scheme: if we are interrupted in
+ * between setting the indirect address register and reading from the
+ * indirect data register, the contents of the address register could
+ * be changed out from under us.
+ */
+static void sf_stats_update(xsc)
+ void *xsc;
+{
+ struct sf_softc *sc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ struct sf_stats stats;
+ u_int32_t *ptr;
+ int i;
+
+ sc = xsc;
+ SF_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->sf_miibus);
+
+ ptr = (u_int32_t *)&stats;
+ for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
+ ptr[i] = csr_read_4(sc, SF_STATS_BASE +
+ (i + sizeof(u_int32_t)));
+
+ for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
+ csr_write_4(sc, SF_STATS_BASE +
+ (i + sizeof(u_int32_t)), 0);
+
+ ifp->if_collisions += stats.sf_tx_single_colls +
+ stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
+
+ mii_tick(mii);
+
+ if (!sc->sf_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->sf_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ sf_start(ifp);
+ }
+
+ sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
+
+ SF_UNLOCK(sc);
+
+ return;
+}
+
+static void sf_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct sf_softc *sc;
+
+ sc = ifp->if_softc;
+
+ SF_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("sf%d: watchdog timeout\n", sc->sf_unit);
+
+ sf_stop(sc);
+ sf_reset(sc);
+ sf_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ sf_start(ifp);
+
+ SF_UNLOCK(sc);
+
+ return;
+}
+
+static void sf_shutdown(dev)
+ device_t dev;
+{
+ struct sf_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ sf_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_sfreg.h b/sys/pci/if_sfreg.h
new file mode 100644
index 0000000..1975cfc
--- /dev/null
+++ b/sys/pci/if_sfreg.h
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Registers for the Adaptec AIC-6915 Starfire. The Starfire has a 512K
+ * register space. These registers can be accessed in the following way:
+ * - PCI config registers are always accessible through PCI config space
+ * - Full 512K space mapped into memory using PCI memory mapped access
+ * - 256-byte I/O space mapped through PCI I/O access
+ * - Full 512K space mapped through indirect I/O using PCI I/O access
+ * It's possible to use either memory mapped mode or I/O mode to access
+ * the registers, but memory mapped is usually the easiest. All registers
+ * are 32 bits wide and must be accessed using 32-bit operations.
+ */
+
+/*
+ * Adaptec PCI vendor ID.
+ */
+#define AD_VENDORID 0x9004
+
+/*
+ * AIC-6915 PCI device ID.
+ */
+#define AD_DEVICEID_STARFIRE 0x6915
+
+/*
+ * AIC-6915 subsystem IDs. Adaptec uses the subsystem ID to identify
+ * the exact kind of NIC on which the ASIC is mounted. Currently there
+ * are six different variations. Note: the Adaptec manual lists code 0x28
+ * for two different NICs: the 62044 and the 69011/TX. This is a typo:
+ * the code for the 62044 is really 0x18.
+ *
+ * Note that there also appears to be an 0x19 code for a newer rev
+ * 62044 card.
+ */
+#define AD_SUBSYSID_62011_REV0 0x0008 /* single port 10/100baseTX 64-bit */
+#define AD_SUBSYSID_62011_REV1 0x0009 /* single port 10/100baseTX 64-bit */
+#define AD_SUBSYSID_62022 0x0010 /* dual port 10/100baseTX 64-bit */
+#define AD_SUBSYSID_62044_REV0 0x0018 /* quad port 10/100baseTX 64-bit */
+#define AD_SUBSYSID_62044_REV1 0x0019 /* quad port 10/100baseTX 64-bit */
+#define AD_SUBSYSID_62020 0x0020 /* single port 10/100baseFX 64-bit */
+#define AD_SUBSYSID_69011 0x0028 /* single port 10/100baseTX 32-bit */
+
+/*
+ * Starfire internal register space map. The entire register space
+ * is available using PCI memory mapped mode. The SF_RMAP_INTREG
+ * space is available using PCI I/O mode. The entire space can be
+ * accessed using indirect I/O using the indirect I/O addr and
+ * indirect I/O data registers located within the SF_RMAP_INTREG space.
+ */
+#define SF_RMAP_ROMADDR_BASE 0x00000 /* Expansion ROM space */
+#define SF_RMAP_ROMADDR_MAX 0x3FFFF
+
+#define SF_RMAP_EXGPIO_BASE 0x40000 /* External general purpose regs */
+#define SF_RMAP_EXGPIO_MAX 0x3FFFF
+
+#define SF_RMAP_INTREG_BASE 0x50000 /* Internal functional registers */
+#define SF_RMAP_INTREG_MAX 0x500FF
+#define SF_RMAP_GENREG_BASE 0x50100 /* General purpose registers */
+#define SF_RMAP_GENREG_MAX 0x5FFFF
+
+#define SF_RMAP_FIFO_BASE 0x60000
+#define SF_RMAP_FIFO_MAX 0x6FFFF
+
+#define SF_RMAP_STS_BASE 0x70000
+#define SF_RMAP_STS_MAX 0x70083
+
+#define SF_RMAP_RSVD_BASE 0x70084
+#define SF_RMAP_RSVD_MAX 0x7FFFF
+
+/*
+ * PCI config header registers, 0x0000 to 0x003F
+ */
+#define SF_PCI_VENDOR_ID 0x0000
+#define SF_PCI_DEVICE_ID 0x0002
+#define SF_PCI_COMMAND 0x0004
+#define SF_PCI_STATUS 0x0006
+#define SF_PCI_REVID 0x0008
+#define SF_PCI_CLASSCODE 0x0009
+#define SF_PCI_CACHELEN 0x000C
+#define SF_PCI_LATENCY_TIMER 0x000D
+#define SF_PCI_HEADER_TYPE 0x000E
+#define SF_PCI_LOMEM 0x0010
+#define SF_PCI_LOIO 0x0014
+#define SF_PCI_SUBVEN_ID 0x002C
+#define SF_PCI_SYBSYS_ID 0x002E
+#define SF_PCI_BIOSROM 0x0030
+#define SF_PCI_INTLINE 0x003C
+#define SF_PCI_INTPIN 0x003D
+#define SF_PCI_MINGNT 0x003E
+#define SF_PCI_MINLAT 0x003F
+
+/*
+ * PCI registers, 0x0040 to 0x006F
+ */
+#define SF_PCI_DEVCFG 0x0040
+#define SF_BACCTL 0x0044
+#define SF_PCI_MON1 0x0048
+#define SF_PCI_MON2 0x004C
+#define SF_PCI_CAPID 0x0050 /* 8 bits */
+#define SF_PCI_NEXTPTR 0x0051 /* 8 bits */
+#define SF_PCI_PWRMGMTCAP 0x0052 /* 16 bits */
+#define SF_PCI_PWRMGMTCTRL 0x0054 /* 16 bits */
+#define SF_PCI_PME_EVENT 0x0058
+#define SF_PCI_EECTL 0x0060
+#define SF_PCI_COMPLIANCE 0x0064
+#define SF_INDIRECTIO_ADDR 0x0068
+#define SF_INDIRECTIO_DATA 0x006C
+
+#define SF_PCIDEVCFG_RESET 0x00000001
+#define SF_PCIDEVCFG_FORCE64 0x00000002
+#define SF_PCIDEVCFG_SYSTEM64 0x00000004
+#define SF_PCIDEVCFG_RSVD0 0x00000008
+#define SF_PCIDEVCFG_INCR_INB 0x00000010
+#define SF_PCIDEVCFG_ABTONPERR 0x00000020
+#define SF_PCIDEVCFG_STPONPERR 0x00000040
+#define SF_PCIDEVCFG_MR_ENB 0x00000080
+#define SF_PCIDEVCFG_FIFOTHR 0x00000F00
+#define SF_PCIDEVCFG_STPONCA 0x00001000
+#define SF_PCIDEVCFG_PCIMEN 0x00002000 /* enable PCI bus master */
+#define SF_PCIDEVCFG_LATSTP 0x00004000
+#define SF_PCIDEVCFG_BYTE_ENB 0x00008000
+#define SF_PCIDEVCFG_EECSWIDTH 0x00070000
+#define SF_PCIDEVCFG_STPMWCA 0x00080000
+#define SF_PCIDEVCFG_REGCSWIDTH 0x00700000
+#define SF_PCIDEVCFG_INTR_ENB 0x00800000
+#define SF_PCIDEVCFG_DPR_ENB 0x01000000
+#define SF_PCIDEVCFG_RSVD1 0x02000000
+#define SF_PCIDEVCFG_RSVD2 0x04000000
+#define SF_PCIDEVCFG_STA_ENB 0x08000000
+#define SF_PCIDEVCFG_RTA_ENB 0x10000000
+#define SF_PCIDEVCFG_RMA_ENB 0x20000000
+#define SF_PCIDEVCFG_SSE_ENB 0x40000000
+#define SF_PCIDEVCFG_DPE_ENB 0x80000000
+
+#define SF_BACCTL_BACDMA_ENB 0x00000001
+#define SF_BACCTL_PREFER_RXDMA 0x00000002
+#define SF_BACCTL_PREFER_TXDMA 0x00000004
+#define SF_BACCTL_SINGLE_DMA 0x00000008
+#define SF_BACCTL_SWAPMODE_DATA 0x00000030
+#define SF_BACCTL_SWAPMODE_DESC 0x000000C0
+
+#define SF_SWAPMODE_LE 0x00000000
+#define SF_SWAPMODE_BE 0x00000010
+
+#define SF_PSTATE_MASK 0x0003
+#define SF_PSTATE_D0 0x0000
+#define SF_PSTATE_D1 0x0001
+#define SF_PSTATE_D2 0x0002
+#define SF_PSTATE_D3 0x0003
+#define SF_PME_EN 0x0010
+#define SF_PME_STATUS 0x8000
+
+
+/*
+ * Ethernet registers 0x0070 to 0x00FF
+ */
+#define SF_GEN_ETH_CTL 0x0070
+#define SF_TIMER_CTL 0x0074
+#define SF_CURTIME 0x0078
+#define SF_ISR 0x0080
+#define SF_ISR_SHADOW 0x0084
+#define SF_IMR 0x0088
+#define SF_GPIO 0x008C
+#define SF_TXDQ_CTL 0x0090
+#define SF_TXDQ_ADDR_HIPRIO 0x0094
+#define SF_TXDQ_ADDR_LOPRIO 0x0098
+#define SF_TXDQ_ADDR_HIADDR 0x009C
+#define SF_TXDQ_PRODIDX 0x00A0
+#define SF_TXDQ_CONSIDX 0x00A4
+#define SF_TXDMA_STS1 0x00A8
+#define SF_TXDMA_STS2 0x00AC
+#define SF_TX_FRAMCTL 0x00B0
+#define SF_TXCQ_ADDR_HI 0x00B4
+#define SF_TXCQ_CTL 0x00B8
+#define SF_RXCQ_CTL_1 0x00BC
+#define SF_RXCQ_CTL_2 0x00C0
+#define SF_CQ_CONSIDX 0x00C4
+#define SF_CQ_PRODIDX 0x00C8
+#define SF_CQ_RXQ2 0x00CC
+#define SF_RXDMA_CTL 0x00D0
+#define SF_RXDQ_CTL_1 0x00D4
+#define SF_RXDQ_CTL_2 0x00D8
+#define SF_RXDQ_ADDR_HIADDR 0x00DC
+#define SF_RXDQ_ADDR_Q1 0x00E0
+#define SF_RXDQ_ADDR_Q2 0x00E4
+#define SF_RXDQ_PTR_Q1 0x00E8
+#define SF_RXDQ_PTR_Q2 0x00EC
+#define SF_RXDMA_STS 0x00F0
+#define SF_RXFILT 0x00F4
+#define SF_RX_FRAMETEST_OUT 0x00F8
+
+/* Ethernet control register */
+#define SF_ETHCTL_RX_ENB 0x00000001
+#define SF_ETHCTL_TX_ENB 0x00000002
+#define SF_ETHCTL_RXDMA_ENB 0x00000004
+#define SF_ETHCTL_TXDMA_ENB 0x00000008
+#define SF_ETHCTL_RXGFP_ENB 0x00000010
+#define SF_ETHCTL_TXGFP_ENB 0x00000020
+#define SF_ETHCTL_SOFTINTR 0x00000800
+
+/* Timer control register */
+#define SF_TIMER_IMASK_INTERVAL 0x0000001F
+#define SF_TIMER_IMASK_MODE 0x00000060
+#define SF_TIMER_SMALLFRAME_BYP 0x00000100
+#define SF_TIMER_SMALLRX_FRAME 0x00000600
+#define SF_TIMER_TIMES_TEN 0x00000800
+#define SF_TIMER_RXHIPRIO_BYP 0x00001000
+#define SF_TIMER_TX_DMADONE_DLY 0x00002000
+#define SF_TIMER_TX_QDONE_DLY 0x00004000
+#define SF_TIMER_TX_FRDONE_DLY 0x00008000
+#define SF_TIMER_GENTIMER 0x00FF0000
+#define SF_TIMER_ONESHOT 0x01000000
+#define SF_TIMER_GENTIMER_RES 0x02000000
+#define SF_TIMER_TIMEST_RES 0x04000000
+#define SF_TIMER_RXQ2DONE_DLY 0x10000000
+#define SF_TIMER_EARLYRX2_DLY 0x20000000
+#define SF_TIMER_RXQ1DONE_DLY 0x40000000
+#define SF_TIMER_EARLYRX1_DLY 0x80000000
+
+/* Interrupt status register */
+#define SF_ISR_PCIINT_ASSERTED 0x00000001
+#define SF_ISR_GFP_TX 0x00000002
+#define SF_ISR_GFP_RX 0x00000004
+#define SF_ISR_TX_BADID_HIPRIO 0x00000008
+#define SF_ISR_TX_BADID_LOPRIO 0x00000010
+#define SF_ISR_NO_TX_CSUM 0x00000020
+#define SF_ISR_RXDQ2_NOBUFS 0x00000040
+#define SF_ISR_RXGFP_NORESP 0x00000080
+#define SF_ISR_RXDQ1_DMADONE 0x00000100
+#define SF_ISR_RXDQ2_DMADONE 0x00000200
+#define SF_ISR_RXDQ1_EARLY 0x00000400
+#define SF_ISR_RXDQ2_EARLY 0x00000800
+#define SF_ISR_TX_QUEUEDONE 0x00001000
+#define SF_ISR_TX_DMADONE 0x00002000
+#define SF_ISR_TX_TXDONE 0x00004000
+#define SF_ISR_NORMALINTR 0x00008000
+#define SF_ISR_RXDQ1_NOBUFS 0x00010000
+#define SF_ISR_RXCQ2_NOBUFS 0x00020000
+#define SF_ISR_TX_LOFIFO 0x00040000
+#define SF_ISR_DMAERR 0x00080000
+#define SF_ISR_PCIINT 0x00100000
+#define SF_ISR_TXCQ_NOBUFS 0x00200000
+#define SF_ISR_RXCQ1_NOBUFS 0x00400000
+#define SF_ISR_SOFTINTR 0x00800000
+#define SF_ISR_GENTIMER 0x01000000
+#define SF_ISR_ABNORMALINTR 0x02000000
+#define SF_ISR_RSVD0 0x04000000
+#define SF_ISR_STATSOFLOW 0x08000000
+#define SF_ISR_GPIO 0xF0000000
+
+/*
+ * Shadow interrupt status register. Unlike the normal IRQ register,
+ * reading bits here does not automatically cause them to reset.
+ */
+#define SF_SISR_PCIINT_ASSERTED 0x00000001
+#define SF_SISR_GFP_TX 0x00000002
+#define SF_SISR_GFP_RX 0x00000004
+#define SF_SISR_TX_BADID_HIPRIO 0x00000008
+#define SF_SISR_TX_BADID_LOPRIO 0x00000010
+#define SF_SISR_NO_TX_CSUM 0x00000020
+#define SF_SISR_RXDQ2_NOBUFS 0x00000040
+#define SF_SISR_RXGFP_NORESP 0x00000080
+#define SF_SISR_RXDQ1_DMADONE 0x00000100
+#define SF_SISR_RXDQ2_DMADONE 0x00000200
+#define SF_SISR_RXDQ1_EARLY 0x00000400
+#define SF_SISR_RXDQ2_EARLY 0x00000800
+#define SF_SISR_TX_QUEUEDONE 0x00001000
+#define SF_SISR_TX_DMADONE 0x00002000
+#define SF_SISR_TX_TXDONE 0x00004000
+#define SF_SISR_NORMALINTR 0x00008000
+#define SF_SISR_RXDQ1_NOBUFS 0x00010000
+#define SF_SISR_RXCQ2_NOBUFS 0x00020000
+#define SF_SISR_TX_LOFIFO 0x00040000
+#define SF_SISR_DMAERR 0x00080000
+#define SF_SISR_PCIINT 0x00100000
+#define SF_SISR_TXCQ_NOBUFS 0x00200000
+#define SF_SISR_RXCQ1_NOBUFS 0x00400000
+#define SF_SISR_SOFTINTR 0x00800000
+#define SF_SISR_GENTIMER 0x01000000
+#define SF_SISR_ABNORMALINTR 0x02000000
+#define SF_SISR_RSVD0 0x04000000
+#define SF_SISR_STATSOFLOW 0x08000000
+#define SF_SISR_GPIO 0xF0000000
+
+/* Interrupt mask register */
+#define SF_IMR_PCIINT_ASSERTED 0x00000001
+#define SF_IMR_GFP_TX 0x00000002
+#define SF_IMR_GFP_RX 0x00000004
+#define SF_IMR_TX_BADID_HIPRIO 0x00000008
+#define SF_IMR_TX_BADID_LOPRIO 0x00000010
+#define SF_IMR_NO_TX_CSUM 0x00000020
+#define SF_IMR_RXDQ2_NOBUFS 0x00000040
+#define SF_IMR_RXGFP_NORESP 0x00000080
+#define SF_IMR_RXDQ1_DMADONE 0x00000100
+#define SF_IMR_RXDQ2_DMADONE 0x00000200
+#define SF_IMR_RXDQ1_EARLY 0x00000400
+#define SF_IMR_RXDQ2_EARLY 0x00000800
+#define SF_IMR_TX_QUEUEDONE 0x00001000
+#define SF_IMR_TX_DMADONE 0x00002000
+#define SF_IMR_TX_TXDONE 0x00004000
+#define SF_IMR_NORMALINTR 0x00008000
+#define SF_IMR_RXDQ1_NOBUFS 0x00010000
+#define SF_IMR_RXCQ2_NOBUFS 0x00020000
+#define SF_IMR_TX_LOFIFO 0x00040000
+#define SF_IMR_DMAERR 0x00080000
+#define SF_IMR_PCIINT 0x00100000
+#define SF_IMR_TXCQ_NOBUFS 0x00200000
+#define SF_IMR_RXCQ1_NOBUFS 0x00400000
+#define SF_IMR_SOFTINTR 0x00800000
+#define SF_IMR_GENTIMER 0x01000000
+#define SF_IMR_ABNORMALINTR 0x02000000
+#define SF_IMR_RSVD0 0x04000000
+#define SF_IMR_STATSOFLOW 0x08000000
+#define SF_IMR_GPIO 0xF0000000
+
+#define SF_INTRS \
+ (SF_IMR_RXDQ2_NOBUFS|SF_IMR_RXDQ1_DMADONE|SF_IMR_RXDQ2_DMADONE| \
+ SF_IMR_TX_TXDONE|SF_IMR_RXDQ1_NOBUFS|SF_IMR_RXDQ2_DMADONE| \
+ SF_IMR_NORMALINTR|SF_IMR_ABNORMALINTR|SF_IMR_TXCQ_NOBUFS| \
+ SF_IMR_RXCQ1_NOBUFS|SF_IMR_RXCQ2_NOBUFS|SF_IMR_STATSOFLOW| \
+ SF_IMR_TX_LOFIFO)
+
+/* TX descriptor queue control registers */
+#define SF_TXDQCTL_DESCTYPE 0x00000007
+#define SF_TXDQCTL_NODMACMP 0x00000008
+#define SF_TXDQCTL_MINSPACE 0x00000070
+#define SF_TXDQCTL_64BITADDR 0x00000080
+#define SF_TXDQCTL_BURSTLEN 0x00003F00
+#define SF_TXDQCTL_SKIPLEN 0x001F0000
+#define SF_TXDQCTL_HIPRIOTHRESH 0xFF000000
+
+#define SF_TXBUFDESC_TYPE0 0x00000000
+#define SF_TXBUFDESC_TYPE1 0x00000001
+#define SF_TXBUFDESC_TYPE2 0x00000002
+#define SF_TXBUFDESC_TYPE3 0x00000003
+#define SF_TXBUFDESC_TYPE4 0x00000004
+
+#define SF_TXMINSPACE_UNLIMIT 0x00000000
+#define SF_TXMINSPACE_32BYTES 0x00000010
+#define SF_TXMINSPACE_64BYTES 0x00000020
+#define SF_TXMINSPACE_128BYTES 0x00000030
+#define SF_TXMINSPACE_256BYTES 0x00000040
+
+#define SF_TXSKIPLEN_0BYTES 0x00000000
+#define SF_TXSKIPLEN_8BYTES 0x00010000
+#define SF_TXSKIPLEN_16BYTES 0x00020000
+#define SF_TXSKIPLEN_24BYTES 0x00030000
+#define SF_TXSKIPLEN_32BYTES 0x00040000
+
+/* TX frame control register */
+#define SF_TXFRMCTL_TXTHRESH 0x000000FF
+#define SF_TXFRMCTL_CPLAFTERTX 0x00000100
+#define SF_TXFRMCRL_DEBUG 0x0000FE00
+#define SF_TXFRMCTL_STATUS 0x01FF0000
+#define SF_TXFRMCTL_MAC_TXIF 0xFE000000
+
+/* TX completion queue control register */
+#define SF_TXCQ_THRESH 0x0000000F
+#define SF_TXCQ_COMMON 0x00000010
+#define SF_TXCQ_SIZE 0x00000020
+#define SF_TXCQ_WRITEENB 0x00000040
+#define SF_TXCQ_USE_64BIT 0x00000080
+#define SF_TXCQ_ADDR 0xFFFFFF00
+
+/* RX completion queue control register */
+#define SF_RXCQ_THRESH 0x0000000F
+#define SF_RXCQ_TYPE 0x00000030
+#define SF_RXCQ_WRITEENB 0x00000040
+#define SF_RXCQ_USE_64BIT 0x00000080
+#define SF_RXCQ_ADDR 0xFFFFFF00
+
+#define SF_RXCQTYPE_0 0x00000000
+#define SF_RXCQTYPE_1 0x00000010
+#define SF_RXCQTYPE_2 0x00000020
+#define SF_RXCQTYPE_3 0x00000030
+
+/* TX descriptor queue producer index register */
+#define SF_TXDQ_PRODIDX_LOPRIO 0x000007FF
+#define SF_TXDQ_PRODIDX_HIPRIO 0x07FF0000
+
+/* TX descriptor queue consumer index register */
+#define SF_TXDQ_CONSIDX_LOPRIO 0x000007FF
+#define SF_TXDQ_CONSIDX_HIPRIO 0x07FF0000
+
+/* Completion queue consumer index register */
+#define SF_CQ_CONSIDX_RXQ1 0x000003FF
+#define SF_CQ_CONSIDX_RXTHRMODE 0x00008000
+#define SF_CQ_CONSIDX_TXQ 0x03FF0000
+#define SF_CQ_CONSIDX_TXTHRMODE 0x80000000
+
+/* Completion queue producer index register */
+#define SF_CQ_PRODIDX_RXQ1 0x000003FF
+#define SF_CQ_PRODIDX_TXQ 0x03FF0000
+
+/* RX completion queue 2 consumer/producer index register */
+#define SF_CQ_RXQ2_CONSIDX 0x000003FF
+#define SF_CQ_RXQ2_RXTHRMODE 0x00008000
+#define SF_CQ_RXQ2_PRODIDX 0x03FF0000
+
+#define SF_CQ_RXTHRMODE_INT_ON 0x00008000
+#define SF_CQ_RXTHRMODE_INT_OFF 0x00000000
+#define SF_CQ_TXTHRMODE_INT_ON 0x80000000
+#define SF_CQ_TXTHRMODE_INT_OFF 0x00000000
+
+#define SF_IDX_LO(x) ((x) & 0x000007FF)
+#define SF_IDX_HI(x) (((x) >> 16) & 0x000007FF)
+
+/* RX DMA control register */
+#define SF_RXDMA_BURSTSIZE 0x0000007F
+#define SF_RXDMA_FPTESTMODE 0x00000080
+#define SF_RXDMA_HIPRIOTHRESH 0x00000F00
+#define SF_RXDMA_RXEARLYTHRESH 0x0001F000
+#define SF_RXDMA_DMACRC 0x00040000
+#define SF_RXDMA_USEBKUPQUEUE 0x00080000
+#define SF_RXDMA_QUEUEMODE 0x00700000
+#define SF_RXDMA_RXCQ2_ON 0x00800000
+#define SF_RXDMA_CSUMMODE 0x03000000
+#define SF_RXDMA_DMAPAUSEPKTS 0x04000000
+#define SF_RXDMA_DMACTLPKTS 0x08000000
+#define SF_RXDMA_DMACRXERRPKTS 0x10000000
+#define SF_RXDMA_DMABADPKTS 0x20000000
+#define SF_RXDMA_DMARUNTS 0x40000000
+#define SF_RXDMA_REPORTBADPKTS 0x80000000
+
+#define SF_RXDQMODE_Q1ONLY 0x00100000
+#define SF_RXDQMODE_Q2_ON_FP 0x00200000
+#define SF_RXDQMODE_Q2_ON_SHORT 0x00300000
+#define SF_RXDQMODE_Q2_ON_PRIO 0x00400000
+#define SF_RXDQMODE_SPLITHDR 0x00500000
+
+#define SF_RXCSUMMODE_IGNORE 0x00000000
+#define SF_RXCSUMMODE_REJECT_BAD_TCP 0x01000000
+#define SF_RXCSUMMODE_REJECT_BAD_TCPUDP 0x02000000
+#define SF_RXCSUMMODE_RSVD 0x03000000
+
+/* RX descriptor queue control registers */
+#define SF_RXDQCTL_MINDESCTHR 0x0000007F
+#define SF_RXDQCTL_Q1_WE 0x00000080
+#define SF_RXDQCTL_DESCSPACE 0x00000700
+#define SF_RXDQCTL_64BITDADDR 0x00000800
+#define SF_RXDQCTL_64BITBADDR 0x00001000
+#define SF_RXDQCTL_VARIABLE 0x00002000
+#define SF_RXDQCTL_ENTRIES 0x00004000
+#define SF_RXDQCTL_PREFETCH 0x00008000
+#define SF_RXDQCTL_BUFLEN 0xFFFF0000
+
+#define SF_DESCSPACE_4BYTES 0x00000000
+#define SF_DESCSPACE_8BYTES 0x00000100
+#define SF_DESCSPACE_16BYTES 0x00000200
+#define SF_DESCSPACE_32BYTES 0x00000300
+#define SF_DESCSPACE_64BYTES 0x00000400
+#define SF_DESCSPACE_128_BYTES 0x00000500
+
+/* RX buffer consumer/producer index registers */
+#define SF_RXDQ_PRODIDX 0x000007FF
+#define SF_RXDQ_CONSIDX 0x07FF0000
+
+/* RX filter control register */
+#define SF_RXFILT_PROMISC 0x00000001
+#define SF_RXFILT_ALLMULTI 0x00000002
+#define SF_RXFILT_BROAD 0x00000004
+#define SF_RXFILT_HASHPRIO 0x00000008
+#define SF_RXFILT_HASHMODE 0x00000030
+#define SF_RXFILT_PERFMODE 0x000000C0
+#define SF_RXFILT_VLANMODE 0x00000300
+#define SF_RXFILT_WAKEMODE 0x00000C00
+#define SF_RXFILT_MULTI_NOBROAD 0x00001000
+#define SF_RXFILT_MIN_VLANPRIO 0x0000E000
+#define SF_RXFILT_PEFECTPRIO 0xFFFF0000
+
+/* Hash filtering mode */
+#define SF_HASHMODE_OFF 0x00000000
+#define SF_HASHMODE_WITHVLAN 0x00000010
+#define SF_HASHMODE_ANYVLAN 0x00000020
+#define SF_HASHMODE_ANY 0x00000030
+
+/* Perfect filtering mode */
+#define SF_PERFMODE_OFF 0x00000000
+#define SF_PERFMODE_NORMAL 0x00000040
+#define SF_PERFMODE_INVERSE 0x00000080
+#define SF_PERFMODE_VLAN 0x000000C0
+
+/* VLAN mode */
+#define SF_VLANMODE_OFF 0x00000000
+#define SF_VLANMODE_NOSTRIP 0x00000100
+#define SF_VLANMODE_STRIP 0x00000200
+#define SF_VLANMODE_RSVD 0x00000300
+
+/* Wakeup mode */
+#define SF_WAKEMODE_OFF 0x00000000
+#define SF_WAKEMODE_FILTER 0x00000400
+#define SF_WAKEMODE_FP 0x00000800
+#define SF_WAKEMODE_HIPRIO 0x00000C00
+
+/*
+ * Extra PCI registers 0x0100 to 0x0FFF
+ */
+#define SF_PCI_TARGSTAT 0x0100
+#define SF_PCI_MASTSTAT1 0x0104
+#define SF_PCI_MASTSTAT2 0x0108
+#define SF_PCI_DMAHOSTADDR_LO 0x010C
+#define SF_BAC_DMADIAG0 0x0110
+#define SF_BAC_DMADIAG1 0x0114
+#define SF_BAC_DMADIAG2 0x0118
+#define SF_BAC_DMADIAG3 0x011C
+#define SF_PAR0 0x0120
+#define SF_PAR1 0x0124
+#define SF_PCICB_FUNCEVENT 0x0130
+#define SF_PCICB_FUNCEVENT_MASK 0x0134
+#define SF_PCICB_FUNCSTATE 0x0138
+#define SF_PCICB_FUNCFORCE 0x013C
+
+/*
+ * Serial EEPROM registers 0x1000 to 0x1FFF
+ * Presumeably the EEPROM is mapped into this 8K window.
+ */
+#define SF_EEADDR_BASE 0x1000
+#define SF_EEADDR_MAX 0x1FFF
+
+#define SF_EE_NODEADDR 14
+
+/*
+ * MII registers registers 0x2000 to 0x3FFF
+ * There are 32 sets of 32 registers, one set for each possible
+ * PHY address. Each 32 bit register is split into a 16-bit data
+ * port and a couple of status bits.
+ */
+
+#define SF_MIIADDR_BASE 0x2000
+#define SF_MIIADDR_MAX 0x3FFF
+#define SF_MII_BLOCKS 32
+
+#define SF_MII_DATAVALID 0x80000000
+#define SF_MII_BUSY 0x40000000
+#define SF_MII_DATAPORT 0x0000FFFF
+
+#define SF_PHY_REG(phy, reg) \
+ (SF_MIIADDR_BASE + (phy * SF_MII_BLOCKS * sizeof(u_int32_t)) + \
+ (reg * sizeof(u_int32_t)))
+
+/*
+ * Ethernet extra registers 0x4000 to 0x4FFF
+ */
+#define SF_TESTMODE 0x4000
+#define SF_RX_FRAMEPROC_CTL 0x4004
+#define SF_TX_FRAMEPROC_CTL 0x4008
+
+/*
+ * MAC registers 0x5000 to 0x5FFF
+ */
+#define SF_MACCFG_1 0x5000
+#define SF_MACCFG_2 0x5004
+#define SF_BKTOBKIPG 0x5008
+#define SF_NONBKTOBKIPG 0x500C
+#define SF_COLRETRY 0x5010
+#define SF_MAXLEN 0x5014
+#define SF_TXNIBBLECNT 0x5018
+#define SF_TXBYTECNT 0x501C
+#define SF_RETXCNT 0x5020
+#define SF_RANDNUM 0x5024
+#define SF_RANDNUM_MASK 0x5028
+#define SF_TOTALTXCNT 0x5034
+#define SF_RXBYTECNT 0x5040
+#define SF_TXPAUSETIMER 0x5060
+#define SF_VLANTYPE 0x5064
+#define SF_MIISTATUS 0x5070
+
+#define SF_MACCFG1_HUGEFRAMES 0x00000001
+#define SF_MACCFG1_FULLDUPLEX 0x00000002
+#define SF_MACCFG1_AUTOPAD 0x00000004
+#define SF_MACCFG1_HDJAM 0x00000008
+#define SF_MACCFG1_DELAYCRC 0x00000010
+#define SF_MACCFG1_NOBACKOFF 0x00000020
+#define SF_MACCFG1_LENGTHCHECK 0x00000040
+#define SF_MACCFG1_PUREPREAMBLE 0x00000080
+#define SF_MACCFG1_PASSALLRX 0x00000100
+#define SF_MACCFG1_PREAM_DETCNT 0x00000200
+#define SF_MACCFG1_RX_FLOWENB 0x00000400
+#define SF_MACCFG1_TX_FLOWENB 0x00000800
+#define SF_MACCFG1_TESTMODE 0x00003000
+#define SF_MACCFG1_MIILOOPBK 0x00004000
+#define SF_MACCFG1_SOFTRESET 0x00008000
+
+/*
+ * There are the recommended IPG nibble counter settings
+ * specified in the Adaptec manual for full duplex and
+ * half duplex operation.
+ */
+#define SF_IPGT_FDX 0x15
+#define SF_IPGT_HDX 0x11
+
+/*
+ * RX filter registers 0x6000 to 0x6FFF
+ */
+#define SF_RXFILT_PERFECT_BASE 0x6000
+#define SF_RXFILT_PERFECT_MAX 0x60FF
+#define SF_RXFILT_PERFECT_SKIP 0x0010
+#define SF_RXFILT_PERFECT_CNT 0x0010
+
+#define SF_RXFILT_HASH_BASE 0x6100
+#define SF_RXFILT_HASH_MAX 0x62FF
+#define SF_RXFILT_HASH_SKIP 0x0010
+#define SF_RXFILT_HASH_CNT 0x001F
+#define SF_RXFILT_HASH_ADDROFF 0x0000
+#define SF_RXFILT_HASH_PRIOOFF 0x0004
+#define SF_RXFILT_HASH_VLANOFF 0x0008
+
+/*
+ * Statistics registers 0x7000 to 0x7FFF
+ */
+#define SF_STATS_BASE 0x7000
+#define SF_STATS_END 0x7FFF
+
+/*
+ * TX frame processor instruction space 0x8000 to 0x9FFF
+ */
+
+/*
+ * RX frame processor instruction space 0xA000 to 0xBFFF
+ */
+
+/*
+ * Ethernet FIFO access space 0xC000 to 0xDFFF
+ */
+
+/*
+ * Reserved 0xE000 to 0xFFFF
+ */
+
+/*
+ * Descriptor data structures.
+ */
+
+
+/* Receive descriptor formats. */
+#define SF_RX_MINSPACING 8
+#define SF_RX_DLIST_CNT 256
+#define SF_RX_CLIST_CNT 1024
+#define SF_RX_HOSTADDR(x) (((x) >> 2) & 0x3FFFFFFF)
+
+/*
+ * RX buffer descriptor type 0, 32-bit addressing. Note that we
+ * program the RX buffer queue control register(s) to allow a
+ * descriptor spacing of 16 bytes, which leaves room after each
+ * descriptor to store a pointer to the mbuf for each buffer.
+ */
+struct sf_rx_bufdesc_type0 {
+ u_int32_t sf_valid:1,
+ sf_end:1,
+ sf_addrlo:30;
+ u_int32_t sf_pad0;
+#ifdef __i386__
+ u_int32_t sf_pad1;
+#endif
+ struct mbuf *sf_mbuf;
+};
+
+/*
+ * RX buffer descriptor type 0, 64-bit addressing.
+ */
+struct sf_rx_bufdesc_type1 {
+ u_int32_t sf_valid:1,
+ sf_end:1,
+ sf_addrlo:30;
+ u_int32_t sf_addrhi;
+#ifdef __i386__
+ u_int32_t sf_pad;
+#endif
+ struct mbuf *sf_mbuf;
+};
+
+/*
+ * RX completion descriptor, type 0 (short).
+ */
+struct sf_rx_cmpdesc_type0 {
+ u_int32_t sf_len:16,
+ sf_endidx:11,
+ sf_status1:3,
+ sf_id:2;
+};
+
+/*
+ * RX completion descriptor, type 1 (basic). Includes vlan ID
+ * if this is a vlan-addressed packet, plus extended status.
+ */
+struct sf_rx_cmpdesc_type1 {
+ u_int32_t sf_len:16,
+ sf_endidx:11,
+ sf_status1:3,
+ sf_id:2;
+ u_int16_t sf_status2;
+ u_int16_t sf_vlanid;
+};
+
+/*
+ * RX completion descriptor, type 2 (checksum). Includes partial TCP/IP
+ * checksum instead of vlan tag, plus extended status.
+ */
+struct sf_rx_cmpdesc_type2 {
+ u_int32_t sf_len:16,
+ sf_endidx:11,
+ sf_status1:3,
+ sf_id:2;
+ u_int16_t sf_status2;
+ u_int16_t sf_cksum;
+};
+
+/*
+ * RX completion descriptor type 3 (full). Includes timestamp, partial
+ * TCP/IP checksum, vlan tag plus priority, two extended status fields.
+ */
+struct sf_rx_cmpdesc_type3 {
+ u_int32_t sf_len:16,
+ sf_endidx:11,
+ sf_status1:3,
+ sf_id:2;
+ u_int32_t sf_startidx:10,
+ sf_status3:6,
+ sf_status2:16;
+ u_int16_t sf_cksum;
+ u_int16_t sf_vlanid_prio;
+ u_int32_t sf_timestamp;
+};
+
+#define SF_RXSTAT1_QUEUE 0x1
+#define SF_RXSTAT1_FIFOFULL 0x2
+#define SF_RXSTAT1_OK 0x4
+
+ /* 0=unknown,5=unsupported */
+#define SF_RXSTAT2_FRAMETYPE 0x0007 /* 1=IPv4,2=IPv2,3=IPX,4=ICMP */
+#define SF_RXSTAT2_UDP 0x0008
+#define SF_RXSTAT2_TCP 0x0010
+#define SF_RXSTAT2_FRAG 0x0020
+#define SF_RXSTAT2_PCSUM_OK 0x0040 /* partial checksum ok */
+#define SF_RXSTAT2_CSUM_BAD 0x0080 /* TCP/IP checksum bad */
+#define SF_RXSTAT2_CSUM_OK 0x0100 /* TCP/IP checksum ok */
+#define SF_RXSTAT2_VLAN 0x0200
+#define SF_RXSTAT2_BADRXCODE 0x0400
+#define SF_RXSTAT2_DRIBBLE 0x0800
+#define SF_RXSTAT2_ISL_CRCERR 0x1000
+#define SF_RXSTAT2_CRCERR 0x2000
+#define SF_RXSTAT2_HASH 0x4000
+#define SF_RXSTAT2_PERFECT 0x8000
+
+#define SF_RXSTAT3_TRAILER 0x01
+#define SF_RXSTAT3_HEADER 0x02
+#define SF_RXSTAT3_CONTROL 0x04
+#define SF_RXSTAT3_PAUSE 0x08
+#define SF_RXSTAT3_ISL 0x10
+
+/*
+ * Transmit descriptor formats.
+ * Each transmit descriptor type allows for a skip field at the
+ * start of each structure. The size of the skip field can vary,
+ * however we always set it for 8 bytes, which is enough to hold
+ * a pointer (32 bits on x86, 64-bits on alpha) that we can use
+ * to hold the address of the head of the mbuf chain for the
+ * frame or fragment associated with the descriptor. This saves
+ * us from having to create a separate pointer array to hold
+ * the mbuf addresses.
+ */
+#define SF_TX_BUFDESC_ID 0xB
+#define SF_MAXFRAGS 14
+#define SF_TX_MINSPACING 128
+#define SF_TX_DLIST_CNT 128
+#define SF_TX_DLIST_SIZE 16384
+#define SF_TX_SKIPLEN 1
+#define SF_TX_CLIST_CNT 1024
+
+struct sf_frag {
+ u_int32_t sf_addr;
+ u_int16_t sf_fraglen;
+ u_int16_t sf_pktlen;
+};
+
+struct sf_frag_msdos {
+ u_int16_t sf_pktlen;
+ u_int16_t sf_fraglen;
+ u_int32_t sf_addr;
+};
+
+/*
+ * TX frame descriptor type 0, 32-bit addressing. One descriptor can
+ * be used to map multiple packet fragments. We use this format since
+ * BSD networking fragments packet data across mbuf chains. Note that
+ * the number of fragments can be variable depending on how the descriptor
+ * spacing is specified in the TX descriptor queue control register.
+ * We always use a spacing of 128 bytes, and a skipfield length of 8
+ * bytes: this means 16 bytes for the descriptor, including the skipfield,
+ * with 121 bytes left for fragment maps. Each fragment requires 8 bytes,
+ * which allows for 14 fragments per descriptor. The total size of the
+ * transmit buffer queue is limited to 16384 bytes, so with a spacing of
+ * 128 bytes per descriptor, we have room for 128 descriptors in the queue.
+ */
+struct sf_tx_bufdesc_type0 {
+#ifdef __i386__
+ u_int32_t sf_pad;
+#endif
+ struct mbuf *sf_mbuf;
+ u_int32_t sf_rsvd0:24,
+ sf_crcen:1,
+ sf_caltcp:1,
+ sf_end:1,
+ sf_intr:1,
+ sf_id:4;
+ u_int8_t sf_fragcnt;
+ u_int8_t sf_rsvd2;
+ u_int16_t sf_rsvd1;
+ struct sf_frag sf_frags[14];
+};
+
+/*
+ * TX buffer descriptor type 1, 32-bit addressing. Each descriptor
+ * maps a single fragment.
+ */
+struct sf_tx_bufdesc_type1 {
+#ifdef __i386__
+ u_int32_t sf_pad;
+#endif
+ struct mbuf *sf_mbuf;
+ u_int32_t sf_fraglen:16,
+ sf_fragcnt:8,
+ sf_crcen:1,
+ sf_caltcp:1,
+ sf_end:1,
+ sf_intr:1,
+ sf_id:4;
+ u_int32_t sf_addr;
+};
+
+/*
+ * TX buffer descriptor type 2, 64-bit addressing. Each descriptor
+ * maps a single fragment.
+ */
+struct sf_tx_bufdesc_type2 {
+#ifdef __i386__
+ u_int32_t sf_pad;
+#endif
+ struct mbuf *sf_mbuf;
+ u_int32_t sf_fraglen:16,
+ sf_fragcnt:8,
+ sf_crcen:1,
+ sf_caltcp:1,
+ sf_end:1,
+ sf_intr:1,
+ sf_id:4;
+ u_int32_t sf_addrlo;
+ u_int32_t sf_addrhi;
+};
+
+/* TX buffer descriptor type 3 is not defined. */
+
+/*
+ * TX frame descriptor type 4, 32-bit addressing. This is a special
+ * case of the type 0 descriptor, identical except that the fragment
+ * address and length fields are ordered differently. This is done
+ * to optimize copies in MS-DOS and OS/2 drivers.
+ */
+struct sf_tx_bufdesc_type4 {
+#ifdef __i386__
+ u_int32_t sf_pad;
+#endif
+ struct mbuf *sf_mbuf;
+ u_int32_t sf_rsvd0:24,
+ sf_crcen:1,
+ sf_caltcp:1,
+ sf_end:1,
+ sf_intr:1,
+ sf_id:4;
+ u_int8_t sf_fragcnt;
+ u_int8_t sf_rsvd2;
+ u_int16_t sf_rsvd1;
+ struct sf_frag_msdos sf_frags[14];
+};
+
+/*
+ * Transmit completion queue descriptor formats.
+ */
+
+/*
+ * Transmit DMA completion descriptor, type 0.
+ */
+#define SF_TXCMPTYPE_DMA 0x4
+struct sf_tx_cmpdesc_type0 {
+ u_int32_t sf_index:15,
+ sf_priority:1,
+ sf_timestamp:13,
+ sf_type:3;
+};
+
+/*
+ * Transmit completion descriptor, type 1.
+ */
+#define SF_TXCMPTYPE_TX 0x5
+struct sf_tx_cmpdesc_type1 {
+ u_int32_t sf_index:15,
+ sf_priority:1,
+ sf_txstat:13,
+ sf_type:3;
+};
+
+#define SF_TXSTAT_CRCERR 0x0001
+#define SF_TXSTAT_LENCHECKERR 0x0002
+#define SF_TXSTAT_LENRANGEERR 0x0004
+#define SF_TXSTAT_TX_OK 0x0008
+#define SF_TXSTAT_TX_DEFERED 0x0010
+#define SF_TXSTAT_EXCESS_DEFER 0x0020
+#define SF_TXSTAT_EXCESS_COLL 0x0040
+#define SF_TXSTAT_LATE_COLL 0x0080
+#define SF_TXSTAT_TOOBIG 0x0100
+#define SF_TXSTAT_TX_UNDERRUN 0x0200
+#define SF_TXSTAT_CTLFRAME_OK 0x0400
+#define SF_TXSTAT_PAUSEFRAME_OK 0x0800
+#define SF_TXSTAT_PAUSED 0x1000
+
+/* Statistics counters. */
+struct sf_stats {
+ u_int32_t sf_tx_frames;
+ u_int32_t sf_tx_single_colls;
+ u_int32_t sf_tx_multi_colls;
+ u_int32_t sf_tx_crcerrs;
+ u_int32_t sf_tx_bytes;
+ u_int32_t sf_tx_defered;
+ u_int32_t sf_tx_late_colls;
+ u_int32_t sf_tx_pause_frames;
+ u_int32_t sf_tx_control_frames;
+ u_int32_t sf_tx_excess_colls;
+ u_int32_t sf_tx_excess_defer;
+ u_int32_t sf_tx_mcast_frames;
+ u_int32_t sf_tx_bcast_frames;
+ u_int32_t sf_tx_frames_lost;
+ u_int32_t sf_rx_rx_frames;
+ u_int32_t sf_rx_crcerrs;
+ u_int32_t sf_rx_alignerrs;
+ u_int32_t sf_rx_bytes;
+ u_int32_t sf_rx_control_frames;
+ u_int32_t sf_rx_unsup_control_frames;
+ u_int32_t sf_rx_giants;
+ u_int32_t sf_rx_runts;
+ u_int32_t sf_rx_jabbererrs;
+ u_int32_t sf_rx_pkts_64;
+ u_int32_t sf_rx_pkts_65_127;
+ u_int32_t sf_rx_pkts_128_255;
+ u_int32_t sf_rx_pkts_256_511;
+ u_int32_t sf_rx_pkts_512_1023;
+ u_int32_t sf_rx_pkts_1024_1518;
+ u_int32_t sf_rx_frames_lost;
+ u_int16_t sf_tx_underruns;
+ u_int16_t sf_pad;
+};
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->sf_btag, sc->sf_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->sf_btag, sc->sf_bhandle, reg)
+
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->sf_btag, sc->sf_bhandle, reg)
+
+
+struct sf_type {
+ u_int16_t sf_vid;
+ u_int16_t sf_did;
+ char *sf_name;
+};
+
+#define SF_INC(x, y) (x) = (x + 1) % y
+
+#define ETHER_ALIGN 2
+
+/*
+ * Note: alignment is important here: each list must be aligned to
+ * a 256-byte boundary. It turns out that each ring is some multiple
+ * of 4K in length, so we can stack them all on top of each other
+ * and just worry about aligning the whole mess. There's one transmit
+ * buffer ring and two receive buffer rings: one RX ring is for small
+ * packets and the other is for large packets. Each buffer ring also
+ * has a companion completion queue.
+ */
+struct sf_list_data {
+ struct sf_tx_bufdesc_type0 sf_tx_dlist[SF_TX_DLIST_CNT];
+ struct sf_tx_cmpdesc_type1 sf_tx_clist[SF_TX_CLIST_CNT];
+ struct sf_rx_bufdesc_type0 sf_rx_dlist_big[SF_RX_DLIST_CNT];
+#ifdef notdef
+ /*
+ * Unfortunately, because the Starfire doesn't allow arbitrary
+ * byte alignment, we have to copy packets in the RX handler in
+ * order to align the payload correctly. This means that we
+ * don't gain anything by having separate large and small descriptor
+ * lists, so for now we don't bother with the small one.
+ */
+ struct sf_rx_bufdesc_type0 sf_rx_dlist_small[SF_RX_DLIST_CNT];
+#endif
+ struct sf_rx_cmpdesc_type3 sf_rx_clist[SF_RX_CLIST_CNT];
+};
+
+struct sf_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t sf_bhandle; /* bus space handle */
+ bus_space_tag_t sf_btag; /* bus space tag */
+ void *sf_intrhand; /* interrupt handler cookie */
+ struct resource *sf_irq; /* irq resource descriptor */
+ struct resource *sf_res; /* mem/ioport resource */
+ struct sf_type *sf_info; /* Starfire adapter info */
+ device_t sf_miibus;
+ u_int8_t sf_unit; /* interface number */
+ struct sf_list_data *sf_ldata;
+ int sf_tx_cnt;
+ u_int8_t sf_link;
+ int sf_if_flags;
+ struct callout_handle sf_stat_ch;
+ struct mtx sf_mtx;
+};
+
+
+#define SF_LOCK(_sc) mtx_lock(&(_sc)->sf_mtx)
+#define SF_UNLOCK(_sc) mtx_unlock(&(_sc)->sf_mtx)
+
+#define SF_TIMEOUT 1000
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_sis.c b/sys/pci/if_sis.c
new file mode 100644
index 0000000..22a2163
--- /dev/null
+++ b/sys/pci/if_sis.c
@@ -0,0 +1,2085 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are
+ * available from http://www.sis.com.tw.
+ *
+ * This driver also supports the NatSemi DP83815. Datasheets are
+ * available from http://www.national.com.
+ *
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The SiS 900 is a fairly simple chip. It uses bus master DMA with
+ * simple TX and RX descriptors of 3 longwords in size. The receiver
+ * has a single perfect filter entry for the station address and a
+ * 128-bit multicast hash table. The SiS 900 has a built-in MII-based
+ * transceiver while the 7016 requires an external transceiver chip.
+ * Both chips offer the standard bit-bang MII interface as well as
+ * an enchanced PHY interface which simplifies accessing MII registers.
+ *
+ * The only downside to this chipset is that RX descriptors must be
+ * longword aligned.
+ */
+
+#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/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <net/bpf.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define SIS_USEIOSPACE
+
+#include <pci/if_sisreg.h>
+
+MODULE_DEPEND(sis, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct sis_type sis_devs[] = {
+ { SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" },
+ { SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" },
+ { NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int sis_probe (device_t);
+static int sis_attach (device_t);
+static int sis_detach (device_t);
+
+static int sis_newbuf (struct sis_softc *,
+ struct sis_desc *, struct mbuf *);
+static int sis_encap (struct sis_softc *,
+ struct mbuf *, u_int32_t *);
+static void sis_rxeof (struct sis_softc *);
+static void sis_rxeoc (struct sis_softc *);
+static void sis_txeof (struct sis_softc *);
+static void sis_intr (void *);
+static void sis_tick (void *);
+static void sis_start (struct ifnet *);
+static int sis_ioctl (struct ifnet *, u_long, caddr_t);
+static void sis_init (void *);
+static void sis_stop (struct sis_softc *);
+static void sis_watchdog (struct ifnet *);
+static void sis_shutdown (device_t);
+static int sis_ifmedia_upd (struct ifnet *);
+static void sis_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static u_int16_t sis_reverse (u_int16_t);
+static void sis_delay (struct sis_softc *);
+static void sis_eeprom_idle (struct sis_softc *);
+static void sis_eeprom_putbyte (struct sis_softc *, int);
+static void sis_eeprom_getword (struct sis_softc *, int, u_int16_t *);
+static void sis_read_eeprom (struct sis_softc *, caddr_t, int, int, int);
+#ifdef __i386__
+static void sis_read_cmos (struct sis_softc *, device_t, caddr_t,
+ int, int);
+static void sis_read_mac (struct sis_softc *, device_t, caddr_t);
+static device_t sis_find_bridge (device_t);
+#endif
+
+static int sis_miibus_readreg (device_t, int, int);
+static int sis_miibus_writereg (device_t, int, int, int);
+static void sis_miibus_statchg (device_t);
+
+static void sis_setmulti_sis (struct sis_softc *);
+static void sis_setmulti_ns (struct sis_softc *);
+static u_int32_t sis_crc (struct sis_softc *, caddr_t);
+static void sis_reset (struct sis_softc *);
+static int sis_list_rx_init (struct sis_softc *);
+static int sis_list_tx_init (struct sis_softc *);
+
+static void sis_dma_map_desc_ptr (void *, bus_dma_segment_t *, int, int);
+static void sis_dma_map_desc_next (void *, bus_dma_segment_t *, int, int);
+static void sis_dma_map_ring (void *, bus_dma_segment_t *, int, int);
+#ifdef SIS_USEIOSPACE
+#define SIS_RES SYS_RES_IOPORT
+#define SIS_RID SIS_PCI_LOIO
+#else
+#define SIS_RES SYS_RES_MEMORY
+#define SIS_RID SIS_PCI_LOMEM
+#endif
+
+static device_method_t sis_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, sis_probe),
+ DEVMETHOD(device_attach, sis_attach),
+ DEVMETHOD(device_detach, sis_detach),
+ DEVMETHOD(device_shutdown, sis_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, sis_miibus_readreg),
+ DEVMETHOD(miibus_writereg, sis_miibus_writereg),
+ DEVMETHOD(miibus_statchg, sis_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t sis_driver = {
+ "sis",
+ sis_methods,
+ sizeof(struct sis_softc)
+};
+
+static devclass_t sis_devclass;
+
+#ifdef __i386__
+static int sis_quick=1;
+SYSCTL_INT(_hw, OID_AUTO, sis_quick, CTLFLAG_RW,
+ &sis_quick,0,"do not mdevget in sis driver");
+#endif
+
+DRIVER_MODULE(if_sis, pci, sis_driver, sis_devclass, 0, 0);
+DRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0);
+
+#define SIS_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | (x))
+
+#define SIS_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~(x))
+
+#define SIO_SET(x) \
+ CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x)
+
+#define SIO_CLR(x) \
+ CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
+
+static void
+sis_dma_map_desc_next(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg, error;
+{
+ struct sis_desc *r;
+
+ r = arg;
+ r->sis_next = segs->ds_addr;
+
+ return;
+}
+
+static void
+sis_dma_map_desc_ptr(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg, error;
+{
+ struct sis_desc *r;
+
+ r = arg;
+ r->sis_ptr = segs->ds_addr;
+
+ return;
+}
+
+static void
+sis_dma_map_ring(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg, error;
+{
+ u_int32_t *p;
+
+ p = arg;
+ *p = segs->ds_addr;
+
+ return;
+}
+
+/*
+ * Routine to reverse the bits in a word. Stolen almost
+ * verbatim from /usr/games/fortune.
+ */
+static u_int16_t sis_reverse(n)
+ u_int16_t n;
+{
+ n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa);
+ n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc);
+ n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0);
+ n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00);
+
+ return(n);
+}
+
+static void sis_delay(sc)
+ struct sis_softc *sc;
+{
+ int idx;
+
+ for (idx = (300 / 33) + 1; idx > 0; idx--)
+ CSR_READ_4(sc, SIS_CSR);
+
+ return;
+}
+
+static void sis_eeprom_idle(sc)
+ struct sis_softc *sc;
+{
+ register int i;
+
+ SIO_SET(SIS_EECTL_CSEL);
+ sis_delay(sc);
+ SIO_SET(SIS_EECTL_CLK);
+ sis_delay(sc);
+
+ for (i = 0; i < 25; i++) {
+ SIO_CLR(SIS_EECTL_CLK);
+ sis_delay(sc);
+ SIO_SET(SIS_EECTL_CLK);
+ sis_delay(sc);
+ }
+
+ SIO_CLR(SIS_EECTL_CLK);
+ sis_delay(sc);
+ SIO_CLR(SIS_EECTL_CSEL);
+ sis_delay(sc);
+ CSR_WRITE_4(sc, SIS_EECTL, 0x00000000);
+
+ return;
+}
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void sis_eeprom_putbyte(sc, addr)
+ struct sis_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ d = addr | SIS_EECMD_READ;
+
+ /*
+ * Feed in each bit and stobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ SIO_SET(SIS_EECTL_DIN);
+ } else {
+ SIO_CLR(SIS_EECTL_DIN);
+ }
+ sis_delay(sc);
+ SIO_SET(SIS_EECTL_CLK);
+ sis_delay(sc);
+ SIO_CLR(SIS_EECTL_CLK);
+ sis_delay(sc);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void sis_eeprom_getword(sc, addr, dest)
+ struct sis_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Force EEPROM to idle state. */
+ sis_eeprom_idle(sc);
+
+ /* Enter EEPROM access mode. */
+ sis_delay(sc);
+ SIO_CLR(SIS_EECTL_CLK);
+ sis_delay(sc);
+ SIO_SET(SIS_EECTL_CSEL);
+ sis_delay(sc);
+
+ /*
+ * Send address of word we want to read.
+ */
+ sis_eeprom_putbyte(sc, addr);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_SET(SIS_EECTL_CLK);
+ sis_delay(sc);
+ if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT)
+ word |= i;
+ sis_delay(sc);
+ SIO_CLR(SIS_EECTL_CLK);
+ sis_delay(sc);
+ }
+
+ /* Turn off EEPROM access mode. */
+ sis_eeprom_idle(sc);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void sis_read_eeprom(sc, dest, off, cnt, swap)
+ struct sis_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ sis_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+#ifdef __i386__
+static device_t sis_find_bridge(dev)
+ device_t dev;
+{
+ devclass_t pci_devclass;
+ device_t *pci_devices;
+ int pci_count = 0;
+ device_t *pci_children;
+ int pci_childcount = 0;
+ device_t *busp, *childp;
+ device_t child = NULL;
+ int i, j;
+
+ if ((pci_devclass = devclass_find("pci")) == NULL)
+ return(NULL);
+
+ devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
+
+ for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
+ pci_childcount = 0;
+ device_get_children(*busp, &pci_children, &pci_childcount);
+ for (j = 0, childp = pci_children;
+ j < pci_childcount; j++, childp++) {
+ if (pci_get_vendor(*childp) == SIS_VENDORID &&
+ pci_get_device(*childp) == 0x0008) {
+ child = *childp;
+ goto done;
+ }
+ }
+ }
+
+done:
+ free(pci_devices, M_TEMP);
+ free(pci_children, M_TEMP);
+ return(child);
+}
+
+static void sis_read_cmos(sc, dev, dest, off, cnt)
+ struct sis_softc *sc;
+ device_t dev;
+ caddr_t dest;
+ int off;
+ int cnt;
+{
+ device_t bridge;
+ u_int8_t reg;
+ int i;
+ bus_space_tag_t btag;
+
+ bridge = sis_find_bridge(dev);
+ if (bridge == NULL)
+ return;
+ reg = pci_read_config(bridge, 0x48, 1);
+ pci_write_config(bridge, 0x48, reg|0x40, 1);
+
+ /* XXX */
+ btag = I386_BUS_SPACE_IO;
+
+ for (i = 0; i < cnt; i++) {
+ bus_space_write_1(btag, 0x0, 0x70, i + off);
+ *(dest + i) = bus_space_read_1(btag, 0x0, 0x71);
+ }
+
+ pci_write_config(bridge, 0x48, reg & ~0x40, 1);
+ return;
+}
+
+static void sis_read_mac(sc, dev, dest)
+ struct sis_softc *sc;
+ device_t dev;
+ caddr_t dest;
+{
+ u_int32_t filtsave, csrsave;
+
+ filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
+ csrsave = CSR_READ_4(sc, SIS_CSR);
+
+ CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave);
+ CSR_WRITE_4(sc, SIS_CSR, 0);
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE);
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
+ ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1);
+ ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
+ ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA);
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
+ CSR_WRITE_4(sc, SIS_CSR, csrsave);
+ return;
+}
+#endif
+
+static int sis_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct sis_softc *sc;
+ int i, val = 0;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sis_type == SIS_TYPE_83815) {
+ if (phy != 0)
+ return(0);
+ /*
+ * The NatSemi chip can take a while after
+ * a reset to come ready, during which the BMSR
+ * returns a value of 0. This is *never* supposed
+ * to happen: some of the BMSR bits are meant to
+ * be hardwired in the on position, and this can
+ * confuse the miibus code a bit during the probe
+ * and attach phase. So we make an effort to check
+ * for this condition and wait for it to clear.
+ */
+ if (!CSR_READ_4(sc, NS_BMSR))
+ DELAY(1000);
+ val = CSR_READ_4(sc, NS_BMCR + (reg * 4));
+ return(val);
+ }
+
+ if (sc->sis_type == SIS_TYPE_900 &&
+ sc->sis_rev < SIS_REV_635 && phy != 0)
+ return(0);
+
+ CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
+ SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
+
+ for (i = 0; i < SIS_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
+ break;
+ }
+
+ if (i == SIS_TIMEOUT) {
+ printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
+ return(0);
+ }
+
+ val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
+
+ if (val == 0xFFFF)
+ return(0);
+
+ return(val);
+}
+
+static int sis_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct sis_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sis_type == SIS_TYPE_83815) {
+ if (phy != 0)
+ return(0);
+ CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
+ return(0);
+ }
+
+ if (sc->sis_type == SIS_TYPE_900 && phy != 0)
+ return(0);
+
+ CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
+ (reg << 6) | SIS_PHYOP_WRITE);
+ SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
+
+ for (i = 0; i < SIS_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
+ break;
+ }
+
+ if (i == SIS_TIMEOUT)
+ printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
+
+ return(0);
+}
+
+static void sis_miibus_statchg(dev)
+ device_t dev;
+{
+ struct sis_softc *sc;
+
+ sc = device_get_softc(dev);
+ sis_init(sc);
+
+ return;
+}
+
+static u_int32_t sis_crc(sc, addr)
+ struct sis_softc *sc;
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /*
+ * return the filter bit position
+ *
+ * The NatSemi chip has a 512-bit filter, which is
+ * different than the SiS, so we special-case it.
+ */
+ if (sc->sis_type == SIS_TYPE_83815)
+ return((crc >> 23) & 0x1FF);
+
+ return((crc >> 25) & 0x0000007F);
+}
+
+static void sis_setmulti_ns(sc)
+ struct sis_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ u_int32_t h = 0, i, filtsave;
+ int bit, index;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
+ return;
+ }
+
+ /*
+ * We have to explicitly enable the multicast hash table
+ * on the NatSemi chip if we want to use it, which we do.
+ */
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
+ SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
+
+ filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
+
+ /* first, zot all the existing hash bits */
+ for (i = 0; i < 32; i++) {
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2));
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
+ }
+
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ index = h >> 3;
+ bit = h & 0x1F;
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index);
+ if (bit > 0xF)
+ bit -= 0x10;
+ SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
+ }
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
+
+ return;
+}
+
+static void sis_setmulti_sis(sc)
+ struct sis_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ u_int32_t h = 0, i, filtsave;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
+ return;
+ }
+
+ SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
+
+ filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
+
+ /* first, zot all the existing hash bits */
+ for (i = 0; i < 8; i++) {
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + ((i * 16) >> 4)) << 16);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
+ }
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16);
+ SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF)));
+ }
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
+
+ return;
+}
+
+static void sis_reset(sc)
+ struct sis_softc *sc;
+{
+ register int i;
+
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET);
+
+ for (i = 0; i < SIS_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET))
+ break;
+ }
+
+ if (i == SIS_TIMEOUT)
+ printf("sis%d: reset never completed\n", sc->sis_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ /*
+ * If this is a NetSemi chip, make sure to clear
+ * PME mode.
+ */
+ if (sc->sis_type == SIS_TYPE_83815) {
+ CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS);
+ CSR_WRITE_4(sc, NS_CLKRUN, 0);
+ }
+
+ return;
+}
+
+/*
+ * Probe for an SiS chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int sis_probe(dev)
+ device_t dev;
+{
+ struct sis_type *t;
+
+ t = sis_devs;
+
+ while(t->sis_name != NULL) {
+ if ((pci_get_vendor(dev) == t->sis_vid) &&
+ (pci_get_device(dev) == t->sis_did)) {
+ device_set_desc(dev, t->sis_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int sis_attach(dev)
+ device_t dev;
+{
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct sis_softc *sc;
+ struct ifnet *ifp;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct sis_softc));
+
+ mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ SIS_LOCK(sc);
+
+ if (pci_get_device(dev) == SIS_DEVICEID_900)
+ sc->sis_type = SIS_TYPE_900;
+ if (pci_get_device(dev) == SIS_DEVICEID_7016)
+ sc->sis_type = SIS_TYPE_7016;
+ if (pci_get_vendor(dev) == NS_VENDORID)
+ sc->sis_type = SIS_TYPE_83815;
+
+ sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1);
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, SIS_PCI_LOIO, 4);
+ membase = pci_read_config(dev, SIS_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, SIS_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("sis%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, SIS_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, SIS_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, SIS_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef SIS_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("sis%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("sis%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;;
+ goto fail;
+ }
+#endif
+
+ rid = SIS_RID;
+ sc->sis_res = bus_alloc_resource(dev, SIS_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->sis_res == NULL) {
+ printf("sis%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->sis_btag = rman_get_bustag(sc->sis_res);
+ sc->sis_bhandle = rman_get_bushandle(sc->sis_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->sis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->sis_irq == NULL) {
+ printf("sis%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET,
+ sis_intr, sc, &sc->sis_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+ printf("sis%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Reset the adapter. */
+ sis_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ switch (pci_get_vendor(dev)) {
+ case NS_VENDORID:
+ /*
+ * Reading the MAC address out of the EEPROM on
+ * the NatSemi chip takes a bit more work than
+ * you'd expect. The address spans 4 16-bit words,
+ * with the first word containing only a single bit.
+ * You have to shift everything over one bit to
+ * get it aligned properly. Also, the bits are
+ * stored backwards (the LSB is really the MSB,
+ * and so on) so you have to reverse them in order
+ * to get the MAC address into the form we want.
+ * Why? Who the hell knows.
+ */
+ {
+ u_int16_t tmp[4];
+
+ sis_read_eeprom(sc, (caddr_t)&tmp,
+ NS_EE_NODEADDR, 4, 0);
+
+ /* Shift everything over one bit. */
+ tmp[3] = tmp[3] >> 1;
+ tmp[3] |= tmp[2] << 15;
+ tmp[2] = tmp[2] >> 1;
+ tmp[2] |= tmp[1] << 15;
+ tmp[1] = tmp[1] >> 1;
+ tmp[1] |= tmp[0] << 15;
+
+ /* Now reverse all the bits. */
+ tmp[3] = sis_reverse(tmp[3]);
+ tmp[2] = sis_reverse(tmp[2]);
+ tmp[1] = sis_reverse(tmp[1]);
+
+ bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN);
+ }
+ break;
+ case SIS_VENDORID:
+ default:
+#ifdef __i386__
+ /*
+ * If this is a SiS 630E chipset with an embedded
+ * SiS 900 controller, we have to read the MAC address
+ * from the APC CMOS RAM. Our method for doing this
+ * is very ugly since we have to reach out and grab
+ * ahold of hardware for which we cannot properly
+ * allocate resources. This code is only compiled on
+ * the i386 architecture since the SiS 630E chipset
+ * is for x86 motherboards only. Note that there are
+ * a lot of magic numbers in this hack. These are
+ * taken from SiS's Linux driver. I'd like to replace
+ * them with proper symbolic definitions, but that
+ * requires some datasheets that I don't have access
+ * to at the moment.
+ */
+ if (sc->sis_rev == SIS_REV_630S ||
+ sc->sis_rev == SIS_REV_630E ||
+ sc->sis_rev == SIS_REV_630EA1)
+ sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6);
+
+ else if (sc->sis_rev == SIS_REV_635 ||
+ sc->sis_rev == SIS_REV_630ET)
+ sis_read_mac(sc, dev, (caddr_t)&eaddr);
+ else
+#endif
+ sis_read_eeprom(sc, (caddr_t)&eaddr,
+ SIS_EE_NODEADDR, 3, 0);
+ break;
+ }
+
+ /*
+ * A SiS chip was detected. Inform the world.
+ */
+ printf("sis%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->sis_unit = unit;
+ callout_handle_init(&sc->sis_stat_ch);
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ /*
+ * Allocate the parent bus DMA tag appropriate for PCI.
+ */
+#define SIS_NSEG_NEW 32
+ error = bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, SIS_NSEG_NEW, /* maxsize, nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ &sc->sis_parent_tag);
+
+ /*
+ * Now allocate a tag for the DMA descriptor lists.
+ * All of our lists are allocated as a contiguous block
+ * of memory.
+ */
+ error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ SIS_RX_LIST_SZ, 1, /* maxsize,nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ 0, /* flags */
+ &sc->sis_ldata.sis_rx_tag);
+
+ error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ 0, /* flags */
+ &sc->sis_ldata.sis_tx_tag);
+
+ error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ 0, /* flags */
+ &sc->sis_tag);
+
+ /*
+ * Now allocate a chunk of DMA-able memory based on the
+ * tag we just created.
+ */
+ error = bus_dmamem_alloc(sc->sis_ldata.sis_tx_tag,
+ (void **)&sc->sis_ldata.sis_tx_list, BUS_DMA_NOWAIT,
+ &sc->sis_ldata.sis_tx_dmamap);
+
+ if (error) {
+ printf("sis%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag,
+ (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT,
+ &sc->sis_ldata.sis_rx_dmamap);
+
+ if (error) {
+ printf("sis%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+ bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
+ error = ENXIO;
+ goto fail;
+ }
+
+
+ bzero(sc->sis_ldata.sis_tx_list, SIS_TX_LIST_SZ);
+ bzero(sc->sis_ldata.sis_rx_list, SIS_RX_LIST_SZ);
+
+ /*
+ * Obtain the physical addresses of the RX and TX
+ * rings which we'll need later in the init routine.
+ */
+ bus_dmamap_load(sc->sis_ldata.sis_tx_tag,
+ sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]),
+ sizeof(struct sis_desc), sis_dma_map_ring,
+ &sc->sis_cdata.sis_tx_paddr, 0);
+ bus_dmamap_load(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]),
+ sizeof(struct sis_desc), sis_dma_map_ring,
+ &sc->sis_cdata.sis_rx_paddr, 0);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "sis";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = sis_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = sis_start;
+ ifp->if_watchdog = sis_watchdog;
+ ifp->if_init = sis_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = SIS_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ if (mii_phy_probe(dev, &sc->sis_miibus,
+ sis_ifmedia_upd, sis_ifmedia_sts)) {
+ printf("sis%d: MII without any PHY!\n", sc->sis_unit);
+ bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+ bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap);
+ bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+
+ /*
+ * Tell the upper layer(s) we support long frames.
+ */
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+
+ callout_handle_init(&sc->sis_stat_ch);
+ SIS_UNLOCK(sc);
+ return(0);
+
+fail:
+ SIS_UNLOCK(sc);
+ mtx_destroy(&sc->sis_mtx);
+ return(error);
+}
+
+static int sis_detach(dev)
+ device_t dev;
+{
+ struct sis_softc *sc;
+ struct ifnet *ifp;
+
+
+ sc = device_get_softc(dev);
+ SIS_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ sis_reset(sc);
+ sis_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->sis_miibus);
+
+ bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
+ bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
+
+ bus_dmamap_unload(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_dmamap);
+ bus_dmamap_unload(sc->sis_ldata.sis_tx_tag,
+ sc->sis_ldata.sis_tx_dmamap);
+ bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap);
+ bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
+ bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
+ bus_dma_tag_destroy(sc->sis_parent_tag);
+
+ SIS_UNLOCK(sc);
+ mtx_destroy(&sc->sis_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int sis_list_tx_init(sc)
+ struct sis_softc *sc;
+{
+ struct sis_list_data *ld;
+ struct sis_ring_data *cd;
+ int i, nexti;
+
+ cd = &sc->sis_cdata;
+ ld = &sc->sis_ldata;
+
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ nexti = (i == (SIS_TX_LIST_CNT - 1)) ? 0 : i+1;
+ ld->sis_tx_list[i].sis_nextdesc =
+ &ld->sis_tx_list[nexti];
+ bus_dmamap_load(sc->sis_ldata.sis_tx_tag,
+ sc->sis_ldata.sis_tx_dmamap,
+ &ld->sis_tx_list[nexti], sizeof(struct sis_desc),
+ sis_dma_map_desc_next, &ld->sis_tx_list[i], 0);
+ ld->sis_tx_list[i].sis_mbuf = NULL;
+ ld->sis_tx_list[i].sis_ptr = 0;
+ ld->sis_tx_list[i].sis_ctl = 0;
+ }
+
+ cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0;
+
+ bus_dmamap_sync(sc->sis_ldata.sis_tx_tag,
+ sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
+
+ return(0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int sis_list_rx_init(sc)
+ struct sis_softc *sc;
+{
+ struct sis_list_data *ld;
+ struct sis_ring_data *cd;
+ int i,nexti;
+
+ ld = &sc->sis_ldata;
+ cd = &sc->sis_cdata;
+
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ if (sis_newbuf(sc, &ld->sis_rx_list[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ nexti = (i == (SIS_RX_LIST_CNT - 1)) ? 0 : i+1;
+ ld->sis_rx_list[i].sis_nextdesc =
+ &ld->sis_rx_list[nexti];
+ bus_dmamap_load(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_dmamap,
+ &ld->sis_rx_list[nexti],
+ sizeof(struct sis_desc), sis_dma_map_desc_next,
+ &ld->sis_rx_list[i], 0);
+ }
+
+ bus_dmamap_sync(sc->sis_ldata.sis_rx_tag,
+ sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
+
+ cd->sis_rx_prod = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int sis_newbuf(sc, c, m)
+ struct sis_softc *sc;
+ struct sis_desc *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+
+ if (c == NULL)
+ return(EINVAL);
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ c->sis_mbuf = m_new;
+ c->sis_ctl = SIS_RXLEN;
+
+ bus_dmamap_create(sc->sis_tag, 0, &c->sis_map);
+ bus_dmamap_load(sc->sis_tag, c->sis_map,
+ mtod(m_new, void *), m_new->m_len,
+ sis_dma_map_desc_ptr, c, 0);
+ bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREWRITE);
+
+ return(0);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void sis_rxeof(sc)
+ struct sis_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct sis_desc *cur_rx;
+ int i, total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+ i = sc->sis_cdata.sis_rx_prod;
+
+ while(SIS_OWNDESC(&sc->sis_ldata.sis_rx_list[i])) {
+
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif /* DEVICE_POLLING */
+ cur_rx = &sc->sis_ldata.sis_rx_list[i];
+ rxstat = cur_rx->sis_rxstat;
+ bus_dmamap_sync(sc->sis_tag,
+ cur_rx->sis_map, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map);
+ bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map);
+ m = cur_rx->sis_mbuf;
+ cur_rx->sis_mbuf = NULL;
+ total_len = SIS_RXBYTES(cur_rx);
+ SIS_INC(i, SIS_RX_LIST_CNT);
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (!(rxstat & SIS_CMDSTS_PKT_OK)) {
+ ifp->if_ierrors++;
+ if (rxstat & SIS_RXSTAT_COLL)
+ ifp->if_collisions++;
+ sis_newbuf(sc, cur_rx, m);
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+#ifdef __i386__
+ /*
+ * On the x86 we do not have alignment problems, so try to
+ * allocate a new buffer for the receive ring, and pass up
+ * the one where the packet is already, saving the expensive
+ * copy done in m_devget().
+ * If we are on an architecture with alignment problems, or
+ * if the allocation fails, then use m_devget and leave the
+ * existing buffer in the receive ring.
+ */
+ if (sis_quick && sis_newbuf(sc, cur_rx, NULL) == 0) {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+ } else
+#endif
+ {
+ struct mbuf *m0;
+ m0 = m_devget(mtod(m, char *), total_len,
+ ETHER_ALIGN, ifp, NULL);
+ sis_newbuf(sc, cur_rx, m);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc->sis_cdata.sis_rx_prod = i;
+
+ return;
+}
+
+void sis_rxeoc(sc)
+ struct sis_softc *sc;
+{
+ sis_rxeof(sc);
+ sis_init(sc);
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void sis_txeof(sc)
+ struct sis_softc *sc;
+{
+ struct sis_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ u_int32_t idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ idx = sc->sis_cdata.sis_tx_cons;
+ while (idx != sc->sis_cdata.sis_tx_prod) {
+ cur_tx = &sc->sis_ldata.sis_tx_list[idx];
+
+ if (SIS_OWNDESC(cur_tx))
+ break;
+
+ if (cur_tx->sis_ctl & SIS_CMDSTS_MORE) {
+ sc->sis_cdata.sis_tx_cnt--;
+ SIS_INC(idx, SIS_TX_LIST_CNT);
+ continue;
+ }
+
+ if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) {
+ ifp->if_oerrors++;
+ if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS)
+ ifp->if_collisions++;
+ if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL)
+ ifp->if_collisions++;
+ }
+
+ ifp->if_collisions +=
+ (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16;
+
+ ifp->if_opackets++;
+ if (cur_tx->sis_mbuf != NULL) {
+ m_freem(cur_tx->sis_mbuf);
+ cur_tx->sis_mbuf = NULL;
+ bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map);
+ bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map);
+ }
+
+ sc->sis_cdata.sis_tx_cnt--;
+ SIS_INC(idx, SIS_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->sis_cdata.sis_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void sis_tick(xsc)
+ void *xsc;
+{
+ struct sis_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+
+ sc = xsc;
+ SIS_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ mii = device_get_softc(sc->sis_miibus);
+ mii_tick(mii);
+
+ if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->sis_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ sis_start(ifp);
+ }
+
+ sc->sis_stat_ch = timeout(sis_tick, sc, hz);
+
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+#ifdef DEVICE_POLLING
+static poll_handler_t sis_poll;
+
+static void
+sis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct sis_softc *sc = ifp->if_softc;
+
+ SIS_LOCK(sc);
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ CSR_WRITE_4(sc, SIS_IER, 1);
+ goto done;
+ }
+
+ /*
+ * On the sis, reading the status register also clears it.
+ * So before returning to intr mode we must make sure that all
+ * possible pending sources of interrupts have been served.
+ * In practice this means run to completion the *eof routines,
+ * and then call the interrupt routine
+ */
+ sc->rxcycles = count;
+ sis_rxeof(sc);
+ sis_txeof(sc);
+ if (ifp->if_snd.ifq_head != NULL)
+ sis_start(ifp);
+
+ if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
+ u_int32_t status;
+
+ /* Reading the ISR register clears all interrupts. */
+ status = CSR_READ_4(sc, SIS_ISR);
+
+ if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW))
+ sis_rxeoc(sc);
+
+ if (status & (SIS_ISR_RX_IDLE))
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+
+ if (status & SIS_ISR_SYSERR) {
+ sis_reset(sc);
+ sis_init(sc);
+ }
+ }
+done:
+ SIS_UNLOCK(sc);
+ return;
+}
+#endif /* DEVICE_POLLING */
+
+static void sis_intr(arg)
+ void *arg;
+{
+ struct sis_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+
+ SIS_LOCK(sc);
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING)
+ goto done;
+ if (ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */
+ CSR_WRITE_4(sc, SIS_IER, 0);
+ goto done;
+ }
+#endif /* DEVICE_POLLING */
+
+ /* Supress unwanted interrupts */
+ if (!(ifp->if_flags & IFF_UP)) {
+ sis_stop(sc);
+ goto done;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, SIS_IER, 0);
+
+ for (;;) {
+ /* Reading the ISR register clears all interrupts. */
+ status = CSR_READ_4(sc, SIS_ISR);
+
+ if ((status & SIS_INTRS) == 0)
+ break;
+
+ if (status &
+ (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR |
+ SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) )
+ sis_txeof(sc);
+
+ if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE))
+ sis_rxeof(sc);
+
+ if (status & (SIS_ISR_RX_ERR | SIS_ISR_RX_OFLOW))
+ sis_rxeoc(sc);
+
+ if (status & (SIS_ISR_RX_IDLE))
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+
+ if (status & SIS_ISR_SYSERR) {
+ sis_reset(sc);
+ sis_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, SIS_IER, 1);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ sis_start(ifp);
+done:
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int sis_encap(sc, m_head, txidx)
+ struct sis_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct sis_desc *f = NULL;
+ struct mbuf *m;
+ int frag, cur, cnt = 0;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if ((SIS_TX_LIST_CNT -
+ (sc->sis_cdata.sis_tx_cnt + cnt)) < 2)
+ return(ENOBUFS);
+ f = &sc->sis_ldata.sis_tx_list[frag];
+ f->sis_ctl = SIS_CMDSTS_MORE | m->m_len;
+ bus_dmamap_create(sc->sis_tag, 0, &f->sis_map);
+ bus_dmamap_load(sc->sis_tag, f->sis_map,
+ mtod(m, void *), m->m_len,
+ sis_dma_map_desc_ptr, f, 0);
+ bus_dmamap_sync(sc->sis_tag,
+ f->sis_map, BUS_DMASYNC_PREREAD);
+ if (cnt != 0)
+ f->sis_ctl |= SIS_CMDSTS_OWN;
+ cur = frag;
+ SIS_INC(frag, SIS_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->sis_ldata.sis_tx_list[cur].sis_mbuf = m_head;
+ sc->sis_ldata.sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE;
+ sc->sis_ldata.sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN;
+ sc->sis_cdata.sis_tx_cnt += cnt;
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void sis_start(ifp)
+ struct ifnet *ifp;
+{
+ struct sis_softc *sc;
+ struct mbuf *m_head = NULL;
+ u_int32_t idx;
+
+ sc = ifp->if_softc;
+ SIS_LOCK(sc);
+
+ if (!sc->sis_link) {
+ SIS_UNLOCK(sc);
+ return;
+ }
+
+ idx = sc->sis_cdata.sis_tx_prod;
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ SIS_UNLOCK(sc);
+ return;
+ }
+
+ while(sc->sis_ldata.sis_tx_list[idx].sis_mbuf == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (sis_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+
+ }
+
+ /* Transmit */
+ sc->sis_cdata.sis_tx_prod = idx;
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+static void sis_init(xsc)
+ void *xsc;
+{
+ struct sis_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+
+ SIS_LOCK(sc);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ sis_stop(sc);
+
+ mii = device_get_softc(sc->sis_miibus);
+
+ /* Set MAC address */
+ if (sc->sis_type == SIS_TYPE_83815) {
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
+ } else {
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
+ CSR_WRITE_4(sc, SIS_RXFILT_DATA,
+ ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
+ }
+
+ /* Init circular RX list. */
+ if (sis_list_rx_init(sc) == ENOBUFS) {
+ printf("sis%d: initialization failed: no "
+ "memory for rx buffers\n", sc->sis_unit);
+ sis_stop(sc);
+ SIS_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ sis_list_tx_init(sc);
+
+ /*
+ * For the NatSemi chip, we have to explicitly enable the
+ * reception of ARP frames, as well as turn on the 'perfect
+ * match' filter where we store the station address, otherwise
+ * we won't receive unicasts meant for this host.
+ */
+ if (sc->sis_type == SIS_TYPE_83815) {
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP);
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT);
+ }
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
+ } else {
+ SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
+ }
+
+ /*
+ * Set the capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
+ } else {
+ SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
+ }
+
+ /*
+ * Load the multicast filter.
+ */
+ if (sc->sis_type == SIS_TYPE_83815)
+ sis_setmulti_ns(sc);
+ else
+ sis_setmulti_sis(sc);
+
+ /* Turn the receive filter on */
+ SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
+
+ /*
+ * Load the address of the RX and TX lists.
+ */
+ CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_cdata.sis_rx_paddr);
+ CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_cdata.sis_tx_paddr);
+
+ /* Set RX configuration */
+ CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG);
+
+ /* Accept Long Packets for VLAN support */
+ SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER);
+
+ /* Set TX configuration */
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
+ CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10);
+ } else {
+ CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
+ }
+
+ /* Set full/half duplex mode. */
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ SIS_SETBIT(sc, SIS_TX_CFG,
+ (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
+ SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
+ } else {
+ SIS_CLRBIT(sc, SIS_TX_CFG,
+ (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
+ SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS);
+#ifdef DEVICE_POLLING
+ /*
+ * ... only enable interrupts if we are not polling, make sure
+ * they are off otherwise.
+ */
+ if (ifp->if_ipending & IFF_POLLING)
+ CSR_WRITE_4(sc, SIS_IER, 0);
+ else
+#endif /* DEVICE_POLLING */
+ CSR_WRITE_4(sc, SIS_IER, 1);
+
+ /* Enable receiver and transmitter. */
+ SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+
+#ifdef notdef
+ mii_mediachg(mii);
+#endif
+
+ /*
+ * Page 75 of the DP83815 manual recommends the
+ * following register settings "for optimum
+ * performance." Note however that at least three
+ * of the registers are listed as "reserved" in
+ * the register map, so who knows what they do.
+ */
+ if (sc->sis_type == SIS_TYPE_83815) {
+ CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
+ CSR_WRITE_4(sc, NS_PHY_CR, 0x189C);
+ CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000);
+ CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040);
+ CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C);
+ }
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->sis_stat_ch = timeout(sis_tick, sc, hz);
+
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int sis_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct sis_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ mii = device_get_softc(sc->sis_miibus);
+ sc->sis_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void sis_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct sis_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ mii = device_get_softc(sc->sis_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int sis_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct sis_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ sis_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ sis_stop(sc);
+ }
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ SIS_LOCK(sc);
+ if (sc->sis_type == SIS_TYPE_83815)
+ sis_setmulti_ns(sc);
+ else
+ sis_setmulti_sis(sc);
+ SIS_UNLOCK(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->sis_miibus);
+ SIS_LOCK(sc);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ SIS_UNLOCK(sc);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return(error);
+}
+
+static void sis_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct sis_softc *sc;
+
+ sc = ifp->if_softc;
+
+ SIS_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("sis%d: watchdog timeout\n", sc->sis_unit);
+
+ sis_stop(sc);
+ sis_reset(sc);
+ sis_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ sis_start(ifp);
+
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void sis_stop(sc)
+ struct sis_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ SIS_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(sis_tick, sc, sc->sis_stat_ch);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif
+ CSR_WRITE_4(sc, SIS_IER, 0);
+ CSR_WRITE_4(sc, SIS_IMR, 0);
+ SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
+ DELAY(1000);
+ CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0);
+ CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0);
+
+ sc->sis_link = 0;
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ if (sc->sis_ldata.sis_rx_list[i].sis_mbuf != NULL) {
+ bus_dmamap_unload(sc->sis_tag,
+ sc->sis_ldata.sis_rx_list[i].sis_map);
+ bus_dmamap_destroy(sc->sis_tag,
+ sc->sis_ldata.sis_rx_list[i].sis_map);
+ m_freem(sc->sis_ldata.sis_rx_list[i].sis_mbuf);
+ sc->sis_ldata.sis_rx_list[i].sis_mbuf = NULL;
+ }
+ }
+ bzero(sc->sis_ldata.sis_rx_list,
+ sizeof(sc->sis_ldata.sis_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ if (sc->sis_ldata.sis_tx_list[i].sis_mbuf != NULL) {
+ bus_dmamap_unload(sc->sis_tag,
+ sc->sis_ldata.sis_tx_list[i].sis_map);
+ bus_dmamap_destroy(sc->sis_tag,
+ sc->sis_ldata.sis_tx_list[i].sis_map);
+ m_freem(sc->sis_ldata.sis_tx_list[i].sis_mbuf);
+ sc->sis_ldata.sis_tx_list[i].sis_mbuf = NULL;
+ }
+ }
+
+ bzero(sc->sis_ldata.sis_tx_list,
+ sizeof(sc->sis_ldata.sis_tx_list));
+
+ SIS_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void sis_shutdown(dev)
+ device_t dev;
+{
+ struct sis_softc *sc;
+
+ sc = device_get_softc(dev);
+ SIS_LOCK(sc);
+ sis_reset(sc);
+ sis_stop(sc);
+ SIS_UNLOCK(sc);
+
+ return;
+}
diff --git a/sys/pci/if_sisreg.h b/sys/pci/if_sisreg.h
new file mode 100644
index 0000000..8244f2a
--- /dev/null
+++ b/sys/pci/if_sisreg.h
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Register definitions for the SiS 900 and SiS 7016 chipsets. The
+ * 7016 is actually an older chip and some of its registers differ
+ * from the 900, however the core operational registers are the same:
+ * the differences lie in the OnNow/Wake on LAN stuff which we don't
+ * use anyway. The 7016 needs an external MII compliant PHY while the
+ * SiS 900 has one built in. All registers are 32-bits wide.
+ */
+
+/* Registers common to SiS 900 and SiS 7016 */
+#define SIS_CSR 0x00
+#define SIS_CFG 0x04
+#define SIS_EECTL 0x08
+#define SIS_PCICTL 0x0C
+#define SIS_ISR 0x10
+#define SIS_IMR 0x14
+#define SIS_IER 0x18
+#define SIS_PHYCTL 0x1C
+#define SIS_TX_LISTPTR 0x20
+#define SIS_TX_CFG 0x24
+#define SIS_RX_LISTPTR 0x30
+#define SIS_RX_CFG 0x34
+#define SIS_FLOWCTL 0x38
+#define SIS_RXFILT_CTL 0x48
+#define SIS_RXFILT_DATA 0x4C
+#define SIS_PWRMAN_CTL 0xB0
+#define SIS_PWERMAN_WKUP_EVENT 0xB4
+#define SIS_WKUP_FRAME_CRC 0xBC
+#define SIS_WKUP_FRAME_MASK0 0xC0
+#define SIS_WKUP_FRAME_MASKXX 0xEC
+
+/* SiS 7016 specific registers */
+#define SIS_SILICON_REV 0x5C
+#define SIS_MIB_CTL0 0x60
+#define SIS_MIB_CTL1 0x64
+#define SIS_MIB_CTL2 0x68
+#define SIS_MIB_CTL3 0x6C
+#define SIS_MIB 0x80
+#define SIS_LINKSTS 0xA0
+#define SIS_TIMEUNIT 0xA4
+#define SIS_GPIO 0xB8
+
+/* NS DP83815 registers */
+#define NS_CLKRUN 0x3C
+#define NS_BMCR 0x80
+#define NS_BMSR 0x84
+#define NS_PHYIDR1 0x88
+#define NS_PHYIDR2 0x8C
+#define NS_ANAR 0x90
+#define NS_ANLPAR 0x94
+#define NS_ANER 0x98
+#define NS_ANNPTR 0x9C
+
+#define NS_PHY_CR 0xE4
+#define NS_PHY_10BTSCR 0xE8
+#define NS_PHY_PAGE 0xCC
+#define NS_PHY_EXTCFG 0xF0
+#define NS_PHY_DSPCFG 0xF4
+#define NS_PHY_SDCFG 0xF8
+#define NS_PHY_TDATA 0xFC
+
+#define NS_CLKRUN_PMESTS 0x00008000
+#define NS_CLKRUN_PMEENB 0x00000100
+#define NS_CLNRUN_CLKRUN_ENB 0x00000001
+
+#define SIS_CSR_TX_ENABLE 0x00000001
+#define SIS_CSR_TX_DISABLE 0x00000002
+#define SIS_CSR_RX_ENABLE 0x00000004
+#define SIS_CSR_RX_DISABLE 0x00000008
+#define SIS_CSR_TX_RESET 0x00000010
+#define SIS_CSR_RX_RESET 0x00000020
+#define SIS_CSR_SOFTINTR 0x00000080
+#define SIS_CSR_RESET 0x00000100
+#define SIS_CSR_ACCESS_MODE 0x00000200
+#define SIS_CSR_RELOAD 0x00000400
+
+#define SIS_CFG_BIGENDIAN 0x00000001
+#define SIS_CFG_PERR_DETECT 0x00000008
+#define SIS_CFG_DEFER_DISABLE 0x00000010
+#define SIS_CFG_OUTOFWIN_TIMER 0x00000020
+#define SIS_CFG_SINGLE_BACKOFF 0x00000040
+#define SIS_CFG_PCIREQ_ALG 0x00000080
+
+#define SIS_EECTL_DIN 0x00000001
+#define SIS_EECTL_DOUT 0x00000002
+#define SIS_EECTL_CLK 0x00000004
+#define SIS_EECTL_CSEL 0x00000008
+
+#define SIS_EECMD_WRITE 0x140
+#define SIS_EECMD_READ 0x180
+#define SIS_EECMD_ERASE 0x1c0
+
+#define SIS_EE_NODEADDR 0x8
+#define NS_EE_NODEADDR 0x6
+
+#define SIS_PCICTL_SRAMADDR 0x0000001F
+#define SIS_PCICTL_RAMTSTENB 0x00000020
+#define SIS_PCICTL_TXTSTENB 0x00000040
+#define SIS_PCICTL_RXTSTENB 0x00000080
+#define SIS_PCICTL_BMTSTENB 0x00000200
+#define SIS_PCICTL_RAMADDR 0x001F0000
+#define SIS_PCICTL_ROMTIME 0x0F000000
+#define SIS_PCICTL_DISCTEST 0x40000000
+
+#define SIS_ISR_RX_OK 0x00000001
+#define SIS_ISR_RX_DESC_OK 0x00000002
+#define SIS_ISR_RX_ERR 0x00000004
+#define SIS_ISR_RX_EARLY 0x00000008
+#define SIS_ISR_RX_IDLE 0x00000010
+#define SIS_ISR_RX_OFLOW 0x00000020
+#define SIS_ISR_TX_OK 0x00000040
+#define SIS_ISR_TX_DESC_OK 0x00000080
+#define SIS_ISR_TX_ERR 0x00000100
+#define SIS_ISR_TX_IDLE 0x00000200
+#define SIS_ISR_TX_UFLOW 0x00000400
+#define SIS_ISR_SOFTINTR 0x00000800
+#define SIS_ISR_HIBITS 0x00008000
+#define SIS_ISR_RX_FIFO_OFLOW 0x00010000
+#define SIS_ISR_TGT_ABRT 0x00100000
+#define SIS_ISR_BM_ABRT 0x00200000
+#define SIS_ISR_SYSERR 0x00400000
+#define SIS_ISR_PARITY_ERR 0x00800000
+#define SIS_ISR_RX_RESET_DONE 0x01000000
+#define SIS_ISR_TX_RESET_DONE 0x02000000
+#define SIS_ISR_TX_PAUSE_START 0x04000000
+#define SIS_ISR_TX_PAUSE_DONE 0x08000000
+#define SIS_ISR_WAKE_EVENT 0x10000000
+
+#define SIS_IMR_RX_OK 0x00000001
+#define SIS_IMR_RX_DESC_OK 0x00000002
+#define SIS_IMR_RX_ERR 0x00000004
+#define SIS_IMR_RX_EARLY 0x00000008
+#define SIS_IMR_RX_IDLE 0x00000010
+#define SIS_IMR_RX_OFLOW 0x00000020
+#define SIS_IMR_TX_OK 0x00000040
+#define SIS_IMR_TX_DESC_OK 0x00000080
+#define SIS_IMR_TX_ERR 0x00000100
+#define SIS_IMR_TX_IDLE 0x00000200
+#define SIS_IMR_TX_UFLOW 0x00000400
+#define SIS_IMR_SOFTINTR 0x00000800
+#define SIS_IMR_HIBITS 0x00008000
+#define SIS_IMR_RX_FIFO_OFLOW 0x00010000
+#define SIS_IMR_TGT_ABRT 0x00100000
+#define SIS_IMR_BM_ABRT 0x00200000
+#define SIS_IMR_SYSERR 0x00400000
+#define SIS_IMR_PARITY_ERR 0x00800000
+#define SIS_IMR_RX_RESET_DONE 0x01000000
+#define SIS_IMR_TX_RESET_DONE 0x02000000
+#define SIS_IMR_TX_PAUSE_START 0x04000000
+#define SIS_IMR_TX_PAUSE_DONE 0x08000000
+#define SIS_IMR_WAKE_EVENT 0x10000000
+
+#define SIS_INTRS \
+ (SIS_IMR_RX_OFLOW|SIS_IMR_TX_UFLOW|SIS_IMR_TX_OK|\
+ SIS_IMR_TX_IDLE|SIS_IMR_RX_OK|SIS_IMR_RX_ERR|\
+ SIS_IMR_RX_IDLE|\
+ SIS_IMR_SYSERR)
+
+#define SIS_IER_INTRENB 0x00000001
+
+#define SIS_PHYCTL_ACCESS 0x00000010
+#define SIS_PHYCTL_OP 0x00000020
+#define SIS_PHYCTL_REGADDR 0x000007C0
+#define SIS_PHYCTL_PHYADDR 0x0000F800
+#define SIS_PHYCTL_PHYDATA 0xFFFF0000
+
+#define SIS_PHYOP_READ 0x00000020
+#define SIS_PHYOP_WRITE 0x00000000
+
+#define SIS_TXCFG_DRAIN_THRESH 0x0000003F /* 32-byte units */
+#define SIS_TXCFG_FILL_THRESH 0x00003F00 /* 32-byte units */
+#define SIS_TXCFG_DMABURST 0x00700000
+#define SIS_TXCFG_AUTOPAD 0x10000000
+#define SIS_TXCFG_LOOPBK 0x20000000
+#define SIS_TXCFG_IGN_HBEAT 0x40000000
+#define SIS_TXCFG_IGN_CARR 0x80000000
+
+#define SIS_TXCFG_DRAIN(x) (((x) >> 5) & SIS_TXCFG_DRAIN_THRESH)
+#define SIS_TXCFG_FILL(x) ((((x) >> 5) << 8) & SIS_TXCFG_FILL_THRESH)
+
+#define SIS_TXDMA_512BYTES 0x00000000
+#define SIS_TXDMA_4BYTES 0x00100000
+#define SIS_TXDMA_8BYTES 0x00200000
+#define SIS_TXDMA_16BYTES 0x00300000
+#define SIS_TXDMA_32BYTES 0x00400000
+#define SIS_TXDMA_64BYTES 0x00500000
+#define SIS_TXDMA_128BYTES 0x00600000
+#define SIS_TXDMA_256BYTES 0x00700000
+
+#define SIS_TXCFG_100 \
+ (SIS_TXDMA_64BYTES|SIS_TXCFG_AUTOPAD|\
+ SIS_TXCFG_FILL(64)|SIS_TXCFG_DRAIN(1536))
+
+#define SIS_TXCFG_10 \
+ (SIS_TXDMA_32BYTES|SIS_TXCFG_AUTOPAD|\
+ SIS_TXCFG_FILL(64)|SIS_TXCFG_DRAIN(1536))
+
+#define SIS_RXCFG_DRAIN_THRESH 0x0000003E /* 8-byte units */
+#define SIS_RXCFG_DMABURST 0x00700000
+#define SIS_RXCFG_RX_JABBER 0x08000000
+#define SIS_RXCFG_RX_TXPKTS 0x10000000
+#define SIS_RXCFG_RX_RUNTS 0x40000000
+#define SIS_RXCFG_RX_GIANTS 0x80000000
+
+#define SIS_RXCFG_DRAIN(x) ((((x) >> 3) << 1) & SIS_RXCFG_DRAIN_THRESH)
+
+#define SIS_RXDMA_512BYTES 0x00000000
+#define SIS_RXDMA_4BYTES 0x00100000
+#define SIS_RXDMA_8BYTES 0x00200000
+#define SIS_RXDMA_16BYTES 0x00300000
+#define SIS_RXDMA_32BYTES 0x00400000
+#define SIS_RXDMA_64BYTES 0x00500000
+#define SIS_RXDMA_128BYTES 0x00600000
+#define SIS_RXDMA_256BYTES 0x00700000
+
+#define SIS_RXCFG \
+ (SIS_RXCFG_DRAIN(64)|SIS_RXDMA_256BYTES)
+
+#define SIS_RXFILTCTL_ADDR 0x000F0000
+#define NS_RXFILTCTL_MCHASH 0x00200000
+#define NS_RXFILTCTL_ARP 0x00400000
+#define NS_RXFILTCTL_PERFECT 0x08000000
+#define SIS_RXFILTCTL_ALLPHYS 0x10000000
+#define SIS_RXFILTCTL_ALLMULTI 0x20000000
+#define SIS_RXFILTCTL_BROAD 0x40000000
+#define SIS_RXFILTCTL_ENABLE 0x80000000
+
+#define SIS_FILTADDR_PAR0 0x00000000
+#define SIS_FILTADDR_PAR1 0x00010000
+#define SIS_FILTADDR_PAR2 0x00020000
+#define SIS_FILTADDR_MAR0 0x00040000
+#define SIS_FILTADDR_MAR1 0x00050000
+#define SIS_FILTADDR_MAR2 0x00060000
+#define SIS_FILTADDR_MAR3 0x00070000
+#define SIS_FILTADDR_MAR4 0x00080000
+#define SIS_FILTADDR_MAR5 0x00090000
+#define SIS_FILTADDR_MAR6 0x000A0000
+#define SIS_FILTADDR_MAR7 0x000B0000
+
+#define NS_FILTADDR_PAR0 0x00000000
+#define NS_FILTADDR_PAR1 0x00000002
+#define NS_FILTADDR_PAR2 0x00000004
+
+#define NS_FILTADDR_FMEM_LO 0x00000200
+#define NS_FILTADDR_FMEM_HI 0x000003FE
+
+/*
+ * DMA descriptor structures. The first part of the descriptor
+ * is the hardware descriptor format, which is just three longwords.
+ * After this, we include some additional structure members for
+ * use by the driver. Note that for this structure will be a different
+ * size on the alpha, but that's okay as long as it's a multiple of 4
+ * bytes in size.
+ */
+struct sis_desc {
+ /* SiS hardware descriptor section */
+ u_int32_t sis_next;
+ u_int32_t sis_cmdsts;
+#define sis_rxstat sis_cmdsts
+#define sis_txstat sis_cmdsts
+#define sis_ctl sis_cmdsts
+ u_int32_t sis_ptr;
+ /* Driver software section */
+ struct mbuf *sis_mbuf;
+ struct sis_desc *sis_nextdesc;
+ bus_dmamap_t sis_map;
+};
+
+#define SIS_CMDSTS_BUFLEN 0x00000FFF
+#define SIS_CMDSTS_PKT_OK 0x08000000
+#define SIS_CMDSTS_CRC 0x10000000
+#define SIS_CMDSTS_INTR 0x20000000
+#define SIS_CMDSTS_MORE 0x40000000
+#define SIS_CMDSTS_OWN 0x80000000
+
+#define SIS_LASTDESC(x) (!((x)->sis_ctl & SIS_CMDSTS_MORE)))
+#define SIS_OWNDESC(x) ((x)->sis_ctl & SIS_CMDSTS_OWN)
+#define SIS_INC(x, y) { if (++(x) == y) x = 0; }
+#define SIS_RXBYTES(x) (((x)->sis_ctl & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN)
+
+#define SIS_RXSTAT_COLL 0x00010000
+#define SIS_RXSTAT_LOOPBK 0x00020000
+#define SIS_RXSTAT_ALIGNERR 0x00040000
+#define SIS_RXSTAT_CRCERR 0x00080000
+#define SIS_RXSTAT_SYMBOLERR 0x00100000
+#define SIS_RXSTAT_RUNT 0x00200000
+#define SIS_RXSTAT_GIANT 0x00400000
+#define SIS_RXSTAT_DSTCLASS 0x01800000
+#define SIS_RXSTAT_OVERRUN 0x02000000
+#define SIS_RXSTAT_RX_ABORT 0x04000000
+
+#define SIS_DSTCLASS_REJECT 0x00000000
+#define SIS_DSTCLASS_UNICAST 0x00800000
+#define SIS_DSTCLASS_MULTICAST 0x01000000
+#define SIS_DSTCLASS_BROADCAST 0x02000000
+
+#define SIS_TXSTAT_COLLCNT 0x000F0000
+#define SIS_TXSTAT_EXCESSCOLLS 0x00100000
+#define SIS_TXSTAT_OUTOFWINCOLL 0x00200000
+#define SIS_TXSTAT_EXCESS_DEFER 0x00400000
+#define SIS_TXSTAT_DEFERED 0x00800000
+#define SIS_TXSTAT_CARR_LOST 0x01000000
+#define SIS_TXSTAT_UNDERRUN 0x02000000
+#define SIS_TXSTAT_TX_ABORT 0x04000000
+
+#define SIS_RX_LIST_CNT 64
+#define SIS_TX_LIST_CNT 128
+
+#define SIS_RX_LIST_SZ SIS_RX_LIST_CNT * sizeof(struct sis_desc)
+#define SIS_TX_LIST_SZ SIS_TX_LIST_CNT * sizeof(struct sis_desc)
+
+struct sis_list_data {
+#ifdef foo
+ struct sis_desc sis_rx_list[SIS_RX_LIST_CNT];
+ struct sis_desc sis_tx_list[SIS_TX_LIST_CNT];
+#endif
+ struct sis_desc *sis_rx_list;
+ struct sis_desc *sis_tx_list;
+ bus_dma_tag_t sis_rx_tag;
+ bus_dmamap_t sis_rx_dmamap;
+ bus_dma_tag_t sis_tx_tag;
+ bus_dmamap_t sis_tx_dmamap;
+};
+
+struct sis_ring_data {
+ int sis_rx_prod;
+ int sis_tx_prod;
+ int sis_tx_cons;
+ int sis_tx_cnt;
+ u_int32_t sis_rx_paddr;
+ u_int32_t sis_tx_paddr;
+};
+
+
+/*
+ * SiS PCI vendor ID.
+ */
+#define SIS_VENDORID 0x1039
+
+/*
+ * SiS PCI device IDs
+ */
+#define SIS_DEVICEID_900 0x0900
+#define SIS_DEVICEID_7016 0x7016
+
+/*
+ * SiS 900 PCI revision codes.
+ */
+#define SIS_REV_630E 0x0081
+#define SIS_REV_630S 0x0082
+#define SIS_REV_630EA1 0x0083
+#define SIS_REV_630ET 0x0084
+#define SIS_REV_635 0x0090
+
+/*
+ * NatSemi vendor ID
+ */
+#define NS_VENDORID 0x100B
+
+/*
+ * DP83815 device ID
+ */
+#define NS_DEVICEID_DP83815 0x0020
+
+struct sis_type {
+ u_int16_t sis_vid;
+ u_int16_t sis_did;
+ char *sis_name;
+};
+
+#define SIS_TYPE_900 1
+#define SIS_TYPE_7016 2
+#define SIS_TYPE_83815 3
+
+struct sis_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t sis_bhandle;
+ bus_space_tag_t sis_btag;
+ struct resource *sis_res;
+ struct resource *sis_irq;
+ void *sis_intrhand;
+ device_t sis_miibus;
+ u_int8_t sis_unit;
+ u_int8_t sis_type;
+ u_int8_t sis_rev;
+ u_int8_t sis_link;
+ struct sis_list_data sis_ldata;
+ bus_dma_tag_t sis_parent_tag;
+ bus_dma_tag_t sis_tag;
+ struct sis_ring_data sis_cdata;
+ struct callout_handle sis_stat_ch;
+#ifdef DEVICE_POLLING
+ int rxcycles;
+#endif
+ struct mtx sis_mtx;
+};
+
+#define SIS_LOCK(_sc) mtx_lock(&(_sc)->sis_mtx)
+#define SIS_UNLOCK(_sc) mtx_unlock(&(_sc)->sis_mtx)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->sis_btag, sc->sis_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->sis_btag, sc->sis_bhandle, reg)
+
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->sis_btag, sc->sis_bhandle, reg)
+
+#define SIS_TIMEOUT 1000
+#define ETHER_ALIGN 2
+#define SIS_RXLEN 1536
+#define SIS_MIN_FRAMELEN 60
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define SIS_PCI_VENDOR_ID 0x00
+#define SIS_PCI_DEVICE_ID 0x02
+#define SIS_PCI_COMMAND 0x04
+#define SIS_PCI_STATUS 0x06
+#define SIS_PCI_REVID 0x08
+#define SIS_PCI_CLASSCODE 0x09
+#define SIS_PCI_CACHELEN 0x0C
+#define SIS_PCI_LATENCY_TIMER 0x0D
+#define SIS_PCI_HEADER_TYPE 0x0E
+#define SIS_PCI_LOIO 0x10
+#define SIS_PCI_LOMEM 0x14
+#define SIS_PCI_BIOSROM 0x30
+#define SIS_PCI_INTLINE 0x3C
+#define SIS_PCI_INTPIN 0x3D
+#define SIS_PCI_MINGNT 0x3E
+#define SIS_PCI_MINLAT 0x0F
+#define SIS_PCI_RESETOPT 0x48
+#define SIS_PCI_EEPROM_DATA 0x4C
+
+/* power management registers */
+#define SIS_PCI_CAPID 0x50 /* 8 bits */
+#define SIS_PCI_NEXTPTR 0x51 /* 8 bits */
+#define SIS_PCI_PWRMGMTCAP 0x52 /* 16 bits */
+#define SIS_PCI_PWRMGMTCTRL 0x54 /* 16 bits */
+
+#define SIS_PSTATE_MASK 0x0003
+#define SIS_PSTATE_D0 0x0000
+#define SIS_PSTATE_D1 0x0001
+#define SIS_PSTATE_D2 0x0002
+#define SIS_PSTATE_D3 0x0003
+#define SIS_PME_EN 0x0010
+#define SIS_PME_STATUS 0x8000
diff --git a/sys/pci/if_sk.c b/sys/pci/if_sk.c
new file mode 100644
index 0000000..adb523c
--- /dev/null
+++ b/sys/pci/if_sk.c
@@ -0,0 +1,2218 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * SysKonnect SK-NET gigabit ethernet driver for FreeBSD. Supports
+ * the SK-984x series adapters, both single port and dual port.
+ * References:
+ * The XaQti XMAC II datasheet,
+ * http://www.freebsd.org/~wpaul/SysKonnect/xmacii_datasheet_rev_c_9-29.pdf
+ * The SysKonnect GEnesis manual, http://www.syskonnect.com
+ *
+ * Note: XaQti has been aquired by Vitesse, and Vitesse does not have the
+ * XMAC II datasheet online. I have put my copy at people.freebsd.org as a
+ * convenience to others until Vitesse corrects this problem:
+ *
+ * http://people.freebsd.org/~wpaul/SysKonnect/xmacii_datasheet_rev_c_9-29.pdf
+ *
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
+ * Department of Electrical Engineering
+ * Columbia University, New York City
+ */
+
+/*
+ * The SysKonnect gigabit ethernet adapters consist of two main
+ * components: the SysKonnect GEnesis controller chip and the XaQti Corp.
+ * XMAC II gigabit ethernet MAC. The XMAC provides all of the MAC
+ * components and a PHY while the GEnesis controller provides a PCI
+ * interface with DMA support. Each card may have between 512K and
+ * 2MB of SRAM on board depending on the configuration.
+ *
+ * The SysKonnect GEnesis controller can have either one or two XMAC
+ * chips connected to it, allowing single or dual port NIC configurations.
+ * SysKonnect has the distinction of being the only vendor on the market
+ * with a dual port gigabit ethernet NIC. The GEnesis provides dual FIFOs,
+ * dual DMA queues, packet/MAC/transmit arbiters and direct access to the
+ * XMAC registers. This driver takes advantage of these features to allow
+ * both XMACs to operate as independent interfaces.
+ */
+
+#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/queue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/brgphyreg.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define SK_USEIOSPACE
+
+#include <pci/if_skreg.h>
+#include <pci/xmaciireg.h>
+
+MODULE_DEPEND(sk, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static struct sk_type sk_devs[] = {
+ { SK_VENDORID, SK_DEVICEID_GE, "SysKonnect Gigabit Ethernet" },
+ { 0, 0, NULL }
+};
+
+static int sk_probe (device_t);
+static int sk_attach (device_t);
+static int sk_detach (device_t);
+static int sk_detach_xmac (device_t);
+static int sk_probe_xmac (device_t);
+static int sk_attach_xmac (device_t);
+static void sk_tick (void *);
+static void sk_intr (void *);
+static void sk_intr_xmac (struct sk_if_softc *);
+static void sk_intr_bcom (struct sk_if_softc *);
+static void sk_rxeof (struct sk_if_softc *);
+static void sk_txeof (struct sk_if_softc *);
+static int sk_encap (struct sk_if_softc *, struct mbuf *,
+ u_int32_t *);
+static void sk_start (struct ifnet *);
+static int sk_ioctl (struct ifnet *, u_long, caddr_t);
+static void sk_init (void *);
+static void sk_init_xmac (struct sk_if_softc *);
+static void sk_stop (struct sk_if_softc *);
+static void sk_watchdog (struct ifnet *);
+static void sk_shutdown (device_t);
+static int sk_ifmedia_upd (struct ifnet *);
+static void sk_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+static void sk_reset (struct sk_softc *);
+static int sk_newbuf (struct sk_if_softc *,
+ struct sk_chain *, struct mbuf *);
+static int sk_alloc_jumbo_mem (struct sk_if_softc *);
+static void *sk_jalloc (struct sk_if_softc *);
+static void sk_jfree (void *, void *);
+static int sk_init_rx_ring (struct sk_if_softc *);
+static void sk_init_tx_ring (struct sk_if_softc *);
+static u_int32_t sk_win_read_4 (struct sk_softc *, int);
+static u_int16_t sk_win_read_2 (struct sk_softc *, int);
+static u_int8_t sk_win_read_1 (struct sk_softc *, int);
+static void sk_win_write_4 (struct sk_softc *, int, u_int32_t);
+static void sk_win_write_2 (struct sk_softc *, int, u_int32_t);
+static void sk_win_write_1 (struct sk_softc *, int, u_int32_t);
+static u_int8_t sk_vpd_readbyte (struct sk_softc *, int);
+static void sk_vpd_read_res (struct sk_softc *, struct vpd_res *, int);
+static void sk_vpd_read (struct sk_softc *);
+
+static int sk_miibus_readreg (device_t, int, int);
+static int sk_miibus_writereg (device_t, int, int, int);
+static void sk_miibus_statchg (device_t);
+
+static u_int32_t sk_calchash (caddr_t);
+static void sk_setfilt (struct sk_if_softc *, caddr_t, int);
+static void sk_setmulti (struct sk_if_softc *);
+
+#ifdef SK_USEIOSPACE
+#define SK_RES SYS_RES_IOPORT
+#define SK_RID SK_PCI_LOIO
+#else
+#define SK_RES SYS_RES_MEMORY
+#define SK_RID SK_PCI_LOMEM
+#endif
+
+/*
+ * Note that we have newbus methods for both the GEnesis controller
+ * itself and the XMAC(s). The XMACs are children of the GEnesis, and
+ * the miibus code is a child of the XMACs. We need to do it this way
+ * so that the miibus drivers can access the PHY registers on the
+ * right PHY. It's not quite what I had in mind, but it's the only
+ * design that achieves the desired effect.
+ */
+static device_method_t skc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, sk_probe),
+ DEVMETHOD(device_attach, sk_attach),
+ DEVMETHOD(device_detach, sk_detach),
+ DEVMETHOD(device_shutdown, sk_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ { 0, 0 }
+};
+
+static driver_t skc_driver = {
+ "skc",
+ skc_methods,
+ sizeof(struct sk_softc)
+};
+
+static devclass_t skc_devclass;
+
+static device_method_t sk_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, sk_probe_xmac),
+ DEVMETHOD(device_attach, sk_attach_xmac),
+ DEVMETHOD(device_detach, sk_detach_xmac),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, sk_miibus_readreg),
+ DEVMETHOD(miibus_writereg, sk_miibus_writereg),
+ DEVMETHOD(miibus_statchg, sk_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t sk_driver = {
+ "sk",
+ sk_methods,
+ sizeof(struct sk_if_softc)
+};
+
+static devclass_t sk_devclass;
+
+DRIVER_MODULE(if_sk, pci, skc_driver, skc_devclass, 0, 0);
+DRIVER_MODULE(sk, skc, sk_driver, sk_devclass, 0, 0);
+DRIVER_MODULE(miibus, sk, miibus_driver, miibus_devclass, 0, 0);
+
+#define SK_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x)
+
+#define SK_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x)
+
+#define SK_WIN_SETBIT_4(sc, reg, x) \
+ sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) | x)
+
+#define SK_WIN_CLRBIT_4(sc, reg, x) \
+ sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) & ~x)
+
+#define SK_WIN_SETBIT_2(sc, reg, x) \
+ sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) | x)
+
+#define SK_WIN_CLRBIT_2(sc, reg, x) \
+ sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) & ~x)
+
+static u_int32_t sk_win_read_4(sc, reg)
+ struct sk_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ return(CSR_READ_4(sc, SK_WIN_BASE + SK_REG(reg)));
+}
+
+static u_int16_t sk_win_read_2(sc, reg)
+ struct sk_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ return(CSR_READ_2(sc, SK_WIN_BASE + SK_REG(reg)));
+}
+
+static u_int8_t sk_win_read_1(sc, reg)
+ struct sk_softc *sc;
+ int reg;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ return(CSR_READ_1(sc, SK_WIN_BASE + SK_REG(reg)));
+}
+
+static void sk_win_write_4(sc, reg, val)
+ struct sk_softc *sc;
+ int reg;
+ u_int32_t val;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ CSR_WRITE_4(sc, SK_WIN_BASE + SK_REG(reg), val);
+ return;
+}
+
+static void sk_win_write_2(sc, reg, val)
+ struct sk_softc *sc;
+ int reg;
+ u_int32_t val;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ CSR_WRITE_2(sc, SK_WIN_BASE + SK_REG(reg), (u_int32_t)val);
+ return;
+}
+
+static void sk_win_write_1(sc, reg, val)
+ struct sk_softc *sc;
+ int reg;
+ u_int32_t val;
+{
+ CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg));
+ CSR_WRITE_1(sc, SK_WIN_BASE + SK_REG(reg), val);
+ return;
+}
+
+/*
+ * The VPD EEPROM contains Vital Product Data, as suggested in
+ * the PCI 2.1 specification. The VPD data is separared into areas
+ * denoted by resource IDs. The SysKonnect VPD contains an ID string
+ * resource (the name of the adapter), a read-only area resource
+ * containing various key/data fields and a read/write area which
+ * can be used to store asset management information or log messages.
+ * We read the ID string and read-only into buffers attached to
+ * the controller softc structure for later use. At the moment,
+ * we only use the ID string during sk_attach().
+ */
+static u_int8_t sk_vpd_readbyte(sc, addr)
+ struct sk_softc *sc;
+ int addr;
+{
+ int i;
+
+ sk_win_write_2(sc, SK_PCI_REG(SK_PCI_VPD_ADDR), addr);
+ for (i = 0; i < SK_TIMEOUT; i++) {
+ DELAY(1);
+ if (sk_win_read_2(sc,
+ SK_PCI_REG(SK_PCI_VPD_ADDR)) & SK_VPD_FLAG)
+ break;
+ }
+
+ if (i == SK_TIMEOUT)
+ return(0);
+
+ return(sk_win_read_1(sc, SK_PCI_REG(SK_PCI_VPD_DATA)));
+}
+
+static void sk_vpd_read_res(sc, res, addr)
+ struct sk_softc *sc;
+ struct vpd_res *res;
+ int addr;
+{
+ int i;
+ u_int8_t *ptr;
+
+ ptr = (u_int8_t *)res;
+ for (i = 0; i < sizeof(struct vpd_res); i++)
+ ptr[i] = sk_vpd_readbyte(sc, i + addr);
+
+ return;
+}
+
+static void sk_vpd_read(sc)
+ struct sk_softc *sc;
+{
+ int pos = 0, i;
+ struct vpd_res res;
+
+ if (sc->sk_vpd_prodname != NULL)
+ free(sc->sk_vpd_prodname, M_DEVBUF);
+ if (sc->sk_vpd_readonly != NULL)
+ free(sc->sk_vpd_readonly, M_DEVBUF);
+ sc->sk_vpd_prodname = NULL;
+ sc->sk_vpd_readonly = NULL;
+
+ sk_vpd_read_res(sc, &res, pos);
+
+ if (res.vr_id != VPD_RES_ID) {
+ printf("skc%d: bad VPD resource id: expected %x got %x\n",
+ sc->sk_unit, VPD_RES_ID, res.vr_id);
+ return;
+ }
+
+ pos += sizeof(res);
+ sc->sk_vpd_prodname = malloc(res.vr_len + 1, M_DEVBUF, M_NOWAIT);
+ for (i = 0; i < res.vr_len; i++)
+ sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos);
+ sc->sk_vpd_prodname[i] = '\0';
+ pos += i;
+
+ sk_vpd_read_res(sc, &res, pos);
+
+ if (res.vr_id != VPD_RES_READ) {
+ printf("skc%d: bad VPD resource id: expected %x got %x\n",
+ sc->sk_unit, VPD_RES_READ, res.vr_id);
+ return;
+ }
+
+ pos += sizeof(res);
+ sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
+ for (i = 0; i < res.vr_len + 1; i++)
+ sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos);
+
+ return;
+}
+
+static int sk_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct sk_if_softc *sc_if;
+ int i;
+
+ sc_if = device_get_softc(dev);
+
+ if (sc_if->sk_phytype == SK_PHYTYPE_XMAC && phy != 0)
+ return(0);
+
+ SK_IF_LOCK(sc_if);
+
+ SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg|(phy << 8));
+ SK_XM_READ_2(sc_if, XM_PHY_DATA);
+ if (sc_if->sk_phytype != SK_PHYTYPE_XMAC) {
+ for (i = 0; i < SK_TIMEOUT; i++) {
+ DELAY(1);
+ if (SK_XM_READ_2(sc_if, XM_MMUCMD) &
+ XM_MMUCMD_PHYDATARDY)
+ break;
+ }
+
+ if (i == SK_TIMEOUT) {
+ printf("sk%d: phy failed to come ready\n",
+ sc_if->sk_unit);
+ return(0);
+ }
+ }
+ DELAY(1);
+ i = SK_XM_READ_2(sc_if, XM_PHY_DATA);
+ SK_IF_UNLOCK(sc_if);
+ return(i);
+}
+
+static int sk_miibus_writereg(dev, phy, reg, val)
+ device_t dev;
+ int phy, reg, val;
+{
+ struct sk_if_softc *sc_if;
+ int i;
+
+ sc_if = device_get_softc(dev);
+ SK_IF_LOCK(sc_if);
+
+ SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg|(phy << 8));
+ for (i = 0; i < SK_TIMEOUT; i++) {
+ if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY))
+ break;
+ }
+
+ if (i == SK_TIMEOUT) {
+ printf("sk%d: phy failed to come ready\n", sc_if->sk_unit);
+ return(ETIMEDOUT);
+ }
+
+ SK_XM_WRITE_2(sc_if, XM_PHY_DATA, val);
+ for (i = 0; i < SK_TIMEOUT; i++) {
+ DELAY(1);
+ if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY))
+ break;
+ }
+
+ SK_IF_UNLOCK(sc_if);
+
+ if (i == SK_TIMEOUT)
+ printf("sk%d: phy write timed out\n", sc_if->sk_unit);
+
+ return(0);
+}
+
+static void sk_miibus_statchg(dev)
+ device_t dev;
+{
+ struct sk_if_softc *sc_if;
+ struct mii_data *mii;
+
+ sc_if = device_get_softc(dev);
+ mii = device_get_softc(sc_if->sk_miibus);
+ SK_IF_LOCK(sc_if);
+ /*
+ * If this is a GMII PHY, manually set the XMAC's
+ * duplex mode accordingly.
+ */
+ if (sc_if->sk_phytype != SK_PHYTYPE_XMAC) {
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_GMIIFDX);
+ } else {
+ SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_GMIIFDX);
+ }
+ }
+ SK_IF_UNLOCK(sc_if);
+
+ return;
+}
+
+#define SK_POLY 0xEDB88320
+#define SK_BITS 6
+
+static u_int32_t sk_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t idx, bit, data, crc;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? SK_POLY : 0);
+ }
+
+ return (~crc & ((1 << SK_BITS) - 1));
+}
+
+static void sk_setfilt(sc_if, addr, slot)
+ struct sk_if_softc *sc_if;
+ caddr_t addr;
+ int slot;
+{
+ int base;
+
+ base = XM_RXFILT_ENTRY(slot);
+
+ SK_XM_WRITE_2(sc_if, base, *(u_int16_t *)(&addr[0]));
+ SK_XM_WRITE_2(sc_if, base + 2, *(u_int16_t *)(&addr[2]));
+ SK_XM_WRITE_2(sc_if, base + 4, *(u_int16_t *)(&addr[4]));
+
+ return;
+}
+
+static void sk_setmulti(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct ifnet *ifp;
+ u_int32_t hashes[2] = { 0, 0 };
+ int h, i;
+ struct ifmultiaddr *ifma;
+ u_int8_t dummy[] = { 0, 0, 0, 0, 0 ,0 };
+
+ ifp = &sc_if->arpcom.ac_if;
+
+ /* First, zot all the existing filters. */
+ for (i = 1; i < XM_RXFILT_MAX; i++)
+ sk_setfilt(sc_if, (caddr_t)&dummy, i);
+ SK_XM_WRITE_4(sc_if, XM_MAR0, 0);
+ SK_XM_WRITE_4(sc_if, XM_MAR2, 0);
+
+ /* Now program new ones. */
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ hashes[0] = 0xFFFFFFFF;
+ hashes[1] = 0xFFFFFFFF;
+ } else {
+ i = 1;
+ TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ /*
+ * Program the first XM_RXFILT_MAX multicast groups
+ * into the perfect filter. For all others,
+ * use the hash table.
+ */
+ if (i < XM_RXFILT_MAX) {
+ sk_setfilt(sc_if,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i);
+ i++;
+ continue;
+ }
+
+ h = sk_calchash(
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+ }
+
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_HASH|
+ XM_MODE_RX_USE_PERFECT);
+ SK_XM_WRITE_4(sc_if, XM_MAR0, hashes[0]);
+ SK_XM_WRITE_4(sc_if, XM_MAR2, hashes[1]);
+
+ return;
+}
+
+static int sk_init_rx_ring(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_chain_data *cd;
+ struct sk_ring_data *rd;
+ int i;
+
+ cd = &sc_if->sk_cdata;
+ rd = sc_if->sk_rdata;
+
+ bzero((char *)rd->sk_rx_ring,
+ sizeof(struct sk_rx_desc) * SK_RX_RING_CNT);
+
+ for (i = 0; i < SK_RX_RING_CNT; i++) {
+ cd->sk_rx_chain[i].sk_desc = &rd->sk_rx_ring[i];
+ if (sk_newbuf(sc_if, &cd->sk_rx_chain[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (SK_RX_RING_CNT - 1)) {
+ cd->sk_rx_chain[i].sk_next =
+ &cd->sk_rx_chain[0];
+ rd->sk_rx_ring[i].sk_next =
+ vtophys(&rd->sk_rx_ring[0]);
+ } else {
+ cd->sk_rx_chain[i].sk_next =
+ &cd->sk_rx_chain[i + 1];
+ rd->sk_rx_ring[i].sk_next =
+ vtophys(&rd->sk_rx_ring[i + 1]);
+ }
+ }
+
+ sc_if->sk_cdata.sk_rx_prod = 0;
+ sc_if->sk_cdata.sk_rx_cons = 0;
+
+ return(0);
+}
+
+static void sk_init_tx_ring(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_chain_data *cd;
+ struct sk_ring_data *rd;
+ int i;
+
+ cd = &sc_if->sk_cdata;
+ rd = sc_if->sk_rdata;
+
+ bzero((char *)sc_if->sk_rdata->sk_tx_ring,
+ sizeof(struct sk_tx_desc) * SK_TX_RING_CNT);
+
+ for (i = 0; i < SK_TX_RING_CNT; i++) {
+ cd->sk_tx_chain[i].sk_desc = &rd->sk_tx_ring[i];
+ if (i == (SK_TX_RING_CNT - 1)) {
+ cd->sk_tx_chain[i].sk_next =
+ &cd->sk_tx_chain[0];
+ rd->sk_tx_ring[i].sk_next =
+ vtophys(&rd->sk_tx_ring[0]);
+ } else {
+ cd->sk_tx_chain[i].sk_next =
+ &cd->sk_tx_chain[i + 1];
+ rd->sk_tx_ring[i].sk_next =
+ vtophys(&rd->sk_tx_ring[i + 1]);
+ }
+ }
+
+ sc_if->sk_cdata.sk_tx_prod = 0;
+ sc_if->sk_cdata.sk_tx_cons = 0;
+ sc_if->sk_cdata.sk_tx_cnt = 0;
+
+ return;
+}
+
+static int sk_newbuf(sc_if, c, m)
+ struct sk_if_softc *sc_if;
+ struct sk_chain *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct sk_rx_desc *r;
+
+ if (m == NULL) {
+ caddr_t *buf = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ /* Allocate the jumbo buffer */
+ buf = sk_jalloc(sc_if);
+ if (buf == NULL) {
+ m_freem(m_new);
+#ifdef SK_VERBOSE
+ printf("sk%d: jumbo allocation failed "
+ "-- packet dropped!\n", sc_if->sk_unit);
+#endif
+ return(ENOBUFS);
+ }
+
+ /* Attach the buffer to the mbuf */
+ MEXTADD(m_new, buf, SK_JLEN, sk_jfree,
+ (struct sk_if_softc *)sc_if, 0, EXT_NET_DRV);
+ m_new->m_data = (void *)buf;
+ m_new->m_pkthdr.len = m_new->m_len = SK_JLEN;
+ } else {
+ /*
+ * We're re-using a previously allocated mbuf;
+ * be sure to re-init pointers and lengths to
+ * default values.
+ */
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = SK_JLEN;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ /*
+ * Adjust alignment so packet payload begins on a
+ * longword boundary. Mandatory for Alpha, useful on
+ * x86 too.
+ */
+ m_adj(m_new, ETHER_ALIGN);
+
+ r = c->sk_desc;
+ c->sk_mbuf = m_new;
+ r->sk_data_lo = vtophys(mtod(m_new, caddr_t));
+ r->sk_ctl = m_new->m_len | SK_RXSTAT;
+
+ return(0);
+}
+
+/*
+ * Allocate jumbo buffer storage. The SysKonnect adapters support
+ * "jumbograms" (9K frames), although SysKonnect doesn't currently
+ * use them in their drivers. In order for us to use them, we need
+ * large 9K receive buffers, however standard mbuf clusters are only
+ * 2048 bytes in size. Consequently, we need to allocate and manage
+ * our own jumbo buffer pool. Fortunately, this does not require an
+ * excessive amount of additional code.
+ */
+static int sk_alloc_jumbo_mem(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ caddr_t ptr;
+ register int i;
+ struct sk_jpool_entry *entry;
+
+ /* Grab a big chunk o' storage. */
+ sc_if->sk_cdata.sk_jumbo_buf = contigmalloc(SK_JMEM, M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc_if->sk_cdata.sk_jumbo_buf == NULL) {
+ printf("sk%d: no memory for jumbo buffers!\n", sc_if->sk_unit);
+ return(ENOBUFS);
+ }
+
+ SLIST_INIT(&sc_if->sk_jfree_listhead);
+ SLIST_INIT(&sc_if->sk_jinuse_listhead);
+
+ /*
+ * Now divide it up into 9K pieces and save the addresses
+ * in an array.
+ */
+ ptr = sc_if->sk_cdata.sk_jumbo_buf;
+ for (i = 0; i < SK_JSLOTS; i++) {
+ sc_if->sk_cdata.sk_jslots[i] = ptr;
+ ptr += SK_JLEN;
+ entry = malloc(sizeof(struct sk_jpool_entry),
+ M_DEVBUF, M_NOWAIT);
+ if (entry == NULL) {
+ free(sc_if->sk_cdata.sk_jumbo_buf, M_DEVBUF);
+ sc_if->sk_cdata.sk_jumbo_buf = NULL;
+ printf("sk%d: no memory for jumbo "
+ "buffer queue!\n", sc_if->sk_unit);
+ return(ENOBUFS);
+ }
+ entry->slot = i;
+ SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead,
+ entry, jpool_entries);
+ }
+
+ return(0);
+}
+
+/*
+ * Allocate a jumbo buffer.
+ */
+static void *sk_jalloc(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_jpool_entry *entry;
+
+ entry = SLIST_FIRST(&sc_if->sk_jfree_listhead);
+
+ if (entry == NULL) {
+#ifdef SK_VERBOSE
+ printf("sk%d: no free jumbo buffers\n", sc_if->sk_unit);
+#endif
+ return(NULL);
+ }
+
+ SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries);
+ SLIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries);
+ return(sc_if->sk_cdata.sk_jslots[entry->slot]);
+}
+
+/*
+ * Release a jumbo buffer.
+ */
+static void sk_jfree(buf, args)
+ void *buf;
+ void *args;
+{
+ struct sk_if_softc *sc_if;
+ int i;
+ struct sk_jpool_entry *entry;
+
+ /* Extract the softc struct pointer. */
+ sc_if = (struct sk_if_softc *)args;
+
+ if (sc_if == NULL)
+ panic("sk_jfree: didn't get softc pointer!");
+
+ /* calculate the slot this buffer belongs to */
+ i = ((vm_offset_t)buf
+ - (vm_offset_t)sc_if->sk_cdata.sk_jumbo_buf) / SK_JLEN;
+
+ if ((i < 0) || (i >= SK_JSLOTS))
+ panic("sk_jfree: asked to free buffer that we don't manage!");
+
+ entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead);
+ if (entry == NULL)
+ panic("sk_jfree: buffer not in use!");
+ entry->slot = i;
+ SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries);
+ SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, jpool_entries);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int sk_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct sk_if_softc *sc_if;
+ struct mii_data *mii;
+
+ sc_if = ifp->if_softc;
+ mii = device_get_softc(sc_if->sk_miibus);
+ sk_init(sc_if);
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void sk_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct sk_if_softc *sc_if;
+ struct mii_data *mii;
+
+ sc_if = ifp->if_softc;
+ mii = device_get_softc(sc_if->sk_miibus);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int sk_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct sk_if_softc *sc_if = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0;
+ struct mii_data *mii;
+
+ SK_IF_LOCK(sc_if);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > SK_JUMBO_MTU)
+ error = EINVAL;
+ else {
+ ifp->if_mtu = ifr->ifr_mtu;
+ sk_init(sc_if);
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc_if->sk_if_flags & IFF_PROMISC)) {
+ SK_XM_SETBIT_4(sc_if, XM_MODE,
+ XM_MODE_RX_PROMISC);
+ sk_setmulti(sc_if);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc_if->sk_if_flags & IFF_PROMISC) {
+ SK_XM_CLRBIT_4(sc_if, XM_MODE,
+ XM_MODE_RX_PROMISC);
+ sk_setmulti(sc_if);
+ } else
+ sk_init(sc_if);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ sk_stop(sc_if);
+ }
+ sc_if->sk_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ sk_setmulti(sc_if);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc_if->sk_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ SK_IF_UNLOCK(sc_if);
+
+ return(error);
+}
+
+/*
+ * Probe for a SysKonnect GEnesis chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int sk_probe(dev)
+ device_t dev;
+{
+ struct sk_type *t;
+
+ t = sk_devs;
+
+ while(t->sk_name != NULL) {
+ if ((pci_get_vendor(dev) == t->sk_vid) &&
+ (pci_get_device(dev) == t->sk_did)) {
+ device_set_desc(dev, t->sk_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Force the GEnesis into reset, then bring it out of reset.
+ */
+static void sk_reset(sc)
+ struct sk_softc *sc;
+{
+ CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_RESET);
+ CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_RESET);
+ DELAY(1000);
+ CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_UNRESET);
+ CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_UNRESET);
+
+ /* Configure packet arbiter */
+ sk_win_write_2(sc, SK_PKTARB_CTL, SK_PKTARBCTL_UNRESET);
+ sk_win_write_2(sc, SK_RXPA1_TINIT, SK_PKTARB_TIMEOUT);
+ sk_win_write_2(sc, SK_TXPA1_TINIT, SK_PKTARB_TIMEOUT);
+ sk_win_write_2(sc, SK_RXPA2_TINIT, SK_PKTARB_TIMEOUT);
+ sk_win_write_2(sc, SK_TXPA2_TINIT, SK_PKTARB_TIMEOUT);
+
+ /* Enable RAM interface */
+ sk_win_write_4(sc, SK_RAMCTL, SK_RAMCTL_UNRESET);
+
+ /*
+ * Configure interrupt moderation. The moderation timer
+ * defers interrupts specified in the interrupt moderation
+ * timer mask based on the timeout specified in the interrupt
+ * moderation timer init register. Each bit in the timer
+ * register represents 18.825ns, so to specify a timeout in
+ * microseconds, we have to multiply by 54.
+ */
+ sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200));
+ sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF|
+ SK_ISR_RX1_EOF|SK_ISR_RX2_EOF);
+ sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START);
+
+ return;
+}
+
+static int sk_probe_xmac(dev)
+ device_t dev;
+{
+ /*
+ * Not much to do here. We always know there will be
+ * at least one XMAC present, and if there are two,
+ * sk_attach() will create a second device instance
+ * for us.
+ */
+ device_set_desc(dev, "XaQti Corp. XMAC II");
+
+ return(0);
+}
+
+/*
+ * Each XMAC chip is attached as a separate logical IP interface.
+ * Single port cards will have only one logical interface of course.
+ */
+static int sk_attach_xmac(dev)
+ device_t dev;
+{
+ struct sk_softc *sc;
+ struct sk_if_softc *sc_if;
+ struct ifnet *ifp;
+ int i, port;
+
+ if (dev == NULL)
+ return(EINVAL);
+
+ sc_if = device_get_softc(dev);
+ sc = device_get_softc(device_get_parent(dev));
+ SK_LOCK(sc);
+ port = *(int *)device_get_ivars(dev);
+ free(device_get_ivars(dev), M_DEVBUF);
+ device_set_ivars(dev, NULL);
+ sc_if->sk_dev = dev;
+
+ bzero((char *)sc_if, sizeof(struct sk_if_softc));
+
+ sc_if->sk_dev = dev;
+ sc_if->sk_unit = device_get_unit(dev);
+ sc_if->sk_port = port;
+ sc_if->sk_softc = sc;
+ sc->sk_if[port] = sc_if;
+ if (port == SK_PORT_A)
+ sc_if->sk_tx_bmu = SK_BMU_TXS_CSR0;
+ if (port == SK_PORT_B)
+ sc_if->sk_tx_bmu = SK_BMU_TXS_CSR1;
+
+ /*
+ * Get station address for this interface. Note that
+ * dual port cards actually come with three station
+ * addresses: one for each port, plus an extra. The
+ * extra one is used by the SysKonnect driver software
+ * as a 'virtual' station address for when both ports
+ * are operating in failover mode. Currently we don't
+ * use this extra address.
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ sc_if->arpcom.ac_enaddr[i] =
+ sk_win_read_1(sc, SK_MAC0_0 + (port * 8) + i);
+
+ printf("sk%d: Ethernet address: %6D\n",
+ sc_if->sk_unit, sc_if->arpcom.ac_enaddr, ":");
+
+ /*
+ * Set up RAM buffer addresses. The NIC will have a certain
+ * amount of SRAM on it, somewhere between 512K and 2MB. We
+ * need to divide this up a) between the transmitter and
+ * receiver and b) between the two XMACs, if this is a
+ * dual port NIC. Our algotithm is to divide up the memory
+ * evenly so that everyone gets a fair share.
+ */
+ if (sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC) {
+ u_int32_t chunk, val;
+
+ chunk = sc->sk_ramsize / 2;
+ val = sc->sk_rboff / sizeof(u_int64_t);
+ sc_if->sk_rx_ramstart = val;
+ val += (chunk / sizeof(u_int64_t));
+ sc_if->sk_rx_ramend = val - 1;
+ sc_if->sk_tx_ramstart = val;
+ val += (chunk / sizeof(u_int64_t));
+ sc_if->sk_tx_ramend = val - 1;
+ } else {
+ u_int32_t chunk, val;
+
+ chunk = sc->sk_ramsize / 4;
+ val = (sc->sk_rboff + (chunk * 2 * sc_if->sk_port)) /
+ sizeof(u_int64_t);
+ sc_if->sk_rx_ramstart = val;
+ val += (chunk / sizeof(u_int64_t));
+ sc_if->sk_rx_ramend = val - 1;
+ sc_if->sk_tx_ramstart = val;
+ val += (chunk / sizeof(u_int64_t));
+ sc_if->sk_tx_ramend = val - 1;
+ }
+
+ /* Read and save PHY type and set PHY address */
+ sc_if->sk_phytype = sk_win_read_1(sc, SK_EPROM1) & 0xF;
+ switch(sc_if->sk_phytype) {
+ case SK_PHYTYPE_XMAC:
+ sc_if->sk_phyaddr = SK_PHYADDR_XMAC;
+ break;
+ case SK_PHYTYPE_BCOM:
+ sc_if->sk_phyaddr = SK_PHYADDR_BCOM;
+ break;
+ default:
+ printf("skc%d: unsupported PHY type: %d\n",
+ sc->sk_unit, sc_if->sk_phytype);
+ SK_UNLOCK(sc);
+ return(ENODEV);
+ }
+
+ /* Allocate the descriptor queues. */
+ sc_if->sk_rdata = contigmalloc(sizeof(struct sk_ring_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc_if->sk_rdata == NULL) {
+ printf("sk%d: no memory for list buffers!\n", sc_if->sk_unit);
+ sc->sk_if[port] = NULL;
+ SK_UNLOCK(sc);
+ return(ENOMEM);
+ }
+
+ bzero(sc_if->sk_rdata, sizeof(struct sk_ring_data));
+
+ /* Try to allocate memory for jumbo buffers. */
+ if (sk_alloc_jumbo_mem(sc_if)) {
+ printf("sk%d: jumbo buffer allocation failed\n",
+ sc_if->sk_unit);
+ contigfree(sc_if->sk_rdata,
+ sizeof(struct sk_ring_data), M_DEVBUF);
+ sc->sk_if[port] = NULL;
+ SK_UNLOCK(sc);
+ return(ENOMEM);
+ }
+
+ ifp = &sc_if->arpcom.ac_if;
+ ifp->if_softc = sc_if;
+ ifp->if_unit = sc_if->sk_unit;
+ ifp->if_name = "sk";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = sk_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = sk_start;
+ ifp->if_watchdog = sk_watchdog;
+ ifp->if_init = sk_init;
+ ifp->if_baudrate = 1000000000;
+ ifp->if_snd.ifq_maxlen = SK_TX_RING_CNT - 1;
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ callout_handle_init(&sc_if->sk_tick_ch);
+
+ /*
+ * Do miibus setup.
+ */
+ sk_init_xmac(sc_if);
+ if (mii_phy_probe(dev, &sc_if->sk_miibus,
+ sk_ifmedia_upd, sk_ifmedia_sts)) {
+ printf("skc%d: no PHY found!\n", sc_if->sk_unit);
+ contigfree(sc_if->sk_rdata,
+ sizeof(struct sk_ring_data), M_DEVBUF);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+ SK_UNLOCK(sc);
+ return(ENXIO);
+ }
+
+ SK_UNLOCK(sc);
+
+ return(0);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int sk_attach(dev)
+ device_t dev;
+{
+ u_int32_t command;
+ struct sk_softc *sc;
+ int unit, error = 0, rid, *port;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct sk_softc));
+
+ mtx_init(&sc->sk_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ SK_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, SK_PCI_LOIO, 4);
+ membase = pci_read_config(dev, SK_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, SK_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("skc%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, SK_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, SK_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, SK_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef SK_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("skc%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("skc%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = SK_RID;
+ sc->sk_res = bus_alloc_resource(dev, SK_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->sk_res == NULL) {
+ printf("sk%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->sk_btag = rman_get_bustag(sc->sk_res);
+ sc->sk_bhandle = rman_get_bushandle(sc->sk_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->sk_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->sk_irq == NULL) {
+ printf("skc%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, SK_RES, SK_RID, sc->sk_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->sk_irq, INTR_TYPE_NET,
+ sk_intr, sc, &sc->sk_intrhand);
+
+ if (error) {
+ printf("skc%d: couldn't set up irq\n", unit);
+ bus_release_resource(dev, SK_RES, SK_RID, sc->sk_res);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sk_irq);
+ goto fail;
+ }
+
+ /* Reset the adapter. */
+ sk_reset(sc);
+
+ sc->sk_unit = unit;
+
+ /* Read and save vital product data from EEPROM. */
+ sk_vpd_read(sc);
+
+ /* Read and save RAM size and RAMbuffer offset */
+ switch(sk_win_read_1(sc, SK_EPROM0)) {
+ case SK_RAMSIZE_512K_64:
+ sc->sk_ramsize = 0x80000;
+ sc->sk_rboff = SK_RBOFF_0;
+ break;
+ case SK_RAMSIZE_1024K_64:
+ sc->sk_ramsize = 0x100000;
+ sc->sk_rboff = SK_RBOFF_80000;
+ break;
+ case SK_RAMSIZE_1024K_128:
+ sc->sk_ramsize = 0x100000;
+ sc->sk_rboff = SK_RBOFF_0;
+ break;
+ case SK_RAMSIZE_2048K_128:
+ sc->sk_ramsize = 0x200000;
+ sc->sk_rboff = SK_RBOFF_0;
+ break;
+ default:
+ printf("skc%d: unknown ram size: %d\n",
+ sc->sk_unit, sk_win_read_1(sc, SK_EPROM0));
+ bus_teardown_intr(dev, sc->sk_irq, sc->sk_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sk_irq);
+ bus_release_resource(dev, SK_RES, SK_RID, sc->sk_res);
+ error = ENXIO;
+ goto fail;
+ break;
+ }
+
+ /* Read and save physical media type */
+ switch(sk_win_read_1(sc, SK_PMDTYPE)) {
+ case SK_PMD_1000BASESX:
+ sc->sk_pmd = IFM_1000_SX;
+ break;
+ case SK_PMD_1000BASELX:
+ sc->sk_pmd = IFM_1000_LX;
+ break;
+ case SK_PMD_1000BASECX:
+ sc->sk_pmd = IFM_1000_CX;
+ break;
+ case SK_PMD_1000BASETX:
+ sc->sk_pmd = IFM_1000_T;
+ break;
+ default:
+ printf("skc%d: unknown media type: 0x%x\n",
+ sc->sk_unit, sk_win_read_1(sc, SK_PMDTYPE));
+ bus_teardown_intr(dev, sc->sk_irq, sc->sk_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sk_irq);
+ bus_release_resource(dev, SK_RES, SK_RID, sc->sk_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Announce the product name. */
+ printf("skc%d: %s\n", sc->sk_unit, sc->sk_vpd_prodname);
+ sc->sk_devs[SK_PORT_A] = device_add_child(dev, "sk", -1);
+ port = malloc(sizeof(int), M_DEVBUF, M_NOWAIT);
+ *port = SK_PORT_A;
+ device_set_ivars(sc->sk_devs[SK_PORT_A], port);
+
+ if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) {
+ sc->sk_devs[SK_PORT_B] = device_add_child(dev, "sk", -1);
+ port = malloc(sizeof(int), M_DEVBUF, M_NOWAIT);
+ *port = SK_PORT_B;
+ device_set_ivars(sc->sk_devs[SK_PORT_B], port);
+ }
+
+ /* Turn on the 'driver is loaded' LED. */
+ CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON);
+
+ bus_generic_attach(dev);
+ SK_UNLOCK(sc);
+ return(0);
+
+fail:
+ SK_UNLOCK(sc);
+ mtx_destroy(&sc->sk_mtx);
+ return(error);
+}
+
+static int sk_detach_xmac(dev)
+ device_t dev;
+{
+ struct sk_softc *sc;
+ struct sk_if_softc *sc_if;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(device_get_parent(dev));
+ sc_if = device_get_softc(dev);
+ SK_IF_LOCK(sc_if);
+
+ ifp = &sc_if->arpcom.ac_if;
+ sk_stop(sc_if);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+ bus_generic_detach(dev);
+ if (sc_if->sk_miibus != NULL)
+ device_delete_child(dev, sc_if->sk_miibus);
+ contigfree(sc_if->sk_cdata.sk_jumbo_buf, SK_JMEM, M_DEVBUF);
+ contigfree(sc_if->sk_rdata, sizeof(struct sk_ring_data), M_DEVBUF);
+ SK_IF_UNLOCK(sc_if);
+
+ return(0);
+}
+
+static int sk_detach(dev)
+ device_t dev;
+{
+ struct sk_softc *sc;
+
+ sc = device_get_softc(dev);
+ SK_LOCK(sc);
+
+ bus_generic_detach(dev);
+ if (sc->sk_devs[SK_PORT_A] != NULL)
+ device_delete_child(dev, sc->sk_devs[SK_PORT_A]);
+ if (sc->sk_devs[SK_PORT_B] != NULL)
+ device_delete_child(dev, sc->sk_devs[SK_PORT_B]);
+
+ bus_teardown_intr(dev, sc->sk_irq, sc->sk_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sk_irq);
+ bus_release_resource(dev, SK_RES, SK_RID, sc->sk_res);
+
+ SK_UNLOCK(sc);
+ mtx_destroy(&sc->sk_mtx);
+
+ return(0);
+}
+
+static int sk_encap(sc_if, m_head, txidx)
+ struct sk_if_softc *sc_if;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct sk_tx_desc *f = NULL;
+ struct mbuf *m;
+ u_int32_t frag, cur, cnt = 0;
+
+ m = m_head;
+ cur = frag = *txidx;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if ((SK_TX_RING_CNT -
+ (sc_if->sk_cdata.sk_tx_cnt + cnt)) < 2)
+ return(ENOBUFS);
+ f = &sc_if->sk_rdata->sk_tx_ring[frag];
+ f->sk_data_lo = vtophys(mtod(m, vm_offset_t));
+ f->sk_ctl = m->m_len | SK_OPCODE_DEFAULT;
+ if (cnt == 0)
+ f->sk_ctl |= SK_TXCTL_FIRSTFRAG;
+ else
+ f->sk_ctl |= SK_TXCTL_OWN;
+ cur = frag;
+ SK_INC(frag, SK_TX_RING_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |=
+ SK_TXCTL_LASTFRAG|SK_TXCTL_EOF_INTR;
+ sc_if->sk_cdata.sk_tx_chain[cur].sk_mbuf = m_head;
+ sc_if->sk_rdata->sk_tx_ring[*txidx].sk_ctl |= SK_TXCTL_OWN;
+ sc_if->sk_cdata.sk_tx_cnt += cnt;
+
+ *txidx = frag;
+
+ return(0);
+}
+
+static void sk_start(ifp)
+ struct ifnet *ifp;
+{
+ struct sk_softc *sc;
+ struct sk_if_softc *sc_if;
+ struct mbuf *m_head = NULL;
+ u_int32_t idx;
+
+ sc_if = ifp->if_softc;
+ sc = sc_if->sk_softc;
+
+ SK_IF_LOCK(sc_if);
+
+ idx = sc_if->sk_cdata.sk_tx_prod;
+
+ while(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /*
+ * Pack the data into the transmit ring. If we
+ * don't have room, set the OACTIVE flag and wait
+ * for the NIC to drain the ring.
+ */
+ if (sk_encap(sc_if, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+ }
+
+ /* Transmit */
+ sc_if->sk_cdata.sk_tx_prod = idx;
+ CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START);
+
+ /* Set a timeout in case the chip goes out to lunch. */
+ ifp->if_timer = 5;
+ SK_IF_UNLOCK(sc_if);
+
+ return;
+}
+
+
+static void sk_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct sk_if_softc *sc_if;
+
+ sc_if = ifp->if_softc;
+
+ printf("sk%d: watchdog timeout\n", sc_if->sk_unit);
+ sk_init(sc_if);
+
+ return;
+}
+
+static void sk_shutdown(dev)
+ device_t dev;
+{
+ struct sk_softc *sc;
+
+ sc = device_get_softc(dev);
+ SK_LOCK(sc);
+
+ /* Turn off the 'driver is loaded' LED. */
+ CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_OFF);
+
+ /*
+ * Reset the GEnesis controller. Doing this should also
+ * assert the resets on the attached XMAC(s).
+ */
+ sk_reset(sc);
+ SK_UNLOCK(sc);
+
+ return;
+}
+
+static void sk_rxeof(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct sk_chain *cur_rx;
+ int total_len = 0;
+ int i;
+ u_int32_t rxstat;
+
+ ifp = &sc_if->arpcom.ac_if;
+ i = sc_if->sk_cdata.sk_rx_prod;
+ cur_rx = &sc_if->sk_cdata.sk_rx_chain[i];
+
+ while(!(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl & SK_RXCTL_OWN)) {
+
+ cur_rx = &sc_if->sk_cdata.sk_rx_chain[i];
+ rxstat = sc_if->sk_rdata->sk_rx_ring[i].sk_xmac_rxstat;
+ m = cur_rx->sk_mbuf;
+ cur_rx->sk_mbuf = NULL;
+ total_len = SK_RXBYTES(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl);
+ SK_INC(i, SK_RX_RING_CNT);
+
+ if (rxstat & XM_RXSTAT_ERRFRAME) {
+ ifp->if_ierrors++;
+ sk_newbuf(sc_if, cur_rx, m);
+ continue;
+ }
+
+ /*
+ * Try to allocate a new jumbo buffer. If that
+ * fails, copy the packet to mbufs and put the
+ * jumbo buffer back in the ring so it can be
+ * re-used. If allocating mbufs fails, then we
+ * have to drop the packet.
+ */
+ if (sk_newbuf(sc_if, cur_rx, NULL) == ENOBUFS) {
+ struct mbuf *m0;
+ m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
+ ifp, NULL);
+ sk_newbuf(sc_if, cur_rx, m);
+ if (m0 == NULL) {
+ printf("sk%d: no receive buffers "
+ "available -- packet dropped!\n",
+ sc_if->sk_unit);
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+ } else {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc_if->sk_cdata.sk_rx_prod = i;
+
+ return;
+}
+
+static void sk_txeof(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_tx_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ u_int32_t idx;
+
+ ifp = &sc_if->arpcom.ac_if;
+
+ /*
+ * Go through our tx ring and free mbufs for those
+ * frames that have been sent.
+ */
+ idx = sc_if->sk_cdata.sk_tx_cons;
+ while(idx != sc_if->sk_cdata.sk_tx_prod) {
+ cur_tx = &sc_if->sk_rdata->sk_tx_ring[idx];
+ if (cur_tx->sk_ctl & SK_TXCTL_OWN)
+ break;
+ if (cur_tx->sk_ctl & SK_TXCTL_LASTFRAG)
+ ifp->if_opackets++;
+ if (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf != NULL) {
+ m_freem(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf);
+ sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf = NULL;
+ }
+ sc_if->sk_cdata.sk_tx_cnt--;
+ SK_INC(idx, SK_TX_RING_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc_if->sk_cdata.sk_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void sk_tick(xsc_if)
+ void *xsc_if;
+{
+ struct sk_if_softc *sc_if;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ int i;
+
+ sc_if = xsc_if;
+ SK_IF_LOCK(sc_if);
+ ifp = &sc_if->arpcom.ac_if;
+ mii = device_get_softc(sc_if->sk_miibus);
+
+ if (!(ifp->if_flags & IFF_UP)) {
+ SK_IF_UNLOCK(sc_if);
+ return;
+ }
+
+ if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) {
+ sk_intr_bcom(sc_if);
+ SK_IF_UNLOCK(sc_if);
+ return;
+ }
+
+ /*
+ * According to SysKonnect, the correct way to verify that
+ * the link has come back up is to poll bit 0 of the GPIO
+ * register three times. This pin has the signal from the
+ * link_sync pin connected to it; if we read the same link
+ * state 3 times in a row, we know the link is up.
+ */
+ for (i = 0; i < 3; i++) {
+ if (SK_XM_READ_2(sc_if, XM_GPIO) & XM_GPIO_GP0_SET)
+ break;
+ }
+
+ if (i != 3) {
+ sc_if->sk_tick_ch = timeout(sk_tick, sc_if, hz);
+ SK_IF_UNLOCK(sc_if);
+ return;
+ }
+
+ /* Turn the GP0 interrupt back on. */
+ SK_XM_CLRBIT_2(sc_if, XM_IMR, XM_IMR_GP0_SET);
+ SK_XM_READ_2(sc_if, XM_ISR);
+ mii_tick(mii);
+ untimeout(sk_tick, sc_if, sc_if->sk_tick_ch);
+
+ SK_IF_UNLOCK(sc_if);
+ return;
+}
+
+static void sk_intr_bcom(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ int status;
+
+ sc = sc_if->sk_softc;
+ mii = device_get_softc(sc_if->sk_miibus);
+ ifp = &sc_if->arpcom.ac_if;
+
+ SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB);
+
+ /*
+ * Read the PHY interrupt register to make sure
+ * we clear any pending interrupts.
+ */
+ status = sk_miibus_readreg(sc_if->sk_dev,
+ SK_PHYADDR_BCOM, BRGPHY_MII_ISR);
+
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ sk_init_xmac(sc_if);
+ return;
+ }
+
+ if (status & (BRGPHY_ISR_LNK_CHG|BRGPHY_ISR_AN_PR)) {
+ int lstat;
+ lstat = sk_miibus_readreg(sc_if->sk_dev,
+ SK_PHYADDR_BCOM, BRGPHY_MII_AUXSTS);
+
+ if (!(lstat & BRGPHY_AUXSTS_LINK) && sc_if->sk_link) {
+ mii_mediachg(mii);
+ /* Turn off the link LED. */
+ SK_IF_WRITE_1(sc_if, 0,
+ SK_LINKLED1_CTL, SK_LINKLED_OFF);
+ sc_if->sk_link = 0;
+ } else if (status & BRGPHY_ISR_LNK_CHG) {
+ sk_miibus_writereg(sc_if->sk_dev, SK_PHYADDR_BCOM,
+ BRGPHY_MII_IMR, 0xFF00);
+ mii_tick(mii);
+ sc_if->sk_link = 1;
+ /* Turn on the link LED. */
+ SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL,
+ SK_LINKLED_ON|SK_LINKLED_LINKSYNC_OFF|
+ SK_LINKLED_BLINK_OFF);
+ } else {
+ mii_tick(mii);
+ sc_if->sk_tick_ch = timeout(sk_tick, sc_if, hz);
+ }
+ }
+
+ SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB);
+
+ return;
+}
+
+static void sk_intr_xmac(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_softc *sc;
+ u_int16_t status;
+ struct mii_data *mii;
+
+ sc = sc_if->sk_softc;
+ mii = device_get_softc(sc_if->sk_miibus);
+ status = SK_XM_READ_2(sc_if, XM_ISR);
+
+ /*
+ * Link has gone down. Start MII tick timeout to
+ * watch for link resync.
+ */
+ if (sc_if->sk_phytype == SK_PHYTYPE_XMAC) {
+ if (status & XM_ISR_GP0_SET) {
+ SK_XM_SETBIT_2(sc_if, XM_IMR, XM_IMR_GP0_SET);
+ sc_if->sk_tick_ch = timeout(sk_tick, sc_if, hz);
+ }
+
+ if (status & XM_ISR_AUTONEG_DONE) {
+ sc_if->sk_tick_ch = timeout(sk_tick, sc_if, hz);
+ }
+ }
+
+ if (status & XM_IMR_TX_UNDERRUN)
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_TXFIFO);
+
+ if (status & XM_IMR_RX_OVERRUN)
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_RXFIFO);
+
+ status = SK_XM_READ_2(sc_if, XM_ISR);
+
+ return;
+}
+
+static void sk_intr(xsc)
+ void *xsc;
+{
+ struct sk_softc *sc = xsc;
+ struct sk_if_softc *sc_if0 = NULL, *sc_if1 = NULL;
+ struct ifnet *ifp0 = NULL, *ifp1 = NULL;
+ u_int32_t status;
+
+ SK_LOCK(sc);
+
+ sc_if0 = sc->sk_if[SK_PORT_A];
+ sc_if1 = sc->sk_if[SK_PORT_B];
+
+ if (sc_if0 != NULL)
+ ifp0 = &sc_if0->arpcom.ac_if;
+ if (sc_if1 != NULL)
+ ifp1 = &sc_if1->arpcom.ac_if;
+
+ for (;;) {
+ status = CSR_READ_4(sc, SK_ISSR);
+ if (!(status & sc->sk_intrmask))
+ break;
+
+ /* Handle receive interrupts first. */
+ if (status & SK_ISR_RX1_EOF) {
+ sk_rxeof(sc_if0);
+ CSR_WRITE_4(sc, SK_BMU_RX_CSR0,
+ SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START);
+ }
+ if (status & SK_ISR_RX2_EOF) {
+ sk_rxeof(sc_if1);
+ CSR_WRITE_4(sc, SK_BMU_RX_CSR1,
+ SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START);
+ }
+
+ /* Then transmit interrupts. */
+ if (status & SK_ISR_TX1_S_EOF) {
+ sk_txeof(sc_if0);
+ CSR_WRITE_4(sc, SK_BMU_TXS_CSR0,
+ SK_TXBMU_CLR_IRQ_EOF);
+ }
+ if (status & SK_ISR_TX2_S_EOF) {
+ sk_txeof(sc_if1);
+ CSR_WRITE_4(sc, SK_BMU_TXS_CSR1,
+ SK_TXBMU_CLR_IRQ_EOF);
+ }
+
+ /* Then MAC interrupts. */
+ if (status & SK_ISR_MAC1 &&
+ ifp0->if_flags & IFF_RUNNING)
+ sk_intr_xmac(sc_if0);
+
+ if (status & SK_ISR_MAC2 &&
+ ifp1->if_flags & IFF_RUNNING)
+ sk_intr_xmac(sc_if1);
+
+ if (status & SK_ISR_EXTERNAL_REG) {
+ if (ifp0 != NULL)
+ sk_intr_bcom(sc_if0);
+ if (ifp1 != NULL)
+ sk_intr_bcom(sc_if1);
+ }
+ }
+
+ CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
+
+ if (ifp0 != NULL && ifp0->if_snd.ifq_head != NULL)
+ sk_start(ifp0);
+ if (ifp1 != NULL && ifp1->if_snd.ifq_head != NULL)
+ sk_start(ifp1);
+
+ SK_UNLOCK(sc);
+
+ return;
+}
+
+static void sk_init_xmac(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ struct sk_softc *sc;
+ struct ifnet *ifp;
+ struct sk_bcom_hack bhack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 } };
+
+ sc = sc_if->sk_softc;
+ ifp = &sc_if->arpcom.ac_if;
+
+ /* Unreset the XMAC. */
+ SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_UNRESET);
+ DELAY(1000);
+
+ /* Reset the XMAC's internal state. */
+ SK_XM_SETBIT_2(sc_if, XM_GPIO, XM_GPIO_RESETMAC);
+
+ /* Save the XMAC II revision */
+ sc_if->sk_xmac_rev = XM_XMAC_REV(SK_XM_READ_4(sc_if, XM_DEVID));
+
+ /*
+ * Perform additional initialization for external PHYs,
+ * namely for the 1000baseTX cards that use the XMAC's
+ * GMII mode.
+ */
+ if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) {
+ int i = 0;
+ u_int32_t val;
+
+ /* Take PHY out of reset. */
+ val = sk_win_read_4(sc, SK_GPIO);
+ if (sc_if->sk_port == SK_PORT_A)
+ val |= SK_GPIO_DIR0|SK_GPIO_DAT0;
+ else
+ val |= SK_GPIO_DIR2|SK_GPIO_DAT2;
+ sk_win_write_4(sc, SK_GPIO, val);
+
+ /* Enable GMII mode on the XMAC. */
+ SK_XM_SETBIT_2(sc_if, XM_HWCFG, XM_HWCFG_GMIIMODE);
+
+ sk_miibus_writereg(sc_if->sk_dev, SK_PHYADDR_BCOM,
+ BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET);
+ DELAY(10000);
+ sk_miibus_writereg(sc_if->sk_dev, SK_PHYADDR_BCOM,
+ BRGPHY_MII_IMR, 0xFFF0);
+
+ /*
+ * Early versions of the BCM5400 apparently have
+ * a bug that requires them to have their reserved
+ * registers initialized to some magic values. I don't
+ * know what the numbers do, I'm just the messenger.
+ */
+ if (sk_miibus_readreg(sc_if->sk_dev,
+ SK_PHYADDR_BCOM, 0x03) == 0x6041) {
+ while(bhack[i].reg) {
+ sk_miibus_writereg(sc_if->sk_dev,
+ SK_PHYADDR_BCOM, bhack[i].reg,
+ bhack[i].val);
+ i++;
+ }
+ }
+ }
+
+ /* Set station address */
+ SK_XM_WRITE_2(sc_if, XM_PAR0,
+ *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[0]));
+ SK_XM_WRITE_2(sc_if, XM_PAR1,
+ *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[2]));
+ SK_XM_WRITE_2(sc_if, XM_PAR2,
+ *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[4]));
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_STATION);
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC);
+ } else {
+ SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD);
+ } else {
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD);
+ }
+
+ /* We don't need the FCS appended to the packet. */
+ SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_STRIPFCS);
+
+ /* We want short frames padded to 60 bytes. */
+ SK_XM_SETBIT_2(sc_if, XM_TXCMD, XM_TXCMD_AUTOPAD);
+
+ /*
+ * Enable the reception of all error frames. This is is
+ * a necessary evil due to the design of the XMAC. The
+ * XMAC's receive FIFO is only 8K in size, however jumbo
+ * frames can be up to 9000 bytes in length. When bad
+ * frame filtering is enabled, the XMAC's RX FIFO operates
+ * in 'store and forward' mode. For this to work, the
+ * entire frame has to fit into the FIFO, but that means
+ * that jumbo frames larger than 8192 bytes will be
+ * truncated. Disabling all bad frame filtering causes
+ * the RX FIFO to operate in streaming mode, in which
+ * case the XMAC will start transfering frames out of the
+ * RX FIFO as soon as the FIFO threshold is reached.
+ */
+ SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_BADFRAMES|
+ XM_MODE_RX_GIANTS|XM_MODE_RX_RUNTS|XM_MODE_RX_CRCERRS|
+ XM_MODE_RX_INRANGELEN);
+
+ if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN))
+ SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK);
+ else
+ SK_XM_CLRBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK);
+
+ /*
+ * Bump up the transmit threshold. This helps hold off transmit
+ * underruns when we're blasting traffic from both ports at once.
+ */
+ SK_XM_WRITE_2(sc_if, XM_TX_REQTHRESH, SK_XM_TX_FIFOTHRESH);
+
+ /* Set multicast filter */
+ sk_setmulti(sc_if);
+
+ /* Clear and enable interrupts */
+ SK_XM_READ_2(sc_if, XM_ISR);
+ if (sc_if->sk_phytype == SK_PHYTYPE_XMAC)
+ SK_XM_WRITE_2(sc_if, XM_IMR, XM_INTRS);
+ else
+ SK_XM_WRITE_2(sc_if, XM_IMR, 0xFFFF);
+
+ /* Configure MAC arbiter */
+ switch(sc_if->sk_xmac_rev) {
+ case XM_XMAC_REV_B2:
+ sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_B2);
+ sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2);
+ break;
+ case XM_XMAC_REV_C1:
+ sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_C1);
+ sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2);
+ break;
+ default:
+ break;
+ }
+ sk_win_write_2(sc, SK_MACARB_CTL,
+ SK_MACARBCTL_UNRESET|SK_MACARBCTL_FASTOE_OFF);
+
+ sc_if->sk_link = 1;
+
+ return;
+}
+
+/*
+ * Note that to properly initialize any part of the GEnesis chip,
+ * you first have to take it out of reset mode.
+ */
+static void sk_init(xsc)
+ void *xsc;
+{
+ struct sk_if_softc *sc_if = xsc;
+ struct sk_softc *sc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+
+ SK_IF_LOCK(sc_if);
+
+ ifp = &sc_if->arpcom.ac_if;
+ sc = sc_if->sk_softc;
+ mii = device_get_softc(sc_if->sk_miibus);
+
+ /* Cancel pending I/O and free all RX/TX buffers. */
+ sk_stop(sc_if);
+
+ /* Configure LINK_SYNC LED */
+ SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_ON);
+ SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_ON);
+
+ /* Configure RX LED */
+ SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_START);
+
+ /* Configure TX LED */
+ SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_TXLEDCTL_COUNTER_START);
+
+ /* Configure I2C registers */
+
+ /* Configure XMAC(s) */
+ sk_init_xmac(sc_if);
+ mii_mediachg(mii);
+
+ /* Configure MAC FIFOs */
+ SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_UNRESET);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXF1_END, SK_FIFO_END);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_ON);
+
+ SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_UNRESET);
+ SK_IF_WRITE_4(sc_if, 0, SK_TXF1_END, SK_FIFO_END);
+ SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_ON);
+
+ /* Configure transmit arbiter(s) */
+ SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL,
+ SK_TXARCTL_ON|SK_TXARCTL_FSYNC_ON);
+
+ /* Configure RAMbuffers */
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_UNRESET);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_START, sc_if->sk_rx_ramstart);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_WR_PTR, sc_if->sk_rx_ramstart);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_RD_PTR, sc_if->sk_rx_ramstart);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_END, sc_if->sk_rx_ramend);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_ON);
+
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_UNRESET);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_STORENFWD_ON);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_START, sc_if->sk_tx_ramstart);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_WR_PTR, sc_if->sk_tx_ramstart);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_RD_PTR, sc_if->sk_tx_ramstart);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_END, sc_if->sk_tx_ramend);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_ON);
+
+ /* Configure BMUs */
+ SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_ONLINE);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO,
+ vtophys(&sc_if->sk_rdata->sk_rx_ring[0]));
+ SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, 0);
+
+ SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_ONLINE);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_LO,
+ vtophys(&sc_if->sk_rdata->sk_tx_ring[0]));
+ SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_HI, 0);
+
+ /* Init descriptors */
+ if (sk_init_rx_ring(sc_if) == ENOBUFS) {
+ printf("sk%d: initialization failed: no "
+ "memory for rx buffers\n", sc_if->sk_unit);
+ sk_stop(sc_if);
+ SK_IF_UNLOCK(sc_if);
+ return;
+ }
+ sk_init_tx_ring(sc_if);
+
+ /* Configure interrupt handling */
+ CSR_READ_4(sc, SK_ISSR);
+ if (sc_if->sk_port == SK_PORT_A)
+ sc->sk_intrmask |= SK_INTRS1;
+ else
+ sc->sk_intrmask |= SK_INTRS2;
+
+ sc->sk_intrmask |= SK_ISR_EXTERNAL_REG;
+
+ CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
+
+ /* Start BMUs. */
+ SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_RX_START);
+
+ /* Enable XMACs TX and RX state machines */
+ SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_IGNPAUSE);
+ SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ SK_IF_UNLOCK(sc_if);
+
+ return;
+}
+
+static void sk_stop(sc_if)
+ struct sk_if_softc *sc_if;
+{
+ int i;
+ struct sk_softc *sc;
+ struct ifnet *ifp;
+
+ SK_IF_LOCK(sc_if);
+ sc = sc_if->sk_softc;
+ ifp = &sc_if->arpcom.ac_if;
+
+ untimeout(sk_tick, sc_if, sc_if->sk_tick_ch);
+
+ if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) {
+ u_int32_t val;
+
+ /* Put PHY back into reset. */
+ val = sk_win_read_4(sc, SK_GPIO);
+ if (sc_if->sk_port == SK_PORT_A) {
+ val |= SK_GPIO_DIR0;
+ val &= ~SK_GPIO_DAT0;
+ } else {
+ val |= SK_GPIO_DIR2;
+ val &= ~SK_GPIO_DAT2;
+ }
+ sk_win_write_4(sc, SK_GPIO, val);
+ }
+
+ /* Turn off various components of this interface. */
+ SK_XM_SETBIT_2(sc_if, XM_GPIO, XM_GPIO_RESETMAC);
+ SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_RESET);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_RESET);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_OFFLINE);
+ SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_OFFLINE);
+ SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF);
+ SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, SK_TXARCTL_OFF);
+ SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP);
+ SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP);
+ SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_OFF);
+ SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_OFF);
+
+ /* Disable interrupts */
+ if (sc_if->sk_port == SK_PORT_A)
+ sc->sk_intrmask &= ~SK_INTRS1;
+ else
+ sc->sk_intrmask &= ~SK_INTRS2;
+ CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
+
+ SK_XM_READ_2(sc_if, XM_ISR);
+ SK_XM_WRITE_2(sc_if, XM_IMR, 0xFFFF);
+
+ /* Free RX and TX mbufs still in the queues. */
+ for (i = 0; i < SK_RX_RING_CNT; i++) {
+ if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) {
+ m_freem(sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf);
+ sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf = NULL;
+ }
+ }
+
+ for (i = 0; i < SK_TX_RING_CNT; i++) {
+ if (sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf != NULL) {
+ m_freem(sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf);
+ sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf = NULL;
+ }
+ }
+
+ ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
+ SK_IF_UNLOCK(sc_if);
+ return;
+}
diff --git a/sys/pci/if_skreg.h b/sys/pci/if_skreg.h
new file mode 100644
index 0000000..061707c
--- /dev/null
+++ b/sys/pci/if_skreg.h
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * SysKonnect PCI vendor ID
+ */
+#define SK_VENDORID 0x1148
+
+/*
+ * SK-NET gigabit ethernet device ID
+ */
+#define SK_DEVICEID_GE 0x4300
+
+/*
+ * GEnesis registers. The GEnesis chip has a 256-byte I/O window
+ * but internally it has a 16K register space. This 16K space is
+ * divided into 128-byte blocks. The first 128 bytes of the I/O
+ * window represent the first block, which is permanently mapped
+ * at the start of the window. The other 127 blocks can be mapped
+ * to the second 128 bytes of the I/O window by setting the desired
+ * block value in the RAP register in block 0. Not all of the 127
+ * blocks are actually used. Most registers are 32 bits wide, but
+ * there are a few 16-bit and 8-bit ones as well.
+ */
+
+
+/* Start of remappable register window. */
+#define SK_WIN_BASE 0x0080
+
+/* Size of a window */
+#define SK_WIN_LEN 0x80
+
+#define SK_WIN_MASK 0x3F80
+#define SK_REG_MASK 0x7F
+
+/* Compute the window of a given register (for the RAP register) */
+#define SK_WIN(reg) (((reg) & SK_WIN_MASK) / SK_WIN_LEN)
+
+/* Compute the relative offset of a register within the window */
+#define SK_REG(reg) ((reg) & SK_REG_MASK)
+
+#define SK_PORT_A 0
+#define SK_PORT_B 1
+
+/*
+ * Compute offset of port-specific register. Since there are two
+ * ports, there are two of some GEnesis modules (e.g. two sets of
+ * DMA queues, two sets of FIFO control registers, etc...). Normally,
+ * the block for port 0 is at offset 0x0 and the block for port 1 is
+ * at offset 0x80 (i.e. the next page over). However for the transmit
+ * BMUs and RAMbuffers, there are two blocks for each port: one for
+ * the sync transmit queue and one for the async queue (which we don't
+ * use). However instead of ordering them like this:
+ * TX sync 1 / TX sync 2 / TX async 1 / TX async 2
+ * SysKonnect has instead ordered them like this:
+ * TX sync 1 / TX async 1 / TX sync 2 / TX async 2
+ * This means that when referencing the TX BMU and RAMbuffer registers,
+ * we have to double the block offset (0x80 * 2) in order to reach the
+ * second queue. This prevents us from using the same formula
+ * (sk_port * 0x80) to compute the offsets for all of the port-specific
+ * blocks: we need an extra offset for the BMU and RAMbuffer registers.
+ * The simplest thing is to provide an extra argument to these macros:
+ * the 'skip' parameter. The 'skip' value is the number of extra pages
+ * for skip when computing the port0/port1 offsets. For most registers,
+ * the skip value is 0; for the BMU and RAMbuffer registers, it's 1.
+ */
+#define SK_IF_READ_4(sc_if, skip, reg) \
+ sk_win_read_4(sc_if->sk_softc, reg + \
+ ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN))
+#define SK_IF_READ_2(sc_if, skip, reg) \
+ sk_win_read_2(sc_if->sk_softc, reg + \
+ ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN))
+#define SK_IF_READ_1(sc_if, skip, reg) \
+ sk_win_read_1(sc_if->sk_softc, reg + \
+ ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN))
+
+#define SK_IF_WRITE_4(sc_if, skip, reg, val) \
+ sk_win_write_4(sc_if->sk_softc, \
+ reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val)
+#define SK_IF_WRITE_2(sc_if, skip, reg, val) \
+ sk_win_write_2(sc_if->sk_softc, \
+ reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val)
+#define SK_IF_WRITE_1(sc_if, skip, reg, val) \
+ sk_win_write_1(sc_if->sk_softc, \
+ reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val)
+
+/* Block 0 registers, permanently mapped at iobase. */
+#define SK_RAP 0x0000
+#define SK_CSR 0x0004
+#define SK_LED 0x0006
+#define SK_ISR 0x0008 /* interrupt source */
+#define SK_IMR 0x000C /* interrupt mask */
+#define SK_IESR 0x0010 /* interrupt hardware error source */
+#define SK_IEMR 0x0014 /* interrupt hardware error mask */
+#define SK_ISSR 0x0018 /* special interrupt source */
+#define SK_XM_IMR0 0x0020
+#define SK_XM_ISR0 0x0028
+#define SK_XM_PHYADDR0 0x0030
+#define SK_XM_PHYDATA0 0x0034
+#define SK_XM_IMR1 0x0040
+#define SK_XM_ISR1 0x0048
+#define SK_XM_PHYADDR1 0x0050
+#define SK_XM_PHYDATA1 0x0054
+#define SK_BMU_RX_CSR0 0x0060
+#define SK_BMU_RX_CSR1 0x0064
+#define SK_BMU_TXS_CSR0 0x0068
+#define SK_BMU_TXA_CSR0 0x006C
+#define SK_BMU_TXS_CSR1 0x0070
+#define SK_BMU_TXA_CSR1 0x0074
+
+/* SK_CSR register */
+#define SK_CSR_SW_RESET 0x0001
+#define SK_CSR_SW_UNRESET 0x0002
+#define SK_CSR_MASTER_RESET 0x0004
+#define SK_CSR_MASTER_UNRESET 0x0008
+#define SK_CSR_MASTER_STOP 0x0010
+#define SK_CSR_MASTER_DONE 0x0020
+#define SK_CSR_SW_IRQ_CLEAR 0x0040
+#define SK_CSR_SW_IRQ_SET 0x0080
+#define SK_CSR_SLOTSIZE 0x0100 /* 1 == 64 bits, 0 == 32 */
+#define SK_CSR_BUSCLOCK 0x0200 /* 1 == 33/66 Mhz, = 33 */
+
+/* SK_LED register */
+#define SK_LED_GREEN_OFF 0x01
+#define SK_LED_GREEN_ON 0x02
+
+/* SK_ISR register */
+#define SK_ISR_TX2_AS_CHECK 0x00000001
+#define SK_ISR_TX2_AS_EOF 0x00000002
+#define SK_ISR_TX2_AS_EOB 0x00000004
+#define SK_ISR_TX2_S_CHECK 0x00000008
+#define SK_ISR_TX2_S_EOF 0x00000010
+#define SK_ISR_TX2_S_EOB 0x00000020
+#define SK_ISR_TX1_AS_CHECK 0x00000040
+#define SK_ISR_TX1_AS_EOF 0x00000080
+#define SK_ISR_TX1_AS_EOB 0x00000100
+#define SK_ISR_TX1_S_CHECK 0x00000200
+#define SK_ISR_TX1_S_EOF 0x00000400
+#define SK_ISR_TX1_S_EOB 0x00000800
+#define SK_ISR_RX2_CHECK 0x00001000
+#define SK_ISR_RX2_EOF 0x00002000
+#define SK_ISR_RX2_EOB 0x00004000
+#define SK_ISR_RX1_CHECK 0x00008000
+#define SK_ISR_RX1_EOF 0x00010000
+#define SK_ISR_RX1_EOB 0x00020000
+#define SK_ISR_LINK2_OFLOW 0x00040000
+#define SK_ISR_MAC2 0x00080000
+#define SK_ISR_LINK1_OFLOW 0x00100000
+#define SK_ISR_MAC1 0x00200000
+#define SK_ISR_TIMER 0x00400000
+#define SK_ISR_EXTERNAL_REG 0x00800000
+#define SK_ISR_SW 0x01000000
+#define SK_ISR_I2C_RDY 0x02000000
+#define SK_ISR_TX2_TIMEO 0x04000000
+#define SK_ISR_TX1_TIMEO 0x08000000
+#define SK_ISR_RX2_TIMEO 0x10000000
+#define SK_ISR_RX1_TIMEO 0x20000000
+#define SK_ISR_RSVD 0x40000000
+#define SK_ISR_HWERR 0x80000000
+
+/* SK_IMR register */
+#define SK_IMR_TX2_AS_CHECK 0x00000001
+#define SK_IMR_TX2_AS_EOF 0x00000002
+#define SK_IMR_TX2_AS_EOB 0x00000004
+#define SK_IMR_TX2_S_CHECK 0x00000008
+#define SK_IMR_TX2_S_EOF 0x00000010
+#define SK_IMR_TX2_S_EOB 0x00000020
+#define SK_IMR_TX1_AS_CHECK 0x00000040
+#define SK_IMR_TX1_AS_EOF 0x00000080
+#define SK_IMR_TX1_AS_EOB 0x00000100
+#define SK_IMR_TX1_S_CHECK 0x00000200
+#define SK_IMR_TX1_S_EOF 0x00000400
+#define SK_IMR_TX1_S_EOB 0x00000800
+#define SK_IMR_RX2_CHECK 0x00001000
+#define SK_IMR_RX2_EOF 0x00002000
+#define SK_IMR_RX2_EOB 0x00004000
+#define SK_IMR_RX1_CHECK 0x00008000
+#define SK_IMR_RX1_EOF 0x00010000
+#define SK_IMR_RX1_EOB 0x00020000
+#define SK_IMR_LINK2_OFLOW 0x00040000
+#define SK_IMR_MAC2 0x00080000
+#define SK_IMR_LINK1_OFLOW 0x00100000
+#define SK_IMR_MAC1 0x00200000
+#define SK_IMR_TIMER 0x00400000
+#define SK_IMR_EXTERNAL_REG 0x00800000
+#define SK_IMR_SW 0x01000000
+#define SK_IMR_I2C_RDY 0x02000000
+#define SK_IMR_TX2_TIMEO 0x04000000
+#define SK_IMR_TX1_TIMEO 0x08000000
+#define SK_IMR_RX2_TIMEO 0x10000000
+#define SK_IMR_RX1_TIMEO 0x20000000
+#define SK_IMR_RSVD 0x40000000
+#define SK_IMR_HWERR 0x80000000
+
+#define SK_INTRS1 \
+ (SK_IMR_RX1_EOF|SK_IMR_TX1_S_EOF|SK_IMR_MAC1)
+
+#define SK_INTRS2 \
+ (SK_IMR_RX2_EOF|SK_IMR_TX2_S_EOF|SK_IMR_MAC2)
+
+/* SK_IESR register */
+#define SK_IESR_PAR_RX2 0x00000001
+#define SK_IESR_PAR_RX1 0x00000002
+#define SK_IESR_PAR_MAC2 0x00000004
+#define SK_IESR_PAR_MAC1 0x00000008
+#define SK_IESR_PAR_WR_RAM 0x00000010
+#define SK_IESR_PAR_RD_RAM 0x00000020
+#define SK_IESR_NO_TSTAMP_MAC2 0x00000040
+#define SK_IESR_NO_TSTAMO_MAC1 0x00000080
+#define SK_IESR_NO_STS_MAC2 0x00000100
+#define SK_IESR_NO_STS_MAC1 0x00000200
+#define SK_IESR_IRQ_STS 0x00000400
+#define SK_IESR_MASTERERR 0x00000800
+
+/* SK_IEMR register */
+#define SK_IEMR_PAR_RX2 0x00000001
+#define SK_IEMR_PAR_RX1 0x00000002
+#define SK_IEMR_PAR_MAC2 0x00000004
+#define SK_IEMR_PAR_MAC1 0x00000008
+#define SK_IEMR_PAR_WR_RAM 0x00000010
+#define SK_IEMR_PAR_RD_RAM 0x00000020
+#define SK_IEMR_NO_TSTAMP_MAC2 0x00000040
+#define SK_IEMR_NO_TSTAMO_MAC1 0x00000080
+#define SK_IEMR_NO_STS_MAC2 0x00000100
+#define SK_IEMR_NO_STS_MAC1 0x00000200
+#define SK_IEMR_IRQ_STS 0x00000400
+#define SK_IEMR_MASTERERR 0x00000800
+
+/* Block 2 */
+#define SK_MAC0_0 0x0100
+#define SK_MAC0_1 0x0104
+#define SK_MAC1_0 0x0108
+#define SK_MAC1_1 0x010C
+#define SK_MAC2_0 0x0110
+#define SK_MAC2_1 0x0114
+#define SK_CONNTYPE 0x0118
+#define SK_PMDTYPE 0x0119
+#define SK_CONFIG 0x011A
+#define SK_CHIPVER 0x011B
+#define SK_EPROM0 0x011C
+#define SK_EPROM1 0x011D
+#define SK_EPROM2 0x011E
+#define SK_EPROM3 0x011F
+#define SK_EP_ADDR 0x0120
+#define SK_EP_DATA 0x0124
+#define SK_EP_LOADCTL 0x0128
+#define SK_EP_LOADTST 0x0129
+#define SK_TIMERINIT 0x0130
+#define SK_TIMER 0x0134
+#define SK_TIMERCTL 0x0138
+#define SK_TIMERTST 0x0139
+#define SK_IMTIMERINIT 0x0140
+#define SK_IMTIMER 0x0144
+#define SK_IMTIMERCTL 0x0148
+#define SK_IMTIMERTST 0x0149
+#define SK_IMMR 0x014C
+#define SK_IHWEMR 0x0150
+#define SK_TESTCTL1 0x0158
+#define SK_TESTCTL2 0x0159
+#define SK_GPIO 0x015C
+#define SK_I2CHWCTL 0x0160
+#define SK_I2CHWDATA 0x0164
+#define SK_I2CHWIRQ 0x0168
+#define SK_I2CSW 0x016C
+#define SK_BLNKINIT 0x0170
+#define SK_BLNKCOUNT 0x0174
+#define SK_BLNKCTL 0x0178
+#define SK_BLNKSTS 0x0179
+#define SK_BLNKTST 0x017A
+
+#define SK_IMCTL_STOP 0x02
+#define SK_IMCTL_START 0x04
+
+#define SK_IMTIMER_TICKS 54
+#define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS)
+
+/*
+ * The SK_EPROM0 register contains a byte that describes the
+ * amount of SRAM mounted on the NIC. The value also tells if
+ * the chips are 64K or 128K. This affects the RAMbuffer address
+ * offset that we need to use.
+ */
+#define SK_RAMSIZE_512K_64 0x1
+#define SK_RAMSIZE_1024K_128 0x2
+#define SK_RAMSIZE_1024K_64 0x3
+#define SK_RAMSIZE_2048K_128 0x4
+
+#define SK_RBOFF_0 0x0
+#define SK_RBOFF_80000 0x80000
+
+/*
+ * SK_EEPROM1 contains the PHY type, which may be XMAC for
+ * fiber-based cards or BCOM for 1000baseT cards with a Broadcom
+ * PHY.
+ */
+#define SK_PHYTYPE_XMAC 0 /* integeated XMAC II PHY */
+#define SK_PHYTYPE_BCOM 1 /* Broadcom BCM5400 */
+#define SK_PHYTYPE_LONE 2 /* Level One LXT1000 */
+#define SK_PHYTYPE_NAT 3 /* National DP83891 */
+
+/*
+ * PHY addresses.
+ */
+#define SK_PHYADDR_XMAC 0x0
+#define SK_PHYADDR_BCOM 0x1
+#define SK_PHYADDR_LONE 0x3
+#define SK_PHYADDR_NAT 0x0
+
+#define SK_CONFIG_SINGLEMAC 0x01
+#define SK_CONFIG_DIS_DSL_CLK 0x02
+
+#define SK_PMD_1000BASELX 0x4C
+#define SK_PMD_1000BASESX 0x53
+#define SK_PMD_1000BASECX 0x43
+#define SK_PMD_1000BASETX 0x54
+
+/* GPIO bits */
+#define SK_GPIO_DAT0 0x00000001
+#define SK_GPIO_DAT1 0x00000002
+#define SK_GPIO_DAT2 0x00000004
+#define SK_GPIO_DAT3 0x00000008
+#define SK_GPIO_DAT4 0x00000010
+#define SK_GPIO_DAT5 0x00000020
+#define SK_GPIO_DAT6 0x00000040
+#define SK_GPIO_DAT7 0x00000080
+#define SK_GPIO_DAT8 0x00000100
+#define SK_GPIO_DAT9 0x00000200
+#define SK_GPIO_DIR0 0x00010000
+#define SK_GPIO_DIR1 0x00020000
+#define SK_GPIO_DIR2 0x00040000
+#define SK_GPIO_DIR3 0x00080000
+#define SK_GPIO_DIR4 0x00100000
+#define SK_GPIO_DIR5 0x00200000
+#define SK_GPIO_DIR6 0x00400000
+#define SK_GPIO_DIR7 0x00800000
+#define SK_GPIO_DIR8 0x01000000
+#define SK_GPIO_DIR9 0x02000000
+
+/* Block 3 Ram interface and MAC arbiter registers */
+#define SK_RAMADDR 0x0180
+#define SK_RAMDATA0 0x0184
+#define SK_RAMDATA1 0x0188
+#define SK_TO0 0x0190
+#define SK_TO1 0x0191
+#define SK_TO2 0x0192
+#define SK_TO3 0x0193
+#define SK_TO4 0x0194
+#define SK_TO5 0x0195
+#define SK_TO6 0x0196
+#define SK_TO7 0x0197
+#define SK_TO8 0x0198
+#define SK_TO9 0x0199
+#define SK_TO10 0x019A
+#define SK_TO11 0x019B
+#define SK_RITIMEO_TMR 0x019C
+#define SK_RAMCTL 0x01A0
+#define SK_RITIMER_TST 0x01A2
+
+#define SK_RAMCTL_RESET 0x0001
+#define SK_RAMCTL_UNRESET 0x0002
+#define SK_RAMCTL_CLR_IRQ_WPAR 0x0100
+#define SK_RAMCTL_CLR_IRQ_RPAR 0x0200
+
+/* Mac arbiter registers */
+#define SK_MINIT_RX1 0x01B0
+#define SK_MINIT_RX2 0x01B1
+#define SK_MINIT_TX1 0x01B2
+#define SK_MINIT_TX2 0x01B3
+#define SK_MTIMEO_RX1 0x01B4
+#define SK_MTIMEO_RX2 0x01B5
+#define SK_MTIMEO_TX1 0x01B6
+#define SK_MTIEMO_TX2 0x01B7
+#define SK_MACARB_CTL 0x01B8
+#define SK_MTIMER_TST 0x01BA
+#define SK_RCINIT_RX1 0x01C0
+#define SK_RCINIT_RX2 0x01C1
+#define SK_RCINIT_TX1 0x01C2
+#define SK_RCINIT_TX2 0x01C3
+#define SK_RCTIMEO_RX1 0x01C4
+#define SK_RCTIMEO_RX2 0x01C5
+#define SK_RCTIMEO_TX1 0x01C6
+#define SK_RCTIMEO_TX2 0x01C7
+#define SK_RECOVERY_CTL 0x01C8
+#define SK_RCTIMER_TST 0x01CA
+
+/* Packet arbiter registers */
+#define SK_RXPA1_TINIT 0x01D0
+#define SK_RXPA2_TINIT 0x01D4
+#define SK_TXPA1_TINIT 0x01D8
+#define SK_TXPA2_TINIT 0x01DC
+#define SK_RXPA1_TIMEO 0x01E0
+#define SK_RXPA2_TIMEO 0x01E4
+#define SK_TXPA1_TIMEO 0x01E8
+#define SK_TXPA2_TIMEO 0x01EC
+#define SK_PKTARB_CTL 0x01F0
+#define SK_PKTATB_TST 0x01F2
+
+#define SK_PKTARB_TIMEOUT 0x2000
+
+#define SK_PKTARBCTL_RESET 0x0001
+#define SK_PKTARBCTL_UNRESET 0x0002
+#define SK_PKTARBCTL_RXTO1_OFF 0x0004
+#define SK_PKTARBCTL_RXTO1_ON 0x0008
+#define SK_PKTARBCTL_RXTO2_OFF 0x0010
+#define SK_PKTARBCTL_RXTO2_ON 0x0020
+#define SK_PKTARBCTL_TXTO1_OFF 0x0040
+#define SK_PKTARBCTL_TXTO1_ON 0x0080
+#define SK_PKTARBCTL_TXTO2_OFF 0x0100
+#define SK_PKTARBCTL_TXTO2_ON 0x0200
+#define SK_PKTARBCTL_CLR_IRQ_RXTO1 0x0400
+#define SK_PKTARBCTL_CLR_IRQ_RXTO2 0x0800
+#define SK_PKTARBCTL_CLR_IRQ_TXTO1 0x1000
+#define SK_PKTARBCTL_CLR_IRQ_TXTO2 0x2000
+
+#define SK_MINIT_XMAC_B2 54
+#define SK_MINIT_XMAC_C1 63
+
+#define SK_MACARBCTL_RESET 0x0001
+#define SK_MACARBCTL_UNRESET 0x0002
+#define SK_MACARBCTL_FASTOE_OFF 0x0004
+#define SK_MACARBCRL_FASTOE_ON 0x0008
+
+#define SK_RCINIT_XMAC_B2 54
+#define SK_RCINIT_XMAC_C1 0
+
+#define SK_RECOVERYCTL_RX1_OFF 0x0001
+#define SK_RECOVERYCTL_RX1_ON 0x0002
+#define SK_RECOVERYCTL_RX2_OFF 0x0004
+#define SK_RECOVERYCTL_RX2_ON 0x0008
+#define SK_RECOVERYCTL_TX1_OFF 0x0010
+#define SK_RECOVERYCTL_TX1_ON 0x0020
+#define SK_RECOVERYCTL_TX2_OFF 0x0040
+#define SK_RECOVERYCTL_TX2_ON 0x0080
+
+#define SK_RECOVERY_XMAC_B2 \
+ (SK_RECOVERYCTL_RX1_ON|SK_RECOVERYCTL_RX2_ON| \
+ SK_RECOVERYCTL_TX1_ON|SK_RECOVERYCTL_TX2_ON)
+
+#define SK_RECOVERY_XMAC_C1 \
+ (SK_RECOVERYCTL_RX1_OFF|SK_RECOVERYCTL_RX2_OFF| \
+ SK_RECOVERYCTL_TX1_OFF|SK_RECOVERYCTL_TX2_OFF)
+
+/* Block 4 -- TX Arbiter MAC 1 */
+#define SK_TXAR1_TIMERINIT 0x0200
+#define SK_TXAR1_TIMERVAL 0x0204
+#define SK_TXAR1_LIMITINIT 0x0208
+#define SK_TXAR1_LIMITCNT 0x020C
+#define SK_TXAR1_COUNTERCTL 0x0210
+#define SK_TXAR1_COUNTERTST 0x0212
+#define SK_TXAR1_COUNTERSTS 0x0212
+
+/* Block 5 -- TX Arbiter MAC 2 */
+#define SK_TXAR2_TIMERINIT 0x0280
+#define SK_TXAR2_TIMERVAL 0x0284
+#define SK_TXAR2_LIMITINIT 0x0288
+#define SK_TXAR2_LIMITCNT 0x028C
+#define SK_TXAR2_COUNTERCTL 0x0290
+#define SK_TXAR2_COUNTERTST 0x0291
+#define SK_TXAR2_COUNTERSTS 0x0292
+
+#define SK_TXARCTL_OFF 0x01
+#define SK_TXARCTL_ON 0x02
+#define SK_TXARCTL_RATECTL_OFF 0x04
+#define SK_TXARCTL_RATECTL_ON 0x08
+#define SK_TXARCTL_ALLOC_OFF 0x10
+#define SK_TXARCTL_ALLOC_ON 0x20
+#define SK_TXARCTL_FSYNC_OFF 0x40
+#define SK_TXARCTL_FSYNC_ON 0x80
+
+/* Block 6 -- External registers */
+#define SK_EXTREG_BASE 0x300
+#define SK_EXTREG_END 0x37C
+
+/* Block 7 -- PCI config registers */
+#define SK_PCI_BASE 0x0380
+#define SK_PCI_END 0x03FC
+
+/* Compute offset of mirrored PCI register */
+#define SK_PCI_REG(reg) ((reg) + SK_PCI_BASE)
+
+/* Block 8 -- RX queue 1 */
+#define SK_RXQ1_BUFCNT 0x0400
+#define SK_RXQ1_BUFCTL 0x0402
+#define SK_RXQ1_NEXTDESC 0x0404
+#define SK_RXQ1_RXBUF_LO 0x0408
+#define SK_RXQ1_RXBUF_HI 0x040C
+#define SK_RXQ1_RXSTAT 0x0410
+#define SK_RXQ1_TIMESTAMP 0x0414
+#define SK_RXQ1_CSUM1 0x0418
+#define SK_RXQ1_CSUM2 0x041A
+#define SK_RXQ1_CSUM1_START 0x041C
+#define SK_RXQ1_CSUM2_START 0x041E
+#define SK_RXQ1_CURADDR_LO 0x0420
+#define SK_RXQ1_CURADDR_HI 0x0424
+#define SK_RXQ1_CURCNT_LO 0x0428
+#define SK_RXQ1_CURCNT_HI 0x042C
+#define SK_RXQ1_CURBYTES 0x0430
+#define SK_RXQ1_BMU_CSR 0x0434
+#define SK_RXQ1_WATERMARK 0x0438
+#define SK_RXQ1_FLAG 0x043A
+#define SK_RXQ1_TEST1 0x043C
+#define SK_RXQ1_TEST2 0x0440
+#define SK_RXQ1_TEST3 0x0444
+
+/* Block 9 -- RX queue 2 */
+#define SK_RXQ2_BUFCNT 0x0480
+#define SK_RXQ2_BUFCTL 0x0482
+#define SK_RXQ2_NEXTDESC 0x0484
+#define SK_RXQ2_RXBUF_LO 0x0488
+#define SK_RXQ2_RXBUF_HI 0x048C
+#define SK_RXQ2_RXSTAT 0x0490
+#define SK_RXQ2_TIMESTAMP 0x0494
+#define SK_RXQ2_CSUM1 0x0498
+#define SK_RXQ2_CSUM2 0x049A
+#define SK_RXQ2_CSUM1_START 0x049C
+#define SK_RXQ2_CSUM2_START 0x049E
+#define SK_RXQ2_CURADDR_LO 0x04A0
+#define SK_RXQ2_CURADDR_HI 0x04A4
+#define SK_RXQ2_CURCNT_LO 0x04A8
+#define SK_RXQ2_CURCNT_HI 0x04AC
+#define SK_RXQ2_CURBYTES 0x04B0
+#define SK_RXQ2_BMU_CSR 0x04B4
+#define SK_RXQ2_WATERMARK 0x04B8
+#define SK_RXQ2_FLAG 0x04BA
+#define SK_RXQ2_TEST1 0x04BC
+#define SK_RXQ2_TEST2 0x04C0
+#define SK_RXQ2_TEST3 0x04C4
+
+#define SK_RXBMU_CLR_IRQ_ERR 0x00000001
+#define SK_RXBMU_CLR_IRQ_EOF 0x00000002
+#define SK_RXBMU_CLR_IRQ_EOB 0x00000004
+#define SK_RXBMU_CLR_IRQ_PAR 0x00000008
+#define SK_RXBMU_RX_START 0x00000010
+#define SK_RXBMU_RX_STOP 0x00000020
+#define SK_RXBMU_POLL_OFF 0x00000040
+#define SK_RXBMU_POLL_ON 0x00000080
+#define SK_RXBMU_TRANSFER_SM_RESET 0x00000100
+#define SK_RXBMU_TRANSFER_SM_UNRESET 0x00000200
+#define SK_RXBMU_DESCWR_SM_RESET 0x00000400
+#define SK_RXBMU_DESCWR_SM_UNRESET 0x00000800
+#define SK_RXBMU_DESCRD_SM_RESET 0x00001000
+#define SK_RXBMU_DESCRD_SM_UNRESET 0x00002000
+#define SK_RXBMU_SUPERVISOR_SM_RESET 0x00004000
+#define SK_RXBMU_SUPERVISOR_SM_UNRESET 0x00008000
+#define SK_RXBMU_PFI_SM_RESET 0x00010000
+#define SK_RXBMU_PFI_SM_UNRESET 0x00020000
+#define SK_RXBMU_FIFO_RESET 0x00040000
+#define SK_RXBMU_FIFO_UNRESET 0x00080000
+#define SK_RXBMU_DESC_RESET 0x00100000
+#define SK_RXBMU_DESC_UNRESET 0x00200000
+#define SK_RXBMU_SUPERVISOR_IDLE 0x01000000
+
+#define SK_RXBMU_ONLINE \
+ (SK_RXBMU_TRANSFER_SM_UNRESET|SK_RXBMU_DESCWR_SM_UNRESET| \
+ SK_RXBMU_DESCRD_SM_UNRESET|SK_RXBMU_SUPERVISOR_SM_UNRESET| \
+ SK_RXBMU_PFI_SM_UNRESET|SK_RXBMU_FIFO_UNRESET| \
+ SK_RXBMU_DESC_UNRESET)
+
+#define SK_RXBMU_OFFLINE \
+ (SK_RXBMU_TRANSFER_SM_RESET|SK_RXBMU_DESCWR_SM_RESET| \
+ SK_RXBMU_DESCRD_SM_RESET|SK_RXBMU_SUPERVISOR_SM_RESET| \
+ SK_RXBMU_PFI_SM_RESET|SK_RXBMU_FIFO_RESET| \
+ SK_RXBMU_DESC_RESET)
+
+/* Block 12 -- TX sync queue 1 */
+#define SK_TXQS1_BUFCNT 0x0600
+#define SK_TXQS1_BUFCTL 0x0602
+#define SK_TXQS1_NEXTDESC 0x0604
+#define SK_TXQS1_RXBUF_LO 0x0608
+#define SK_TXQS1_RXBUF_HI 0x060C
+#define SK_TXQS1_RXSTAT 0x0610
+#define SK_TXQS1_CSUM_STARTVAL 0x0614
+#define SK_TXQS1_CSUM_STARTPOS 0x0618
+#define SK_TXQS1_CSUM_WRITEPOS 0x061A
+#define SK_TXQS1_CURADDR_LO 0x0620
+#define SK_TXQS1_CURADDR_HI 0x0624
+#define SK_TXQS1_CURCNT_LO 0x0628
+#define SK_TXQS1_CURCNT_HI 0x062C
+#define SK_TXQS1_CURBYTES 0x0630
+#define SK_TXQS1_BMU_CSR 0x0634
+#define SK_TXQS1_WATERMARK 0x0638
+#define SK_TXQS1_FLAG 0x063A
+#define SK_TXQS1_TEST1 0x063C
+#define SK_TXQS1_TEST2 0x0640
+#define SK_TXQS1_TEST3 0x0644
+
+/* Block 13 -- TX async queue 1 */
+#define SK_TXQA1_BUFCNT 0x0680
+#define SK_TXQA1_BUFCTL 0x0682
+#define SK_TXQA1_NEXTDESC 0x0684
+#define SK_TXQA1_RXBUF_LO 0x0688
+#define SK_TXQA1_RXBUF_HI 0x068C
+#define SK_TXQA1_RXSTAT 0x0690
+#define SK_TXQA1_CSUM_STARTVAL 0x0694
+#define SK_TXQA1_CSUM_STARTPOS 0x0698
+#define SK_TXQA1_CSUM_WRITEPOS 0x069A
+#define SK_TXQA1_CURADDR_LO 0x06A0
+#define SK_TXQA1_CURADDR_HI 0x06A4
+#define SK_TXQA1_CURCNT_LO 0x06A8
+#define SK_TXQA1_CURCNT_HI 0x06AC
+#define SK_TXQA1_CURBYTES 0x06B0
+#define SK_TXQA1_BMU_CSR 0x06B4
+#define SK_TXQA1_WATERMARK 0x06B8
+#define SK_TXQA1_FLAG 0x06BA
+#define SK_TXQA1_TEST1 0x06BC
+#define SK_TXQA1_TEST2 0x06C0
+#define SK_TXQA1_TEST3 0x06C4
+
+/* Block 14 -- TX sync queue 2 */
+#define SK_TXQS2_BUFCNT 0x0700
+#define SK_TXQS2_BUFCTL 0x0702
+#define SK_TXQS2_NEXTDESC 0x0704
+#define SK_TXQS2_RXBUF_LO 0x0708
+#define SK_TXQS2_RXBUF_HI 0x070C
+#define SK_TXQS2_RXSTAT 0x0710
+#define SK_TXQS2_CSUM_STARTVAL 0x0714
+#define SK_TXQS2_CSUM_STARTPOS 0x0718
+#define SK_TXQS2_CSUM_WRITEPOS 0x071A
+#define SK_TXQS2_CURADDR_LO 0x0720
+#define SK_TXQS2_CURADDR_HI 0x0724
+#define SK_TXQS2_CURCNT_LO 0x0728
+#define SK_TXQS2_CURCNT_HI 0x072C
+#define SK_TXQS2_CURBYTES 0x0730
+#define SK_TXQS2_BMU_CSR 0x0734
+#define SK_TXQS2_WATERMARK 0x0738
+#define SK_TXQS2_FLAG 0x073A
+#define SK_TXQS2_TEST1 0x073C
+#define SK_TXQS2_TEST2 0x0740
+#define SK_TXQS2_TEST3 0x0744
+
+/* Block 15 -- TX async queue 2 */
+#define SK_TXQA2_BUFCNT 0x0780
+#define SK_TXQA2_BUFCTL 0x0782
+#define SK_TXQA2_NEXTDESC 0x0784
+#define SK_TXQA2_RXBUF_LO 0x0788
+#define SK_TXQA2_RXBUF_HI 0x078C
+#define SK_TXQA2_RXSTAT 0x0790
+#define SK_TXQA2_CSUM_STARTVAL 0x0794
+#define SK_TXQA2_CSUM_STARTPOS 0x0798
+#define SK_TXQA2_CSUM_WRITEPOS 0x079A
+#define SK_TXQA2_CURADDR_LO 0x07A0
+#define SK_TXQA2_CURADDR_HI 0x07A4
+#define SK_TXQA2_CURCNT_LO 0x07A8
+#define SK_TXQA2_CURCNT_HI 0x07AC
+#define SK_TXQA2_CURBYTES 0x07B0
+#define SK_TXQA2_BMU_CSR 0x07B4
+#define SK_TXQA2_WATERMARK 0x07B8
+#define SK_TXQA2_FLAG 0x07BA
+#define SK_TXQA2_TEST1 0x07BC
+#define SK_TXQA2_TEST2 0x07C0
+#define SK_TXQA2_TEST3 0x07C4
+
+#define SK_TXBMU_CLR_IRQ_ERR 0x00000001
+#define SK_TXBMU_CLR_IRQ_EOF 0x00000002
+#define SK_TXBMU_CLR_IRQ_EOB 0x00000004
+#define SK_TXBMU_TX_START 0x00000010
+#define SK_TXBMU_TX_STOP 0x00000020
+#define SK_TXBMU_POLL_OFF 0x00000040
+#define SK_TXBMU_POLL_ON 0x00000080
+#define SK_TXBMU_TRANSFER_SM_RESET 0x00000100
+#define SK_TXBMU_TRANSFER_SM_UNRESET 0x00000200
+#define SK_TXBMU_DESCWR_SM_RESET 0x00000400
+#define SK_TXBMU_DESCWR_SM_UNRESET 0x00000800
+#define SK_TXBMU_DESCRD_SM_RESET 0x00001000
+#define SK_TXBMU_DESCRD_SM_UNRESET 0x00002000
+#define SK_TXBMU_SUPERVISOR_SM_RESET 0x00004000
+#define SK_TXBMU_SUPERVISOR_SM_UNRESET 0x00008000
+#define SK_TXBMU_PFI_SM_RESET 0x00010000
+#define SK_TXBMU_PFI_SM_UNRESET 0x00020000
+#define SK_TXBMU_FIFO_RESET 0x00040000
+#define SK_TXBMU_FIFO_UNRESET 0x00080000
+#define SK_TXBMU_DESC_RESET 0x00100000
+#define SK_TXBMU_DESC_UNRESET 0x00200000
+#define SK_TXBMU_SUPERVISOR_IDLE 0x01000000
+
+#define SK_TXBMU_ONLINE \
+ (SK_TXBMU_TRANSFER_SM_UNRESET|SK_TXBMU_DESCWR_SM_UNRESET| \
+ SK_TXBMU_DESCRD_SM_UNRESET|SK_TXBMU_SUPERVISOR_SM_UNRESET| \
+ SK_TXBMU_PFI_SM_UNRESET|SK_TXBMU_FIFO_UNRESET| \
+ SK_TXBMU_DESC_UNRESET)
+
+#define SK_TXBMU_OFFLINE \
+ (SK_TXBMU_TRANSFER_SM_RESET|SK_TXBMU_DESCWR_SM_RESET| \
+ SK_TXBMU_DESCRD_SM_RESET|SK_TXBMU_SUPERVISOR_SM_RESET| \
+ SK_TXBMU_PFI_SM_RESET|SK_TXBMU_FIFO_RESET| \
+ SK_TXBMU_DESC_RESET)
+
+/* Block 16 -- Receive RAMbuffer 1 */
+#define SK_RXRB1_START 0x0800
+#define SK_RXRB1_END 0x0804
+#define SK_RXRB1_WR_PTR 0x0808
+#define SK_RXRB1_RD_PTR 0x080C
+#define SK_RXRB1_UTHR_PAUSE 0x0810
+#define SK_RXRB1_LTHR_PAUSE 0x0814
+#define SK_RXRB1_UTHR_HIPRIO 0x0818
+#define SK_RXRB1_UTHR_LOPRIO 0x081C
+#define SK_RXRB1_PKTCNT 0x0820
+#define SK_RXRB1_LVL 0x0824
+#define SK_RXRB1_CTLTST 0x0828
+
+/* Block 17 -- Receive RAMbuffer 2 */
+#define SK_RXRB2_START 0x0880
+#define SK_RXRB2_END 0x0884
+#define SK_RXRB2_WR_PTR 0x0888
+#define SK_RXRB2_RD_PTR 0x088C
+#define SK_RXRB2_UTHR_PAUSE 0x0890
+#define SK_RXRB2_LTHR_PAUSE 0x0894
+#define SK_RXRB2_UTHR_HIPRIO 0x0898
+#define SK_RXRB2_UTHR_LOPRIO 0x089C
+#define SK_RXRB2_PKTCNT 0x08A0
+#define SK_RXRB2_LVL 0x08A4
+#define SK_RXRB2_CTLTST 0x08A8
+
+/* Block 20 -- Sync. Transmit RAMbuffer 1 */
+#define SK_TXRBS1_START 0x0A00
+#define SK_TXRBS1_END 0x0A04
+#define SK_TXRBS1_WR_PTR 0x0A08
+#define SK_TXRBS1_RD_PTR 0x0A0C
+#define SK_TXRBS1_PKTCNT 0x0A20
+#define SK_TXRBS1_LVL 0x0A24
+#define SK_TXRBS1_CTLTST 0x0A28
+
+/* Block 21 -- Async. Transmit RAMbuffer 1 */
+#define SK_TXRBA1_START 0x0A80
+#define SK_TXRBA1_END 0x0A84
+#define SK_TXRBA1_WR_PTR 0x0A88
+#define SK_TXRBA1_RD_PTR 0x0A8C
+#define SK_TXRBA1_PKTCNT 0x0AA0
+#define SK_TXRBA1_LVL 0x0AA4
+#define SK_TXRBA1_CTLTST 0x0AA8
+
+/* Block 22 -- Sync. Transmit RAMbuffer 2 */
+#define SK_TXRBS2_START 0x0B00
+#define SK_TXRBS2_END 0x0B04
+#define SK_TXRBS2_WR_PTR 0x0B08
+#define SK_TXRBS2_RD_PTR 0x0B0C
+#define SK_TXRBS2_PKTCNT 0x0B20
+#define SK_TXRBS2_LVL 0x0B24
+#define SK_TXRBS2_CTLTST 0x0B28
+
+/* Block 23 -- Async. Transmit RAMbuffer 2 */
+#define SK_TXRBA2_START 0x0B80
+#define SK_TXRBA2_END 0x0B84
+#define SK_TXRBA2_WR_PTR 0x0B88
+#define SK_TXRBA2_RD_PTR 0x0B8C
+#define SK_TXRBA2_PKTCNT 0x0BA0
+#define SK_TXRBA2_LVL 0x0BA4
+#define SK_TXRBA2_CTLTST 0x0BA8
+
+#define SK_RBCTL_RESET 0x00000001
+#define SK_RBCTL_UNRESET 0x00000002
+#define SK_RBCTL_OFF 0x00000004
+#define SK_RBCTL_ON 0x00000008
+#define SK_RBCTL_STORENFWD_OFF 0x00000010
+#define SK_RBCTL_STORENFWD_ON 0x00000020
+
+/* Block 24 -- RX MAC FIFO 1 regisrers and LINK_SYNC counter */
+#define SK_RXF1_END 0x0C00
+#define SK_RXF1_WPTR 0x0C04
+#define SK_RXF1_RPTR 0x0C0C
+#define SK_RXF1_PKTCNT 0x0C10
+#define SK_RXF1_LVL 0x0C14
+#define SK_RXF1_MACCTL 0x0C18
+#define SK_RXF1_CTL 0x0C1C
+#define SK_RXLED1_CNTINIT 0x0C20
+#define SK_RXLED1_COUNTER 0x0C24
+#define SK_RXLED1_CTL 0x0C28
+#define SK_RXLED1_TST 0x0C29
+#define SK_LINK_SYNC1_CINIT 0x0C30
+#define SK_LINK_SYNC1_COUNTER 0x0C34
+#define SK_LINK_SYNC1_CTL 0x0C38
+#define SK_LINK_SYNC1_TST 0x0C39
+#define SK_LINKLED1_CTL 0x0C3C
+
+#define SK_FIFO_END 0x3F
+
+/* Block 25 -- RX MAC FIFO 2 regisrers and LINK_SYNC counter */
+#define SK_RXF2_END 0x0C80
+#define SK_RXF2_WPTR 0x0C84
+#define SK_RXF2_RPTR 0x0C8C
+#define SK_RXF2_PKTCNT 0x0C90
+#define SK_RXF2_LVL 0x0C94
+#define SK_RXF2_MACCTL 0x0C98
+#define SK_RXF2_CTL 0x0C9C
+#define SK_RXLED2_CNTINIT 0x0CA0
+#define SK_RXLED2_COUNTER 0x0CA4
+#define SK_RXLED2_CTL 0x0CA8
+#define SK_RXLED2_TST 0x0CA9
+#define SK_LINK_SYNC2_CINIT 0x0CB0
+#define SK_LINK_SYNC2_COUNTER 0x0CB4
+#define SK_LINK_SYNC2_CTL 0x0CB8
+#define SK_LINK_SYNC2_TST 0x0CB9
+#define SK_LINKLED2_CTL 0x0CBC
+
+#define SK_RXMACCTL_CLR_IRQ_NOSTS 0x00000001
+#define SK_RXMACCTL_CLR_IRQ_NOTSTAMP 0x00000002
+#define SK_RXMACCTL_TSTAMP_OFF 0x00000004
+#define SK_RXMACCTL_RSTAMP_ON 0x00000008
+#define SK_RXMACCTL_FLUSH_OFF 0x00000010
+#define SK_RXMACCTL_FLUSH_ON 0x00000020
+#define SK_RXMACCTL_PAUSE_OFF 0x00000040
+#define SK_RXMACCTL_PAUSE_ON 0x00000080
+#define SK_RXMACCTL_AFULL_OFF 0x00000100
+#define SK_RXMACCTL_AFULL_ON 0x00000200
+#define SK_RXMACCTL_VALIDTIME_PATCH_OFF 0x00000400
+#define SK_RXMACCTL_VALIDTIME_PATCH_ON 0x00000800
+#define SK_RXMACCTL_RXRDY_PATCH_OFF 0x00001000
+#define SK_RXMACCTL_RXRDY_PATCH_ON 0x00002000
+#define SK_RXMACCTL_STS_TIMEO 0x00FF0000
+#define SK_RXMACCTL_TSTAMP_TIMEO 0xFF000000
+
+#define SK_RXLEDCTL_ENABLE 0x0001
+#define SK_RXLEDCTL_COUNTER_STOP 0x0002
+#define SK_RXLEDCTL_COUNTER_START 0x0004
+
+#define SK_LINKLED_OFF 0x0001
+#define SK_LINKLED_ON 0x0002
+#define SK_LINKLED_LINKSYNC_OFF 0x0004
+#define SK_LINKLED_LINKSYNC_ON 0x0008
+#define SK_LINKLED_BLINK_OFF 0x0010
+#define SK_LINKLED_BLINK_ON 0x0020
+
+/* Block 26 -- TX MAC FIFO 1 regisrers */
+#define SK_TXF1_END 0x0D00
+#define SK_TXF1_WPTR 0x0D04
+#define SK_TXF1_RPTR 0x0D0C
+#define SK_TXF1_PKTCNT 0x0D10
+#define SK_TXF1_LVL 0x0D14
+#define SK_TXF1_MACCTL 0x0D18
+#define SK_TXF1_CTL 0x0D1C
+#define SK_TXLED1_CNTINIT 0x0D20
+#define SK_TXLED1_COUNTER 0x0D24
+#define SK_TXLED1_CTL 0x0D28
+#define SK_TXLED1_TST 0x0D29
+
+/* Block 27 -- TX MAC FIFO 2 regisrers */
+#define SK_TXF2_END 0x0D80
+#define SK_TXF2_WPTR 0x0D84
+#define SK_TXF2_RPTR 0x0D8C
+#define SK_TXF2_PKTCNT 0x0D90
+#define SK_TXF2_LVL 0x0D94
+#define SK_TXF2_MACCTL 0x0D98
+#define SK_TXF2_CTL 0x0D9C
+#define SK_TXLED2_CNTINIT 0x0DA0
+#define SK_TXLED2_COUNTER 0x0DA4
+#define SK_TXLED2_CTL 0x0DA8
+#define SK_TXLED2_TST 0x0DA9
+
+#define SK_TXMACCTL_XMAC_RESET 0x00000001
+#define SK_TXMACCTL_XMAC_UNRESET 0x00000002
+#define SK_TXMACCTL_LOOP_OFF 0x00000004
+#define SK_TXMACCTL_LOOP_ON 0x00000008
+#define SK_TXMACCTL_FLUSH_OFF 0x00000010
+#define SK_TXMACCTL_FLUSH_ON 0x00000020
+#define SK_TXMACCTL_WAITEMPTY_OFF 0x00000040
+#define SK_TXMACCTL_WAITEMPTY_ON 0x00000080
+#define SK_TXMACCTL_AFULL_OFF 0x00000100
+#define SK_TXMACCTL_AFULL_ON 0x00000200
+#define SK_TXMACCTL_TXRDY_PATCH_OFF 0x00000400
+#define SK_TXMACCTL_RXRDY_PATCH_ON 0x00000800
+#define SK_TXMACCTL_PKT_RECOVERY_OFF 0x00001000
+#define SK_TXMACCTL_PKT_RECOVERY_ON 0x00002000
+#define SK_TXMACCTL_CLR_IRQ_PERR 0x00008000
+#define SK_TXMACCTL_WAITAFTERFLUSH 0x00010000
+
+#define SK_TXLEDCTL_ENABLE 0x0001
+#define SK_TXLEDCTL_COUNTER_STOP 0x0002
+#define SK_TXLEDCTL_COUNTER_START 0x0004
+
+#define SK_FIFO_RESET 0x00000001
+#define SK_FIFO_UNRESET 0x00000002
+#define SK_FIFO_OFF 0x00000004
+#define SK_FIFO_ON 0x00000008
+
+/* Block 0x40 to 0x4F -- XMAC 1 registers */
+#define SK_XMAC1_BASE 0x2000
+#define SK_XMAC1_END 0x23FF
+
+/* Block 0x60 to 0x6F -- XMAC 2 registers */
+#define SK_XMAC2_BASE 0x3000
+#define SK_XMAC2_END 0x33FF
+
+/* Compute relative offset of an XMAC register in the XMAC window(s). */
+#define SK_XMAC_REG(reg, mac) (((reg) * 2) + SK_XMAC1_BASE + \
+ (mac * (SK_XMAC2_BASE - SK_XMAC1_BASE)))
+
+#define SK_XM_READ_4(sc, reg) \
+ (sk_win_read_2(sc->sk_softc, \
+ SK_XMAC_REG(reg, sc->sk_port)) & 0xFFFF) | \
+ ((sk_win_read_2(sc->sk_softc, \
+ SK_XMAC_REG(reg + 2, sc->sk_port)) << 16) & 0xFFFF0000)
+
+#define SK_XM_WRITE_4(sc, reg, val) \
+ sk_win_write_2(sc->sk_softc, \
+ SK_XMAC_REG(reg, sc->sk_port), ((val) & 0xFFFF)); \
+ sk_win_write_2(sc->sk_softc, \
+ SK_XMAC_REG(reg + 2, sc->sk_port), ((val) >> 16) & 0xFFFF);
+
+#define SK_XM_READ_2(sc, reg) \
+ sk_win_read_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port))
+
+#define SK_XM_WRITE_2(sc, reg, val) \
+ sk_win_write_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port), val)
+
+#define SK_XM_SETBIT_4(sc, reg, x) \
+ SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) | (x))
+
+#define SK_XM_CLRBIT_4(sc, reg, x) \
+ SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) & ~(x))
+
+#define SK_XM_SETBIT_2(sc, reg, x) \
+ SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) | (x))
+
+#define SK_XM_CLRBIT_2(sc, reg, x) \
+ SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) & ~(x))
+
+
+/*
+ * The default FIFO threshold on the XMAC II is 4 bytes. On
+ * dual port NICs, this often leads to transmit underruns, so we
+ * bump the threshold a little.
+ */
+#define SK_XM_TX_FIFOTHRESH 512
+
+#define SK_PCI_VENDOR_ID 0x0000
+#define SK_PCI_DEVICE_ID 0x0002
+#define SK_PCI_COMMAND 0x0004
+#define SK_PCI_STATUS 0x0006
+#define SK_PCI_REVID 0x0008
+#define SK_PCI_CLASSCODE 0x0009
+#define SK_PCI_CACHELEN 0x000C
+#define SK_PCI_LATENCY_TIMER 0x000D
+#define SK_PCI_HEADER_TYPE 0x000E
+#define SK_PCI_LOMEM 0x0010
+#define SK_PCI_LOIO 0x0014
+#define SK_PCI_SUBVEN_ID 0x002C
+#define SK_PCI_SYBSYS_ID 0x002E
+#define SK_PCI_BIOSROM 0x0030
+#define SK_PCI_INTLINE 0x003C
+#define SK_PCI_INTPIN 0x003D
+#define SK_PCI_MINGNT 0x003E
+#define SK_PCI_MINLAT 0x003F
+
+/* device specific PCI registers */
+#define SK_PCI_OURREG1 0x0040
+#define SK_PCI_OURREG2 0x0044
+#define SK_PCI_CAPID 0x0048 /* 8 bits */
+#define SK_PCI_NEXTPTR 0x0049 /* 8 bits */
+#define SK_PCI_PWRMGMTCAP 0x004A /* 16 bits */
+#define SK_PCI_PWRMGMTCTRL 0x004C /* 16 bits */
+#define SK_PCI_PME_EVENT 0x004F
+#define SK_PCI_VPD_CAPID 0x0050
+#define SK_PCI_VPD_NEXTPTR 0x0051
+#define SK_PCI_VPD_ADDR 0x0052
+#define SK_PCI_VPD_DATA 0x0054
+
+#define SK_PSTATE_MASK 0x0003
+#define SK_PSTATE_D0 0x0000
+#define SK_PSTATE_D1 0x0001
+#define SK_PSTATE_D2 0x0002
+#define SK_PSTATE_D3 0x0003
+#define SK_PME_EN 0x0010
+#define SK_PME_STATUS 0x8000
+
+/*
+ * VPD flag bit. Set to 0 to initiate a read, will become 1 when
+ * read is complete. Set to 1 to initiate a write, will become 0
+ * when write is finished.
+ */
+#define SK_VPD_FLAG 0x8000
+
+/* VPD structures */
+struct vpd_res {
+ u_int8_t vr_id;
+ u_int8_t vr_len;
+ u_int8_t vr_pad;
+};
+
+struct vpd_key {
+ char vk_key[2];
+ u_int8_t vk_len;
+};
+
+#define VPD_RES_ID 0x82 /* ID string */
+#define VPD_RES_READ 0x90 /* start of read only area */
+#define VPD_RES_WRITE 0x81 /* start of read/write area */
+#define VPD_RES_END 0x78 /* end tag */
+
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->sk_btag, sc->sk_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->sk_btag, sc->sk_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->sk_btag, sc->sk_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->sk_btag, sc->sk_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->sk_btag, sc->sk_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->sk_btag, sc->sk_bhandle, reg)
+
+struct sk_type {
+ u_int16_t sk_vid;
+ u_int16_t sk_did;
+ char *sk_name;
+};
+
+/* RX queue descriptor data structure */
+struct sk_rx_desc {
+ u_int32_t sk_ctl;
+ u_int32_t sk_next;
+ u_int32_t sk_data_lo;
+ u_int32_t sk_data_hi;
+ u_int32_t sk_xmac_rxstat;
+ u_int32_t sk_timestamp;
+ u_int16_t sk_csum2;
+ u_int16_t sk_csum1;
+ u_int16_t sk_csum2_start;
+ u_int16_t sk_csum1_start;
+};
+
+#define SK_OPCODE_DEFAULT 0x00550000
+#define SK_OPCODE_CSUM 0x00560000
+
+#define SK_RXCTL_LEN 0x0000FFFF
+#define SK_RXCTL_OPCODE 0x00FF0000
+#define SK_RXCTL_TSTAMP_VALID 0x01000000
+#define SK_RXCTL_STATUS_VALID 0x02000000
+#define SK_RXCTL_DEV0 0x04000000
+#define SK_RXCTL_EOF_INTR 0x08000000
+#define SK_RXCTL_EOB_INTR 0x10000000
+#define SK_RXCTL_LASTFRAG 0x20000000
+#define SK_RXCTL_FIRSTFRAG 0x40000000
+#define SK_RXCTL_OWN 0x80000000
+
+#define SK_RXSTAT \
+ (SK_OPCODE_DEFAULT|SK_RXCTL_EOF_INTR|SK_RXCTL_LASTFRAG| \
+ SK_RXCTL_FIRSTFRAG|SK_RXCTL_OWN)
+
+struct sk_tx_desc {
+ u_int32_t sk_ctl;
+ u_int32_t sk_next;
+ u_int32_t sk_data_lo;
+ u_int32_t sk_data_hi;
+ u_int32_t sk_xmac_txstat;
+ u_int16_t sk_rsvd0;
+ u_int16_t sk_csum_startval;
+ u_int16_t sk_csum_startpos;
+ u_int16_t sk_csum_writepos;
+ u_int32_t sk_rsvd1;
+};
+
+#define SK_TXCTL_LEN 0x0000FFFF
+#define SK_TXCTL_OPCODE 0x00FF0000
+#define SK_TXCTL_SW 0x01000000
+#define SK_TXCTL_NOCRC 0x02000000
+#define SK_TXCTL_STORENFWD 0x04000000
+#define SK_TXCTL_EOF_INTR 0x08000000
+#define SK_TXCTL_EOB_INTR 0x10000000
+#define SK_TXCTL_LASTFRAG 0x20000000
+#define SK_TXCTL_FIRSTFRAG 0x40000000
+#define SK_TXCTL_OWN 0x80000000
+
+#define SK_TXSTAT \
+ (SK_OPCODE_DEFAULT|SK_TXCTL_EOF_INTR|SK_TXCTL_LASTFRAG|SK_TXCTL_OWN)
+
+#define SK_RXBYTES(x) (x) & 0x0000FFFF;
+#define SK_TXBYTES SK_RXBYTES
+
+#define SK_TX_RING_CNT 512
+#define SK_RX_RING_CNT 256
+
+/*
+ * Jumbo buffer stuff. Note that we must allocate more jumbo
+ * buffers than there are descriptors in the receive ring. This
+ * is because we don't know how long it will take for a packet
+ * to be released after we hand it off to the upper protocol
+ * layers. To be safe, we allocate 1.5 times the number of
+ * receive descriptors.
+ */
+#define SK_JUMBO_FRAMELEN 9018
+#define SK_JUMBO_MTU (SK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define SK_JSLOTS 384
+
+#define SK_JRAWLEN (SK_JUMBO_FRAMELEN + ETHER_ALIGN)
+#define SK_JLEN (SK_JRAWLEN + (sizeof(u_int64_t) - \
+ (SK_JRAWLEN % sizeof(u_int64_t))))
+#define SK_JPAGESZ PAGE_SIZE
+#define SK_RESID (SK_JPAGESZ - (SK_JLEN * SK_JSLOTS) % SK_JPAGESZ)
+#define SK_JMEM ((SK_JLEN * SK_JSLOTS) + SK_RESID)
+
+struct sk_jpool_entry {
+ int slot;
+ SLIST_ENTRY(sk_jpool_entry) jpool_entries;
+};
+
+struct sk_chain {
+ void *sk_desc;
+ struct mbuf *sk_mbuf;
+ struct sk_chain *sk_next;
+};
+
+struct sk_chain_data {
+ struct sk_chain sk_tx_chain[SK_TX_RING_CNT];
+ struct sk_chain sk_rx_chain[SK_RX_RING_CNT];
+ int sk_tx_prod;
+ int sk_tx_cons;
+ int sk_tx_cnt;
+ int sk_rx_prod;
+ int sk_rx_cons;
+ int sk_rx_cnt;
+ /* Stick the jumbo mem management stuff here too. */
+ caddr_t sk_jslots[SK_JSLOTS];
+ void *sk_jumbo_buf;
+
+};
+
+struct sk_ring_data {
+ struct sk_tx_desc sk_tx_ring[SK_TX_RING_CNT];
+ struct sk_rx_desc sk_rx_ring[SK_RX_RING_CNT];
+};
+
+struct sk_bcom_hack {
+ int reg;
+ int val;
+};
+
+#define SK_INC(x, y) (x) = (x + 1) % y
+
+/* Forward decl. */
+struct sk_if_softc;
+
+/* Softc for the GEnesis controller. */
+struct sk_softc {
+ bus_space_handle_t sk_bhandle; /* bus space handle */
+ bus_space_tag_t sk_btag; /* bus space tag */
+ void *sk_intrhand; /* irq handler handle */
+ struct resource *sk_irq; /* IRQ resource handle */
+ struct resource *sk_res; /* I/O or shared mem handle */
+ u_int8_t sk_unit; /* controller number */
+ u_int8_t sk_type;
+ char *sk_vpd_prodname;
+ char *sk_vpd_readonly;
+ u_int32_t sk_rboff; /* RAMbuffer offset */
+ u_int32_t sk_ramsize; /* amount of RAM on NIC */
+ u_int32_t sk_pmd; /* physical media type */
+ u_int32_t sk_intrmask;
+ struct sk_if_softc *sk_if[2];
+ device_t sk_devs[2];
+ struct mtx sk_mtx;
+};
+
+#define SK_LOCK(_sc) mtx_lock(&(_sc)->sk_mtx)
+#define SK_UNLOCK(_sc) mtx_unlock(&(_sc)->sk_mtx)
+#define SK_IF_LOCK(_sc) mtx_lock(&(_sc)->sk_softc->sk_mtx)
+#define SK_IF_UNLOCK(_sc) mtx_unlock(&(_sc)->sk_softc->sk_mtx)
+
+/* Softc for each logical interface */
+struct sk_if_softc {
+ struct arpcom arpcom; /* interface info */
+ device_t sk_miibus;
+ u_int8_t sk_unit; /* interface number */
+ u_int8_t sk_port; /* port # on controller */
+ u_int8_t sk_xmac_rev; /* XMAC chip rev (B2 or C1) */
+ u_int32_t sk_rx_ramstart;
+ u_int32_t sk_rx_ramend;
+ u_int32_t sk_tx_ramstart;
+ u_int32_t sk_tx_ramend;
+ int sk_phytype;
+ int sk_phyaddr;
+ device_t sk_dev;
+ int sk_cnt;
+ int sk_link;
+ struct callout_handle sk_tick_ch;
+ struct sk_chain_data sk_cdata;
+ struct sk_ring_data *sk_rdata;
+ struct sk_softc *sk_softc; /* parent controller */
+ int sk_tx_bmu; /* TX BMU register */
+ int sk_if_flags;
+ SLIST_HEAD(__sk_jfreehead, sk_jpool_entry) sk_jfree_listhead;
+ SLIST_HEAD(__sk_jinusehead, sk_jpool_entry) sk_jinuse_listhead;
+};
+
+#define SK_MAXUNIT 256
+#define SK_TIMEOUT 1000
+#define ETHER_ALIGN 2
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_ste.c b/sys/pci/if_ste.c
new file mode 100644
index 0000000..6b65dcf
--- /dev/null
+++ b/sys/pci/if_ste.c
@@ -0,0 +1,1583 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_memio.h>
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#define STE_USEIOSPACE
+
+#include <pci/if_stereg.h>
+
+MODULE_DEPEND(ste, miibus, 1, 1, 1);
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct ste_type ste_devs[] = {
+ { ST_VENDORID, ST_DEVICEID_ST201, "Sundance ST201 10/100BaseTX" },
+ { DL_VENDORID, DL_DEVICEID_550TX, "D-Link DFE-550TX 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int ste_probe (device_t);
+static int ste_attach (device_t);
+static int ste_detach (device_t);
+static void ste_init (void *);
+static void ste_intr (void *);
+static void ste_rxeof (struct ste_softc *);
+static void ste_txeoc (struct ste_softc *);
+static void ste_txeof (struct ste_softc *);
+static void ste_stats_update (void *);
+static void ste_stop (struct ste_softc *);
+static void ste_reset (struct ste_softc *);
+static int ste_ioctl (struct ifnet *, u_long, caddr_t);
+static int ste_encap (struct ste_softc *, struct ste_chain *,
+ struct mbuf *);
+static void ste_start (struct ifnet *);
+static void ste_watchdog (struct ifnet *);
+static void ste_shutdown (device_t);
+static int ste_newbuf (struct ste_softc *,
+ struct ste_chain_onefrag *,
+ struct mbuf *);
+static int ste_ifmedia_upd (struct ifnet *);
+static void ste_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void ste_mii_sync (struct ste_softc *);
+static void ste_mii_send (struct ste_softc *, u_int32_t, int);
+static int ste_mii_readreg (struct ste_softc *, struct ste_mii_frame *);
+static int ste_mii_writereg (struct ste_softc *, struct ste_mii_frame *);
+static int ste_miibus_readreg (device_t, int, int);
+static int ste_miibus_writereg (device_t, int, int, int);
+static void ste_miibus_statchg (device_t);
+
+static int ste_eeprom_wait (struct ste_softc *);
+static int ste_read_eeprom (struct ste_softc *, caddr_t, int, int, int);
+static void ste_wait (struct ste_softc *);
+static u_int8_t ste_calchash (caddr_t);
+static void ste_setmulti (struct ste_softc *);
+static int ste_init_rx_list (struct ste_softc *);
+static void ste_init_tx_list (struct ste_softc *);
+
+#ifdef STE_USEIOSPACE
+#define STE_RES SYS_RES_IOPORT
+#define STE_RID STE_PCI_LOIO
+#else
+#define STE_RES SYS_RES_MEMORY
+#define STE_RID STE_PCI_LOMEM
+#endif
+
+static device_method_t ste_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ste_probe),
+ DEVMETHOD(device_attach, ste_attach),
+ DEVMETHOD(device_detach, ste_detach),
+ DEVMETHOD(device_shutdown, ste_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, ste_miibus_readreg),
+ DEVMETHOD(miibus_writereg, ste_miibus_writereg),
+ DEVMETHOD(miibus_statchg, ste_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t ste_driver = {
+ "ste",
+ ste_methods,
+ sizeof(struct ste_softc)
+};
+
+static devclass_t ste_devclass;
+
+DRIVER_MODULE(if_ste, pci, ste_driver, ste_devclass, 0, 0);
+DRIVER_MODULE(miibus, ste, miibus_driver, miibus_devclass, 0, 0);
+
+#define STE_SETBIT4(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x)
+
+#define STE_CLRBIT4(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x)
+
+#define STE_SETBIT2(sc, reg, x) \
+ CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | x)
+
+#define STE_CLRBIT2(sc, reg, x) \
+ CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~x)
+
+#define STE_SETBIT1(sc, reg, x) \
+ CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | x)
+
+#define STE_CLRBIT1(sc, reg, x) \
+ CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~x)
+
+
+#define MII_SET(x) STE_SETBIT1(sc, STE_PHYCTL, x)
+#define MII_CLR(x) STE_CLRBIT1(sc, STE_PHYCTL, x)
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void ste_mii_sync(sc)
+ struct ste_softc *sc;
+{
+ register int i;
+
+ MII_SET(STE_PHYCTL_MDIR|STE_PHYCTL_MDATA);
+
+ for (i = 0; i < 32; i++) {
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void ste_mii_send(sc, bits, cnt)
+ struct ste_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ MII_CLR(STE_PHYCTL_MCLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ MII_SET(STE_PHYCTL_MDATA);
+ } else {
+ MII_CLR(STE_PHYCTL_MDATA);
+ }
+ DELAY(1);
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_SET(STE_PHYCTL_MCLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int ste_mii_readreg(sc, frame)
+ struct ste_softc *sc;
+ struct ste_mii_frame *frame;
+
+{
+ int i, ack;
+
+ STE_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = STE_MII_STARTDELIM;
+ frame->mii_opcode = STE_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ CSR_WRITE_2(sc, STE_PHYCTL, 0);
+ /*
+ * Turn on data xmit.
+ */
+ MII_SET(STE_PHYCTL_MDIR);
+
+ ste_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ ste_mii_send(sc, frame->mii_stdelim, 2);
+ ste_mii_send(sc, frame->mii_opcode, 2);
+ ste_mii_send(sc, frame->mii_phyaddr, 5);
+ ste_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Turn off xmit. */
+ MII_CLR(STE_PHYCTL_MDIR);
+
+ /* Idle bit */
+ MII_CLR((STE_PHYCTL_MCLK|STE_PHYCTL_MDATA));
+ DELAY(1);
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+
+ /* Check for ack */
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+ ack = CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA;
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+ }
+
+fail:
+
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+
+ STE_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int ste_mii_writereg(sc, frame)
+ struct ste_softc *sc;
+ struct ste_mii_frame *frame;
+
+{
+ STE_LOCK(sc);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = STE_MII_STARTDELIM;
+ frame->mii_opcode = STE_MII_WRITEOP;
+ frame->mii_turnaround = STE_MII_TURNAROUND;
+
+ /*
+ * Turn on data output.
+ */
+ MII_SET(STE_PHYCTL_MDIR);
+
+ ste_mii_sync(sc);
+
+ ste_mii_send(sc, frame->mii_stdelim, 2);
+ ste_mii_send(sc, frame->mii_opcode, 2);
+ ste_mii_send(sc, frame->mii_phyaddr, 5);
+ ste_mii_send(sc, frame->mii_regaddr, 5);
+ ste_mii_send(sc, frame->mii_turnaround, 2);
+ ste_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ MII_SET(STE_PHYCTL_MCLK);
+ DELAY(1);
+ MII_CLR(STE_PHYCTL_MCLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ MII_CLR(STE_PHYCTL_MDIR);
+
+ STE_UNLOCK(sc);
+
+ return(0);
+}
+
+static int ste_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct ste_softc *sc;
+ struct ste_mii_frame frame;
+
+ sc = device_get_softc(dev);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ ste_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int ste_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct ste_softc *sc;
+ struct ste_mii_frame frame;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ ste_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+static void ste_miibus_statchg(dev)
+ device_t dev;
+{
+ struct ste_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ STE_LOCK(sc);
+ mii = device_get_softc(sc->ste_miibus);
+
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ STE_SETBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
+ } else {
+ STE_CLRBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
+ }
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+static int ste_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct ste_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->ste_miibus);
+ sc->ste_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ return(0);
+}
+
+static void ste_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct ste_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->ste_miibus);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static void ste_wait(sc)
+ struct ste_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < STE_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_DMA_HALTINPROG))
+ break;
+ }
+
+ if (i == STE_TIMEOUT)
+ printf("ste%d: command never completed!\n", sc->ste_unit);
+
+ return;
+}
+
+/*
+ * The EEPROM is slow: give it time to come ready after issuing
+ * it a command.
+ */
+static int ste_eeprom_wait(sc)
+ struct ste_softc *sc;
+{
+ int i;
+
+ DELAY(1000);
+
+ for (i = 0; i < 100; i++) {
+ if (CSR_READ_2(sc, STE_EEPROM_CTL) & STE_EECTL_BUSY)
+ DELAY(1000);
+ else
+ break;
+ }
+
+ if (i == 100) {
+ printf("ste%d: eeprom failed to come ready\n", sc->ste_unit);
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * Read a sequence of words from the EEPROM. Note that ethernet address
+ * data is stored in the EEPROM in network byte order.
+ */
+static int ste_read_eeprom(sc, dest, off, cnt, swap)
+ struct ste_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int err = 0, i;
+ u_int16_t word = 0, *ptr;
+
+ if (ste_eeprom_wait(sc))
+ return(1);
+
+ for (i = 0; i < cnt; i++) {
+ CSR_WRITE_2(sc, STE_EEPROM_CTL, STE_EEOPCODE_READ | (off + i));
+ err = ste_eeprom_wait(sc);
+ if (err)
+ break;
+ word = CSR_READ_2(sc, STE_EEPROM_DATA);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return(err ? 1 : 0);
+}
+
+static u_int8_t ste_calchash(addr)
+ caddr_t addr;
+{
+
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return(crc & 0x0000003F);
+}
+
+static void ste_setmulti(sc)
+ struct ste_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
+ STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_2(sc, STE_MAR0, 0);
+ CSR_WRITE_2(sc, STE_MAR1, 0);
+ CSR_WRITE_2(sc, STE_MAR2, 0);
+ CSR_WRITE_2(sc, STE_MAR3, 0);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = ste_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
+ CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
+ CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
+ CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
+ STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
+ STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
+
+ return;
+}
+
+static void ste_intr(xsc)
+ void *xsc;
+{
+ struct ste_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t status;
+
+ sc = xsc;
+ STE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ /* See if this is really our interrupt. */
+ if (!(CSR_READ_2(sc, STE_ISR) & STE_ISR_INTLATCH)) {
+ STE_UNLOCK(sc);
+ return;
+ }
+
+ for (;;) {
+ status = CSR_READ_2(sc, STE_ISR_ACK);
+
+ if (!(status & STE_INTRS))
+ break;
+
+ if (status & STE_ISR_RX_DMADONE)
+ ste_rxeof(sc);
+
+ if (status & STE_ISR_TX_DMADONE)
+ ste_txeof(sc);
+
+ if (status & STE_ISR_TX_DONE)
+ ste_txeoc(sc);
+
+ if (status & STE_ISR_STATS_OFLOW) {
+ untimeout(ste_stats_update, sc, sc->ste_stat_ch);
+ ste_stats_update(sc);
+ }
+
+ if (status & STE_ISR_HOSTERR) {
+ ste_reset(sc);
+ ste_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts */
+ CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ ste_start(ifp);
+
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void ste_rxeof(sc)
+ struct ste_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct ste_chain_onefrag *cur_rx;
+ int total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+again:
+
+ while((rxstat = sc->ste_cdata.ste_rx_head->ste_ptr->ste_status)) {
+ cur_rx = sc->ste_cdata.ste_rx_head;
+ sc->ste_cdata.ste_rx_head = cur_rx->ste_next;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & STE_RXSTAT_FRAME_ERR) {
+ ifp->if_ierrors++;
+ cur_rx->ste_ptr->ste_status = 0;
+ continue;
+ }
+
+ /*
+ * If there error bit was not set, the upload complete
+ * bit should be set which means we have a valid packet.
+ * If not, something truly strange has happened.
+ */
+ if (!(rxstat & STE_RXSTAT_DMADONE)) {
+ printf("ste%d: bad receive status -- packet dropped",
+ sc->ste_unit);
+ ifp->if_ierrors++;
+ cur_rx->ste_ptr->ste_status = 0;
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+ m = cur_rx->ste_mbuf;
+ total_len = cur_rx->ste_ptr->ste_status & STE_RXSTAT_FRAMELEN;
+
+ /*
+ * Try to conjure up a new mbuf cluster. If that
+ * fails, it means we have an out of memory condition and
+ * should leave the buffer in place and continue. This will
+ * result in a lost packet, but there's little else we
+ * can do in this situation.
+ */
+ if (ste_newbuf(sc, cur_rx, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ cur_rx->ste_ptr->ste_status = 0;
+ continue;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ /*
+ * Handle the 'end of channel' condition. When the upload
+ * engine hits the end of the RX ring, it will stall. This
+ * is our cue to flush the RX ring, reload the uplist pointer
+ * register and unstall the engine.
+ * XXX This is actually a little goofy. With the ThunderLAN
+ * chip, you get an interrupt when the receiver hits the end
+ * of the receive ring, which tells you exactly when you
+ * you need to reload the ring pointer. Here we have to
+ * fake it. I'm mad at myself for not being clever enough
+ * to avoid the use of a goto here.
+ */
+ if (CSR_READ_4(sc, STE_RX_DMALIST_PTR) == 0 ||
+ CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_RXDMA_STOPPED) {
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
+ ste_wait(sc);
+ CSR_WRITE_4(sc, STE_RX_DMALIST_PTR,
+ vtophys(&sc->ste_ldata->ste_rx_list[0]));
+ sc->ste_cdata.ste_rx_head = &sc->ste_cdata.ste_rx_chain[0];
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
+ goto again;
+ }
+
+ return;
+}
+
+static void ste_txeoc(sc)
+ struct ste_softc *sc;
+{
+ u_int8_t txstat;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ while ((txstat = CSR_READ_1(sc, STE_TX_STATUS)) &
+ STE_TXSTATUS_TXDONE) {
+ if (txstat & STE_TXSTATUS_UNDERRUN ||
+ txstat & STE_TXSTATUS_EXCESSCOLLS ||
+ txstat & STE_TXSTATUS_RECLAIMERR) {
+ ifp->if_oerrors++;
+ printf("ste%d: transmission error: %x\n",
+ sc->ste_unit, txstat);
+
+ ste_reset(sc);
+ ste_init(sc);
+
+ if (txstat & STE_TXSTATUS_UNDERRUN &&
+ sc->ste_tx_thresh < STE_PACKET_SIZE) {
+ sc->ste_tx_thresh += STE_MIN_FRAMELEN;
+ printf("ste%d: tx underrun, increasing tx"
+ " start threshold to %d bytes\n",
+ sc->ste_unit, sc->ste_tx_thresh);
+ }
+ CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
+ CSR_WRITE_2(sc, STE_TX_RECLAIM_THRESH,
+ (STE_PACKET_SIZE >> 4));
+ }
+ ste_init(sc);
+ CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
+ }
+
+ return;
+}
+
+static void ste_txeof(sc)
+ struct ste_softc *sc;
+{
+ struct ste_chain *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ idx = sc->ste_cdata.ste_tx_cons;
+ while(idx != sc->ste_cdata.ste_tx_prod) {
+ cur_tx = &sc->ste_cdata.ste_tx_chain[idx];
+
+ if (!(cur_tx->ste_ptr->ste_ctl & STE_TXCTL_DMADONE))
+ break;
+
+ if (cur_tx->ste_mbuf != NULL) {
+ m_freem(cur_tx->ste_mbuf);
+ cur_tx->ste_mbuf = NULL;
+ }
+
+ ifp->if_opackets++;
+
+ sc->ste_cdata.ste_tx_cnt--;
+ STE_INC(idx, STE_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->ste_cdata.ste_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void ste_stats_update(xsc)
+ void *xsc;
+{
+ struct ste_softc *sc;
+ struct ste_stats stats;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ int i;
+ u_int8_t *p;
+
+ sc = xsc;
+ STE_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->ste_miibus);
+
+ p = (u_int8_t *)&stats;
+
+ for (i = 0; i < sizeof(stats); i++) {
+ *p = CSR_READ_1(sc, STE_STATS + i);
+ p++;
+ }
+
+ ifp->if_collisions += stats.ste_single_colls +
+ stats.ste_multi_colls + stats.ste_late_colls;
+
+ mii_tick(mii);
+ if (!sc->ste_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->ste_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ ste_start(ifp);
+ }
+
+ sc->ste_stat_ch = timeout(ste_stats_update, sc, hz);
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+
+/*
+ * Probe for a Sundance ST201 chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int ste_probe(dev)
+ device_t dev;
+{
+ struct ste_type *t;
+
+ t = ste_devs;
+
+ while(t->ste_name != NULL) {
+ if ((pci_get_vendor(dev) == t->ste_vid) &&
+ (pci_get_device(dev) == t->ste_did)) {
+ device_set_desc(dev, t->ste_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int ste_attach(dev)
+ device_t dev;
+{
+ u_int32_t command;
+ struct ste_softc *sc;
+ struct ifnet *ifp;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct ste_softc));
+
+ mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ STE_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, STE_PCI_LOIO, 4);
+ membase = pci_read_config(dev, STE_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, STE_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("ste%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, STE_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, STE_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, STE_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef STE_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("ste%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("ste%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = STE_RID;
+ sc->ste_res = bus_alloc_resource(dev, STE_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->ste_res == NULL) {
+ printf ("ste%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->ste_btag = rman_get_bustag(sc->ste_res);
+ sc->ste_bhandle = rman_get_bushandle(sc->ste_res);
+
+ rid = 0;
+ sc->ste_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->ste_irq == NULL) {
+ printf("ste%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET,
+ ste_intr, sc, &sc->ste_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+ printf("ste%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ callout_handle_init(&sc->ste_stat_ch);
+
+ /* Reset the adapter. */
+ ste_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ if (ste_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
+ STE_EEADDR_NODE0, 3, 0)) {
+ printf("ste%d: failed to read station address\n", unit);
+ bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+ error = ENXIO;;
+ goto fail;
+ }
+
+ /*
+ * A Sundance chip was detected. Inform the world.
+ */
+ printf("ste%d: Ethernet address: %6D\n", unit,
+ sc->arpcom.ac_enaddr, ":");
+
+ sc->ste_unit = unit;
+
+ /* Allocate the descriptor queues. */
+ sc->ste_ldata = contigmalloc(sizeof(struct ste_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->ste_ldata == NULL) {
+ printf("ste%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->ste_ldata, sizeof(struct ste_list_data));
+
+ /* Do MII setup. */
+ if (mii_phy_probe(dev, &sc->ste_miibus,
+ ste_ifmedia_upd, ste_ifmedia_sts)) {
+ printf("ste%d: MII without any phy!\n", sc->ste_unit);
+ bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+ contigfree(sc->ste_ldata,
+ sizeof(struct ste_list_data), M_DEVBUF);
+ error = ENXIO;
+ goto fail;
+ }
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "ste";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = ste_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = ste_start;
+ ifp->if_watchdog = ste_watchdog;
+ ifp->if_init = ste_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = STE_TX_LIST_CNT - 1;
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ STE_UNLOCK(sc);
+ return(0);
+
+fail:
+ STE_UNLOCK(sc);
+ mtx_destroy(&sc->ste_mtx);
+ return(error);
+}
+
+static int ste_detach(dev)
+ device_t dev;
+{
+ struct ste_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ STE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ ste_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->ste_miibus);
+
+ bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
+ bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+
+ contigfree(sc->ste_ldata, sizeof(struct ste_list_data), M_DEVBUF);
+
+ STE_UNLOCK(sc);
+ mtx_destroy(&sc->ste_mtx);
+
+ return(0);
+}
+
+static int ste_newbuf(sc, c, m)
+ struct ste_softc *sc;
+ struct ste_chain_onefrag *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+
+ c->ste_mbuf = m_new;
+ c->ste_ptr->ste_status = 0;
+ c->ste_ptr->ste_frag.ste_addr = vtophys(mtod(m_new, caddr_t));
+ c->ste_ptr->ste_frag.ste_len = 1536 | STE_FRAG_LAST;
+
+ return(0);
+}
+
+static int ste_init_rx_list(sc)
+ struct ste_softc *sc;
+{
+ struct ste_chain_data *cd;
+ struct ste_list_data *ld;
+ int i;
+
+ cd = &sc->ste_cdata;
+ ld = sc->ste_ldata;
+
+ for (i = 0; i < STE_RX_LIST_CNT; i++) {
+ cd->ste_rx_chain[i].ste_ptr = &ld->ste_rx_list[i];
+ if (ste_newbuf(sc, &cd->ste_rx_chain[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (STE_RX_LIST_CNT - 1)) {
+ cd->ste_rx_chain[i].ste_next =
+ &cd->ste_rx_chain[0];
+ ld->ste_rx_list[i].ste_next =
+ vtophys(&ld->ste_rx_list[0]);
+ } else {
+ cd->ste_rx_chain[i].ste_next =
+ &cd->ste_rx_chain[i + 1];
+ ld->ste_rx_list[i].ste_next =
+ vtophys(&ld->ste_rx_list[i + 1]);
+ }
+
+ }
+
+ cd->ste_rx_head = &cd->ste_rx_chain[0];
+
+ return(0);
+}
+
+static void ste_init_tx_list(sc)
+ struct ste_softc *sc;
+{
+ struct ste_chain_data *cd;
+ struct ste_list_data *ld;
+ int i;
+
+ cd = &sc->ste_cdata;
+ ld = sc->ste_ldata;
+ for (i = 0; i < STE_TX_LIST_CNT; i++) {
+ cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i];
+ cd->ste_tx_chain[i].ste_phys = vtophys(&ld->ste_tx_list[i]);
+ if (i == (STE_TX_LIST_CNT - 1))
+ cd->ste_tx_chain[i].ste_next =
+ &cd->ste_tx_chain[0];
+ else
+ cd->ste_tx_chain[i].ste_next =
+ &cd->ste_tx_chain[i + 1];
+ if (i == 0)
+ cd->ste_tx_chain[i].ste_prev =
+ &cd->ste_tx_chain[STE_TX_LIST_CNT - 1];
+ else
+ cd->ste_tx_chain[i].ste_prev =
+ &cd->ste_tx_chain[i - 1];
+ }
+
+
+ bzero((char *)ld->ste_tx_list,
+ sizeof(struct ste_desc) * STE_TX_LIST_CNT);
+
+ cd->ste_tx_prod = 0;
+ cd->ste_tx_cons = 0;
+ cd->ste_tx_cnt = 0;
+
+ return;
+}
+
+static void ste_init(xsc)
+ void *xsc;
+{
+ struct ste_softc *sc;
+ int i;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+
+ sc = xsc;
+ STE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->ste_miibus);
+
+ ste_stop(sc);
+
+ /* Init our MAC address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ CSR_WRITE_1(sc, STE_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Init RX list */
+ if (ste_init_rx_list(sc) == ENOBUFS) {
+ printf("ste%d: initialization failed: no "
+ "memory for RX buffers\n", sc->ste_unit);
+ ste_stop(sc);
+ STE_UNLOCK(sc);
+ return;
+ }
+
+ /* Init TX descriptors */
+ ste_init_tx_list(sc);
+
+ /* Set the TX freethresh value */
+ CSR_WRITE_1(sc, STE_TX_DMABURST_THRESH, STE_PACKET_SIZE >> 8);
+
+ /* Set the TX start threshold for best performance. */
+ CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
+
+ /* Set the TX reclaim threshold. */
+ CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (STE_PACKET_SIZE >> 4));
+
+ /* Set up the RX filter. */
+ CSR_WRITE_1(sc, STE_RX_MODE, STE_RXMODE_UNICAST);
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
+ } else {
+ STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
+ }
+
+ /* Set capture broadcast bit to accept broadcast frames. */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
+ } else {
+ STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
+ }
+
+ ste_setmulti(sc);
+
+ /* Load the address of the RX list. */
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
+ ste_wait(sc);
+ CSR_WRITE_4(sc, STE_RX_DMALIST_PTR,
+ vtophys(&sc->ste_ldata->ste_rx_list[0]));
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
+
+ /* Set TX polling interval */
+ CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64);
+
+ /* Load address of the TX list */
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
+ ste_wait(sc);
+ CSR_WRITE_4(sc, STE_TX_DMALIST_PTR,
+ vtophys(&sc->ste_ldata->ste_tx_list[0]));
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
+ STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
+ ste_wait(sc);
+
+ /* Enable receiver and transmitter */
+ CSR_WRITE_2(sc, STE_MACCTL0, 0);
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE);
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_ENABLE);
+
+ /* Enable stats counters. */
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_ENABLE);
+
+ /* Enable interrupts. */
+ CSR_WRITE_2(sc, STE_ISR, 0xFFFF);
+ CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
+
+ ste_ifmedia_upd(ifp);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->ste_stat_ch = timeout(ste_stats_update, sc, hz);
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+static void ste_stop(sc)
+ struct ste_softc *sc;
+{
+ int i;
+ struct ifnet *ifp;
+
+ STE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ untimeout(ste_stats_update, sc, sc->ste_stat_ch);
+
+ CSR_WRITE_2(sc, STE_IMR, 0);
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_DISABLE);
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_DISABLE);
+ STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_DISABLE);
+ STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
+ STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
+ ste_wait(sc);
+
+ sc->ste_link = 0;
+
+ for (i = 0; i < STE_RX_LIST_CNT; i++) {
+ if (sc->ste_cdata.ste_rx_chain[i].ste_mbuf != NULL) {
+ m_freem(sc->ste_cdata.ste_rx_chain[i].ste_mbuf);
+ sc->ste_cdata.ste_rx_chain[i].ste_mbuf = NULL;
+ }
+ }
+
+ for (i = 0; i < STE_TX_LIST_CNT; i++) {
+ if (sc->ste_cdata.ste_tx_chain[i].ste_mbuf != NULL) {
+ m_freem(sc->ste_cdata.ste_tx_chain[i].ste_mbuf);
+ sc->ste_cdata.ste_tx_chain[i].ste_mbuf = NULL;
+ }
+ }
+
+ ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+static void ste_reset(sc)
+ struct ste_softc *sc;
+{
+ int i;
+
+ STE_SETBIT4(sc, STE_ASICCTL,
+ STE_ASICCTL_GLOBAL_RESET|STE_ASICCTL_RX_RESET|
+ STE_ASICCTL_TX_RESET|STE_ASICCTL_DMA_RESET|
+ STE_ASICCTL_FIFO_RESET|STE_ASICCTL_NETWORK_RESET|
+ STE_ASICCTL_AUTOINIT_RESET|STE_ASICCTL_HOST_RESET|
+ STE_ASICCTL_EXTRESET_RESET);
+
+ DELAY(100000);
+
+ for (i = 0; i < STE_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY))
+ break;
+ }
+
+ if (i == STE_TIMEOUT)
+ printf("ste%d: global reset never completed\n", sc->ste_unit);
+
+ return;
+}
+
+static int ste_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct ste_softc *sc;
+ struct ifreq *ifr;
+ struct mii_data *mii;
+ int error = 0;
+
+ sc = ifp->if_softc;
+ STE_LOCK(sc);
+ ifr = (struct ifreq *)data;
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->ste_if_flags & IFF_PROMISC)) {
+ STE_SETBIT1(sc, STE_RX_MODE,
+ STE_RXMODE_PROMISC);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->ste_if_flags & IFF_PROMISC) {
+ STE_CLRBIT1(sc, STE_RX_MODE,
+ STE_RXMODE_PROMISC);
+ } else if (!(ifp->if_flags & IFF_RUNNING)) {
+ sc->ste_tx_thresh = STE_MIN_FRAMELEN;
+ ste_init(sc);
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ ste_stop(sc);
+ }
+ sc->ste_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ste_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->ste_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ STE_UNLOCK(sc);
+
+ return(error);
+}
+
+static int ste_encap(sc, c, m_head)
+ struct ste_softc *sc;
+ struct ste_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct ste_frag *f = NULL;
+ struct mbuf *m;
+ struct ste_desc *d;
+ int total_len = 0;
+
+ d = c->ste_ptr;
+ d->ste_ctl = 0;
+ d->ste_next = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == STE_MAXFRAGS)
+ break;
+ total_len += m->m_len;
+ f = &c->ste_ptr->ste_frags[frag];
+ f->ste_addr = vtophys(mtod(m, vm_offset_t));
+ f->ste_len = m->m_len;
+ frag++;
+ }
+ }
+
+ c->ste_mbuf = m_head;
+ c->ste_ptr->ste_frags[frag - 1].ste_len |= STE_FRAG_LAST;
+ c->ste_ptr->ste_ctl = total_len;
+
+ return(0);
+}
+
+static void ste_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ste_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct ste_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+ int idx;
+
+ sc = ifp->if_softc;
+ STE_LOCK(sc);
+
+ if (!sc->ste_link) {
+ STE_UNLOCK(sc);
+ return;
+ }
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ STE_UNLOCK(sc);
+ return;
+ }
+
+ idx = sc->ste_cdata.ste_tx_prod;
+ start_tx = &sc->ste_cdata.ste_tx_chain[idx];
+
+ while(sc->ste_cdata.ste_tx_chain[idx].ste_mbuf == NULL) {
+
+ if ((STE_TX_LIST_CNT - sc->ste_cdata.ste_tx_cnt) < 3) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ cur_tx = &sc->ste_cdata.ste_tx_chain[idx];
+
+ ste_encap(sc, cur_tx, m_head);
+
+ if (prev != NULL)
+ prev->ste_ptr->ste_next = cur_tx->ste_phys;
+ prev = cur_tx;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->ste_mbuf);
+
+ STE_INC(idx, STE_TX_LIST_CNT);
+ sc->ste_cdata.ste_tx_cnt++;
+ }
+
+ if (cur_tx == NULL) {
+ STE_UNLOCK(sc);
+ return;
+ }
+
+ cur_tx->ste_ptr->ste_ctl |= STE_TXCTL_DMAINTR;
+
+ /* Start transmission */
+ sc->ste_cdata.ste_tx_prod = idx;
+ start_tx->ste_prev->ste_ptr->ste_next = start_tx->ste_phys;
+
+ ifp->if_timer = 5;
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+static void ste_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct ste_softc *sc;
+
+ sc = ifp->if_softc;
+ STE_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("ste%d: watchdog timeout\n", sc->ste_unit);
+
+ ste_txeoc(sc);
+ ste_txeof(sc);
+ ste_rxeof(sc);
+ ste_reset(sc);
+ ste_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ ste_start(ifp);
+ STE_UNLOCK(sc);
+
+ return;
+}
+
+static void ste_shutdown(dev)
+ device_t dev;
+{
+ struct ste_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ ste_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_stereg.h b/sys/pci/if_stereg.h
new file mode 100644
index 0000000..b369d6d
--- /dev/null
+++ b/sys/pci/if_stereg.h
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Sundance PCI device/vendor ID for the
+ * ST201 chip.
+ */
+#define ST_VENDORID 0x13F0
+#define ST_DEVICEID_ST201 0x0201
+
+/*
+ * D-Link PCI device/vendor ID for the DFE-550TX.
+ */
+#define DL_VENDORID 0x1186
+#define DL_DEVICEID_550TX 0x1002
+
+/*
+ * Register definitions for the Sundance Technologies ST201 PCI
+ * fast ethernet controller. The register space is 128 bytes long and
+ * can be accessed using either PCI I/O space or PCI memory mapping.
+ * There are 32-bit, 16-bit and 8-bit registers.
+ */
+
+#define STE_DMACTL 0x00
+#define STE_TX_DMALIST_PTR 0x04
+#define STE_TX_DMABURST_THRESH 0x08
+#define STE_TX_DMAURG_THRESH 0x09
+#define STE_TX_DMAPOLL_PERIOD 0x0A
+#define STE_RX_DMASTATUS 0x0C
+#define STE_RX_DMALIST_PTR 0x10
+#define STE_RX_DMABURST_THRESH 0x14
+#define STE_RX_DMAURG_THRESH 0x15
+#define STE_RX_DMAPOLL_PERIOD 0x16
+#define STE_DEBUGCTL 0x1A
+#define STE_ASICCTL 0x30
+#define STE_EEPROM_DATA 0x34
+#define STE_EEPROM_CTL 0x36
+#define STE_FIFOCTL 0x3A
+#define STE_TX_STARTTHRESH 0x3C
+#define STE_RX_EARLYTHRESH 0x3E
+#define STE_EXT_ROMADDR 0x40
+#define STE_EXT_ROMDATA 0x44
+#define STE_WAKE_EVENT 0x45
+#define STE_TX_STATUS 0x46
+#define STE_TX_FRAMEID 0x47
+#define STE_COUNTDOWN 0x48
+#define STE_ISR_ACK 0x4A
+#define STE_IMR 0x4C
+#define STE_ISR 0x4E
+#define STE_MACCTL0 0x50
+#define STE_MACCTL1 0x52
+#define STE_PAR0 0x54
+#define STE_PAR1 0x56
+#define STE_PAR2 0x58
+#define STE_MAX_FRAMELEN 0x5A
+#define STE_RX_MODE 0x5C
+#define STE_TX_RECLAIM_THRESH 0x5D
+#define STE_PHYCTL 0x5E
+#define STE_MAR0 0x60
+#define STE_MAR1 0x62
+#define STE_MAR2 0x64
+#define STE_MAR3 0x66
+#define STE_STATS 0x68
+
+#define STE_DMACTL_RXDMA_STOPPED 0x00000001
+#define STE_DMACTL_TXDMA_CMPREQ 0x00000002
+#define STE_DMACTL_TXDMA_STOPPED 0x00000004
+#define STE_DMACTL_RXDMA_COMPLETE 0x00000008
+#define STE_DMACTL_TXDMA_COMPLETE 0x00000010
+#define STE_DMACTL_RXDMA_STALL 0x00000100
+#define STE_DMACTL_RXDMA_UNSTALL 0x00000200
+#define STE_DMACTL_TXDMA_STALL 0x00000400
+#define STE_DMACTL_TXDMA_UNSTALL 0x00000800
+#define STE_DMACTL_TXDMA_INPROG 0x00004000
+#define STE_DMACTL_DMA_HALTINPROG 0x00008000
+#define STE_DMACTL_RXEARLY_ENABLE 0x00020000
+#define STE_DMACTL_COUNTDOWN_SPEED 0x00040000
+#define STE_DMACTL_COUNTDOWN_MODE 0x00080000
+#define STE_DMACTL_MWI_DISABLE 0x00100000
+#define STE_DMACTL_RX_DISCARD_OFLOWS 0x00400000
+#define STE_DMACTL_COUNTDOWN_ENABLE 0x00800000
+#define STE_DMACTL_TARGET_ABORT 0x40000000
+#define STE_DMACTL_MASTER_ABORT 0x80000000
+
+/*
+ * TX DMA burst thresh is the number of 32-byte blocks that
+ * must be loaded into the TX Fifo before a TXDMA burst request
+ * will be issued.
+ */
+#define STE_TXDMABURST_THRESH 0x1F
+
+/*
+ * The number of 32-byte blocks in the TX FIFO falls below the
+ * TX DMA urgent threshold, a TX DMA urgent request will be
+ * generated.
+ */
+#define STE_TXDMAURG_THRESH 0x3F
+
+/*
+ * Number of 320ns intervals between polls of the TXDMA next
+ * descriptor pointer (if we're using polling mode).
+ */
+#define STE_TXDMA_POLL_PERIOD 0x7F
+
+#define STE_RX_DMASTATUS_FRAMELEN 0x00001FFF
+#define STE_RX_DMASTATUS_RXERR 0x00004000
+#define STE_RX_DMASTATUS_DMADONE 0x00008000
+#define STE_RX_DMASTATUS_FIFO_OFLOW 0x00010000
+#define STE_RX_DMASTATUS_RUNT 0x00020000
+#define STE_RX_DMASTATUS_ALIGNERR 0x00040000
+#define STE_RX_DMASTATUS_CRCERR 0x00080000
+#define STE_RX_DMASTATUS_GIANT 0x00100000
+#define STE_RX_DMASTATUS_DRIBBLE 0x00800000
+#define STE_RX_DMASTATUS_DMA_OFLOW 0x01000000
+
+/*
+ * RX DMA burst thresh is the number of 32-byte blocks that
+ * must be present in the RX FIFO before a RXDMA bus master
+ * request will be issued.
+ */
+#define STE_RXDMABURST_THRESH 0xFF
+
+/*
+ * The number of 32-byte blocks in the RX FIFO falls below the
+ * RX DMA urgent threshold, a RX DMA urgent request will be
+ * generated.
+ */
+#define STE_RXDMAURG_THRESH 0x1F
+
+/*
+ * Number of 320ns intervals between polls of the RXDMA complete
+ * bit in the status field on the current RX descriptor (if we're
+ * using polling mode).
+ */
+#define STE_RXDMA_POLL_PERIOD 0x7F
+
+#define STE_DEBUGCTL_GPIO0_CTL 0x0001
+#define STE_DEBUGCTL_GPIO1_CTL 0x0002
+#define STE_DEBUGCTL_GPIO0_DATA 0x0004
+#define STE_DEBUGCTL_GPIO1_DATA 0x0008
+
+#define STE_ASICCTL_ROMSIZE 0x00000002
+#define STE_ASICCTL_TX_LARGEPKTS 0x00000004
+#define STE_ASICCTL_RX_LARGEPKTS 0x00000008
+#define STE_ASICCTL_EXTROM_DISABLE 0x00000010
+#define STE_ASICCTL_PHYSPEED_10 0x00000020
+#define STE_ASICCTL_PHYSPEED_100 0x00000040
+#define STE_ASICCTL_PHYMEDIA 0x00000080
+#define STE_ASICCTL_FORCEDCONFIG 0x00000700
+#define STE_ASICCTL_D3RESET_DISABLE 0x00000800
+#define STE_ASICCTL_SPEEDUPMODE 0x00002000
+#define STE_ASICCTL_LEDMODE 0x00004000
+#define STE_ASICCTL_RSTOUT_POLARITY 0x00008000
+#define STE_ASICCTL_GLOBAL_RESET 0x00010000
+#define STE_ASICCTL_RX_RESET 0x00020000
+#define STE_ASICCTL_TX_RESET 0x00040000
+#define STE_ASICCTL_DMA_RESET 0x00080000
+#define STE_ASICCTL_FIFO_RESET 0x00100000
+#define STE_ASICCTL_NETWORK_RESET 0x00200000
+#define STE_ASICCTL_HOST_RESET 0x00400000
+#define STE_ASICCTL_AUTOINIT_RESET 0x00800000
+#define STE_ASICCTL_EXTRESET_RESET 0x01000000
+#define STE_ASICCTL_SOFTINTR 0x02000000
+#define STE_ASICCTL_RESET_BUSY 0x04000000
+
+#define STE_ASICCTL1_GLOBAL_RESET 0x0001
+#define STE_ASICCTL1_RX_RESET 0x0002
+#define STE_ASICCTL1_TX_RESET 0x0004
+#define STE_ASICCTL1_DMA_RESET 0x0008
+#define STE_ASICCTL1_FIFO_RESET 0x0010
+#define STE_ASICCTL1_NETWORK_RESET 0x0020
+#define STE_ASICCTL1_HOST_RESET 0x0040
+#define STE_ASICCTL1_AUTOINIT_RESET 0x0080
+#define STE_ASICCTL1_EXTRESET_RESET 0x0100
+#define STE_ASICCTL1_SOFTINTR 0x0200
+#define STE_ASICCTL1_RESET_BUSY 0x0400
+
+#define STE_EECTL_ADDR 0x00FF
+#define STE_EECTL_OPCODE 0x0300
+#define STE_EECTL_BUSY 0x1000
+
+#define STE_EEOPCODE_WRITE 0x0100
+#define STE_EEOPCODE_READ 0x0200
+#define STE_EEOPCODE_ERASE 0x0300
+
+#define STE_FIFOCTL_RAMTESTMODE 0x0001
+#define STE_FIFOCTL_OVERRUNMODE 0x0200
+#define STE_FIFOCTL_RXFIFOFULL 0x0800
+#define STE_FIFOCTL_TX_BUSY 0x4000
+#define STE_FIFOCTL_RX_BUSY 0x8000
+
+/*
+ * The number of bytes that must in present in the TX FIFO before
+ * transmission begins. Value should be in increments of 4 bytes.
+ */
+#define STE_TXSTART_THRESH 0x1FFF
+
+/*
+ * Number of bytes that must be present in the RX FIFO before
+ * an RX EARLY interrupt is generated.
+ */
+#define STE_RXEARLY_THRESH 0x1FFF
+
+#define STE_WAKEEVENT_WAKEPKT_ENB 0x01
+#define STE_WAKEEVENT_MAGICPKT_ENB 0x02
+#define STE_WAKEEVENT_LINKEVT_ENB 0x04
+#define STE_WAKEEVENT_WAKEPOLARITY 0x08
+#define STE_WAKEEVENT_WAKEPKTEVENT 0x10
+#define STE_WAKEEVENT_MAGICPKTEVENT 0x20
+#define STE_WAKEEVENT_LINKEVENT 0x40
+#define STE_WAKEEVENT_WAKEONLAN_ENB 0x80
+
+#define STE_TXSTATUS_RECLAIMERR 0x02
+#define STE_TXSTATUS_STATSOFLOW 0x04
+#define STE_TXSTATUS_EXCESSCOLLS 0x08
+#define STE_TXSTATUS_UNDERRUN 0x10
+#define STE_TXSTATUS_TXINTR_REQ 0x40
+#define STE_TXSTATUS_TXDONE 0x80
+
+#define STE_ISRACK_INTLATCH 0x0001
+#define STE_ISRACK_HOSTERR 0x0002
+#define STE_ISRACK_TX_DONE 0x0004
+#define STE_ISRACK_MACCTL_FRAME 0x0008
+#define STE_ISRACK_RX_DONE 0x0010
+#define STE_ISRACK_RX_EARLY 0x0020
+#define STE_ISRACK_SOFTINTR 0x0040
+#define STE_ISRACK_STATS_OFLOW 0x0080
+#define STE_ISRACK_LINKEVENT 0x0100
+#define STE_ISRACK_TX_DMADONE 0x0200
+#define STE_ISRACK_RX_DMADONE 0x0400
+
+#define STE_IMR_HOSTERR 0x0002
+#define STE_IMR_TX_DONE 0x0004
+#define STE_IMR_MACCTL_FRAME 0x0008
+#define STE_IMR_RX_DONE 0x0010
+#define STE_IMR_RX_EARLY 0x0020
+#define STE_IMR_SOFTINTR 0x0040
+#define STE_IMR_STATS_OFLOW 0x0080
+#define STE_IMR_LINKEVENT 0x0100
+#define STE_IMR_TX_DMADONE 0x0200
+#define STE_IMR_RX_DMADONE 0x0400
+
+#define STE_INTRS \
+ (STE_IMR_RX_DMADONE|STE_IMR_TX_DMADONE|STE_IMR_STATS_OFLOW| \
+ STE_IMR_TX_DONE|STE_IMR_HOSTERR|STE_IMR_RX_EARLY)
+
+#define STE_ISR_INTLATCH 0x0001
+#define STE_ISR_HOSTERR 0x0002
+#define STE_ISR_TX_DONE 0x0004
+#define STE_ISR_MACCTL_FRAME 0x0008
+#define STE_ISR_RX_DONE 0x0010
+#define STE_ISR_RX_EARLY 0x0020
+#define STE_ISR_SOFTINTR 0x0040
+#define STE_ISR_STATS_OFLOW 0x0080
+#define STE_ISR_LINKEVENT 0x0100
+#define STE_ISR_TX_DMADONE 0x0200
+#define STE_ISR_RX_DMADONE 0x0400
+
+/*
+ * Note: the Sundance manual gives the impression that the's
+ * only one 32-bit MACCTL register. In fact, there are two
+ * 16-bit registers side by side, and you have to access them
+ * separately.
+ */
+#define STE_MACCTL0_IPG 0x0003
+#define STE_MACCTL0_FULLDUPLEX 0x0020
+#define STE_MACCTL0_RX_GIANTS 0x0040
+#define STE_MACCTL0_FLOWCTL_ENABLE 0x0100
+#define STE_MACCTL0_RX_FCS 0x0200
+#define STE_MACCTL0_FIFOLOOPBK 0x0400
+#define STE_MACCTL0_MACLOOPBK 0x0800
+
+#define STE_MACCTL1_COLLDETECT 0x0001
+#define STE_MACCTL1_CARRSENSE 0x0002
+#define STE_MACCTL1_TX_BUSY 0x0004
+#define STE_MACCTL1_TX_ERROR 0x0008
+#define STE_MACCTL1_STATS_ENABLE 0x0020
+#define STE_MACCTL1_STATS_DISABLE 0x0040
+#define STE_MACCTL1_STATS_ENABLED 0x0080
+#define STE_MACCTL1_TX_ENABLE 0x0100
+#define STE_MACCTL1_TX_DISABLE 0x0200
+#define STE_MACCTL1_TX_ENABLED 0x0400
+#define STE_MACCTL1_RX_ENABLE 0x0800
+#define STE_MACCTL1_RX_DISABLE 0x1000
+#define STE_MACCTL1_RX_ENABLED 0x2000
+#define STE_MACCTL1_PAUSED 0x4000
+
+#define STE_IPG_96BT 0x00000000
+#define STE_IPG_128BT 0x00000001
+#define STE_IPG_224BT 0x00000002
+#define STE_IPG_544BT 0x00000003
+
+#define STE_RXMODE_UNICAST 0x01
+#define STE_RXMODE_ALLMULTI 0x02
+#define STE_RXMODE_BROADCAST 0x04
+#define STE_RXMODE_PROMISC 0x08
+#define STE_RXMODE_MULTIHASH 0x10
+#define STE_RXMODE_ALLIPMULTI 0x20
+
+#define STE_PHYCTL_MCLK 0x01
+#define STE_PHYCTL_MDATA 0x02
+#define STE_PHYCTL_MDIR 0x04
+#define STE_PHYCTL_CLK25_DISABLE 0x08
+#define STE_PHYCTL_DUPLEXPOLARITY 0x10
+#define STE_PHYCTL_DUPLEXSTAT 0x20
+#define STE_PHYCTL_SPEEDSTAT 0x40
+#define STE_PHYCTL_LINKSTAT 0x80
+
+/*
+ * EEPROM offsets.
+ */
+#define STE_EEADDR_CONFIGPARM 0x00
+#define STE_EEADDR_ASICCTL 0x02
+#define STE_EEADDR_SUBSYS_ID 0x04
+#define STE_EEADDR_SUBVEN_ID 0x08
+
+#define STE_EEADDR_NODE0 0x10
+#define STE_EEADDR_NODE1 0x12
+#define STE_EEADDR_NODE2 0x14
+
+/* PCI registers */
+#define STE_PCI_VENDOR_ID 0x00
+#define STE_PCI_DEVICE_ID 0x02
+#define STE_PCI_COMMAND 0x04
+#define STE_PCI_STATUS 0x06
+#define STE_PCI_CLASSCODE 0x09
+#define STE_PCI_LATENCY_TIMER 0x0D
+#define STE_PCI_HEADER_TYPE 0x0E
+#define STE_PCI_LOIO 0x10
+#define STE_PCI_LOMEM 0x14
+#define STE_PCI_BIOSROM 0x30
+#define STE_PCI_INTLINE 0x3C
+#define STE_PCI_INTPIN 0x3D
+#define STE_PCI_MINGNT 0x3E
+#define STE_PCI_MINLAT 0x0F
+
+#define STE_PCI_CAPID 0x50 /* 8 bits */
+#define STE_PCI_NEXTPTR 0x51 /* 8 bits */
+#define STE_PCI_PWRMGMTCAP 0x52 /* 16 bits */
+#define STE_PCI_PWRMGMTCTRL 0x54 /* 16 bits */
+
+#define STE_PSTATE_MASK 0x0003
+#define STE_PSTATE_D0 0x0000
+#define STE_PSTATE_D1 0x0002
+#define STE_PSTATE_D2 0x0002
+#define STE_PSTATE_D3 0x0003
+#define STE_PME_EN 0x0010
+#define STE_PME_STATUS 0x8000
+
+
+struct ste_stats {
+ u_int32_t ste_rx_bytes;
+ u_int32_t ste_tx_bytes;
+ u_int16_t ste_tx_frames;
+ u_int16_t ste_rx_frames;
+ u_int8_t ste_carrsense_errs;
+ u_int8_t ste_late_colls;
+ u_int8_t ste_multi_colls;
+ u_int8_t ste_single_colls;
+ u_int8_t ste_tx_frames_defered;
+ u_int8_t ste_rx_lost_frames;
+ u_int8_t ste_tx_excess_defers;
+ u_int8_t ste_tx_abort_excess_colls;
+ u_int8_t ste_tx_bcast_frames;
+ u_int8_t ste_rx_bcast_frames;
+ u_int8_t ste_tx_mcast_frames;
+ u_int8_t ste_rx_mcast_frames;
+};
+
+struct ste_frag {
+ u_int32_t ste_addr;
+ u_int32_t ste_len;
+};
+
+#define STE_FRAG_LAST 0x80000000
+#define STE_FRAG_LEN 0x00001FFF
+
+#define STE_MAXFRAGS 63
+
+struct ste_desc {
+ u_int32_t ste_next;
+ u_int32_t ste_ctl;
+ struct ste_frag ste_frags[STE_MAXFRAGS];
+};
+
+struct ste_desc_onefrag {
+ u_int32_t ste_next;
+ u_int32_t ste_status;
+ struct ste_frag ste_frag;
+};
+
+#define STE_TXCTL_WORDALIGN 0x00000003
+#define STE_TXCTL_FRAMEID 0x000003FC
+#define STE_TXCTL_NOCRC 0x00002000
+#define STE_TXCTL_TXINTR 0x00008000
+#define STE_TXCTL_DMADONE 0x00010000
+#define STE_TXCTL_DMAINTR 0x80000000
+
+#define STE_RXSTAT_FRAMELEN 0x00001FFF
+#define STE_RXSTAT_FRAME_ERR 0x00004000
+#define STE_RXSTAT_DMADONE 0x00008000
+#define STE_RXSTAT_FIFO_OFLOW 0x00010000
+#define STE_RXSTAT_RUNT 0x00020000
+#define STE_RXSTAT_ALIGNERR 0x00040000
+#define STE_RXSTAT_CRCERR 0x00080000
+#define STE_RXSTAT_GIANT 0x00100000
+#define STE_RXSTAT_DRIBBLEBITS 0x00800000
+#define STE_RXSTAT_DMA_OFLOW 0x01000000
+#define STE_RXATAT_ONEBUF 0x10000000
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->ste_btag, sc->ste_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->ste_btag, sc->ste_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->ste_btag, sc->ste_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->ste_btag, sc->ste_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->ste_btag, sc->ste_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->ste_btag, sc->ste_bhandle, reg)
+
+#define STE_TIMEOUT 1000
+#define STE_MIN_FRAMELEN 60
+#define STE_PACKET_SIZE 1536
+#define ETHER_ALIGN 2
+#define STE_RX_LIST_CNT 128
+#define STE_TX_LIST_CNT 256
+#define STE_INC(x, y) (x) = (x + 1) % y
+
+struct ste_type {
+ u_int16_t ste_vid;
+ u_int16_t ste_did;
+ char *ste_name;
+};
+
+struct ste_list_data {
+ struct ste_desc_onefrag ste_rx_list[STE_RX_LIST_CNT];
+ struct ste_desc ste_tx_list[STE_TX_LIST_CNT];
+ u_int8_t ste_pad[STE_MIN_FRAMELEN];
+};
+
+struct ste_chain {
+ struct ste_desc *ste_ptr;
+ struct mbuf *ste_mbuf;
+ struct ste_chain *ste_next;
+ struct ste_chain *ste_prev;
+ u_int32_t ste_phys;
+};
+
+struct ste_chain_onefrag {
+ struct ste_desc_onefrag *ste_ptr;
+ struct mbuf *ste_mbuf;
+ struct ste_chain_onefrag *ste_next;
+};
+
+struct ste_chain_data {
+ struct ste_chain_onefrag ste_rx_chain[STE_RX_LIST_CNT];
+ struct ste_chain ste_tx_chain[STE_TX_LIST_CNT];
+ struct ste_chain_onefrag *ste_rx_head;
+
+ int ste_tx_prod;
+ int ste_tx_cons;
+ int ste_tx_cnt;
+};
+
+struct ste_softc {
+ struct arpcom arpcom;
+ bus_space_tag_t ste_btag;
+ bus_space_handle_t ste_bhandle;
+ struct resource *ste_res;
+ struct resource *ste_irq;
+ void *ste_intrhand;
+ struct ste_type *ste_info;
+ device_t ste_miibus;
+ int ste_unit;
+ int ste_tx_thresh;
+ u_int8_t ste_link;
+ int ste_if_flags;
+ struct ste_list_data *ste_ldata;
+ struct ste_chain_data ste_cdata;
+ struct callout_handle ste_stat_ch;
+ struct mtx ste_mtx;
+};
+
+#define STE_LOCK(_sc) mtx_lock(&(_sc)->ste_mtx)
+#define STE_UNLOCK(_sc) mtx_unlock(&(_sc)->ste_mtx)
+
+struct ste_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define STE_MII_STARTDELIM 0x01
+#define STE_MII_READOP 0x02
+#define STE_MII_WRITEOP 0x01
+#define STE_MII_TURNAROUND 0x02
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_ti.c b/sys/pci/if_ti.c
new file mode 100644
index 0000000..a4ea930
--- /dev/null
+++ b/sys/pci/if_ti.c
@@ -0,0 +1,3628 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Alteon Networks Tigon PCI gigabit ethernet driver for FreeBSD.
+ * Manuals, sample driver and firmware source kits are available
+ * from http://www.alteon.com/support/openkits.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The Alteon Networks Tigon chip contains an embedded R4000 CPU,
+ * gigabit MAC, dual DMA channels and a PCI interface unit. NICs
+ * using the Tigon may have anywhere from 512K to 2MB of SRAM. The
+ * Tigon supports hardware IP, TCP and UCP checksumming, multicast
+ * filtering and jumbo (9014 byte) frames. The hardware is largely
+ * controlled by firmware, which must be loaded into the NIC during
+ * initialization.
+ *
+ * The Tigon 2 contains 2 R4000 CPUs and requires a newer firmware
+ * revision, which supports new features such as extended commands,
+ * extended jumbo receive ring desciptors and a mini receive ring.
+ *
+ * Alteon Networks is to be commended for releasing such a vast amount
+ * of development material for the Tigon NIC without requiring an NDA
+ * (although they really should have done it a long time ago). With
+ * any luck, the other vendors will finally wise up and follow Alteon's
+ * stellar example.
+ *
+ * The firmware for the Tigon 1 and 2 NICs is compiled directly into
+ * this driver by #including it as a C header file. This bloats the
+ * driver somewhat, but it's the easiest method considering that the
+ * driver code and firmware code need to be kept in sync. The source
+ * for the firmware is not provided with the FreeBSD distribution since
+ * compiling it requires a GNU toolchain targeted for mips-sgi-irix5.3.
+ *
+ * The following people deserve special thanks:
+ * - Terry Murphy of 3Com, for providing a 3c985 Tigon 1 board
+ * for testing
+ * - Raymond Lee of Netgear, for providing a pair of Netgear
+ * GA620 Tigon 2 boards for testing
+ * - Ulf Zimmermann, for bringing the GA260 to my attention and
+ * convincing me to write this driver.
+ * - Andrew Gallatin for providing FreeBSD/Alpha support.
+ */
+
+#include "opt_ti.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/queue.h>
+#include <sys/conf.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <net/bpf.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+/* #define TI_PRIVATE_JUMBOS */
+
+#if !defined(TI_PRIVATE_JUMBOS)
+#include <sys/sockio.h>
+#include <sys/uio.h>
+#include <sys/lock.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_map.h>
+#include <vm/vm_param.h>
+#include <vm/vm_pageout.h>
+#include <sys/vmmeter.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_kern.h>
+#include <sys/proc.h>
+#include <sys/jumbo.h>
+#endif /* !TI_PRIVATE_JUMBOS */
+#include <sys/vnode.h> /* for vfindev, vgone */
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <sys/tiio.h>
+#include <pci/if_tireg.h>
+#include <pci/ti_fw.h>
+#include <pci/ti_fw2.h>
+
+#define TI_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_IP_FRAGS)
+/*
+ * We can only turn on header splitting if we're using extended receive
+ * BDs.
+ */
+#if defined(TI_JUMBO_HDRSPLIT) && defined(TI_PRIVATE_JUMBOS)
+#error "options TI_JUMBO_HDRSPLIT and TI_PRIVATE_JUMBOS are mutually exclusive"
+#endif /* TI_JUMBO_HDRSPLIT && TI_JUMBO_HDRSPLIT */
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+struct ti_softc *tis[8];
+
+typedef enum {
+ TI_SWAP_HTON,
+ TI_SWAP_NTOH
+} ti_swap_type;
+
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+
+static struct ti_type ti_devs[] = {
+ { ALT_VENDORID, ALT_DEVICEID_ACENIC,
+ "Alteon AceNIC 1000baseSX Gigabit Ethernet" },
+ { ALT_VENDORID, ALT_DEVICEID_ACENIC_COPPER,
+ "Alteon AceNIC 1000baseT Gigabit Ethernet" },
+ { TC_VENDORID, TC_DEVICEID_3C985,
+ "3Com 3c985-SX Gigabit Ethernet" },
+ { NG_VENDORID, NG_DEVICEID_GA620,
+ "Netgear GA620 1000baseSX Gigabit Ethernet" },
+ { NG_VENDORID, NG_DEVICEID_GA620T,
+ "Netgear GA620 1000baseT Gigabit Ethernet" },
+ { SGI_VENDORID, SGI_DEVICEID_TIGON,
+ "Silicon Graphics Gigabit Ethernet" },
+ { DEC_VENDORID, DEC_DEVICEID_FARALLON_PN9000SX,
+ "Farallon PN9000SX Gigabit Ethernet" },
+ { 0, 0, NULL }
+};
+
+#define TI_CDEV_MAJOR 153
+
+static d_open_t ti_open;
+static d_close_t ti_close;
+static d_ioctl_t ti_ioctl2;
+
+static struct cdevsw ti_cdevsw = {
+ /* open */ ti_open,
+ /* close */ ti_close,
+ /* read */ NULL,
+ /* write */ NULL,
+ /* ioctl */ ti_ioctl2,
+ /* poll */ seltrue,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "ti",
+ /* maj */ TI_CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+};
+
+static int ti_probe (device_t);
+static int ti_attach (device_t);
+static int ti_detach (device_t);
+static void ti_txeof (struct ti_softc *);
+static void ti_rxeof (struct ti_softc *);
+
+static void ti_stats_update (struct ti_softc *);
+static int ti_encap (struct ti_softc *, struct mbuf *, u_int32_t *);
+
+static void ti_intr (void *);
+static void ti_start (struct ifnet *);
+static int ti_ioctl (struct ifnet *, u_long, caddr_t);
+static void ti_init (void *);
+static void ti_init2 (struct ti_softc *);
+static void ti_stop (struct ti_softc *);
+static void ti_watchdog (struct ifnet *);
+static void ti_shutdown (device_t);
+static int ti_ifmedia_upd (struct ifnet *);
+static void ti_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static u_int32_t ti_eeprom_putbyte (struct ti_softc *, int);
+static u_int8_t ti_eeprom_getbyte (struct ti_softc *, int, u_int8_t *);
+static int ti_read_eeprom (struct ti_softc *, caddr_t, int, int);
+
+static void ti_add_mcast (struct ti_softc *, struct ether_addr *);
+static void ti_del_mcast (struct ti_softc *, struct ether_addr *);
+static void ti_setmulti (struct ti_softc *);
+
+static void ti_mem (struct ti_softc *, u_int32_t,
+ u_int32_t, caddr_t);
+static int ti_copy_mem (struct ti_softc *, u_int32_t,
+ u_int32_t, caddr_t, int, int);
+static int ti_copy_scratch (struct ti_softc *, u_int32_t,
+ u_int32_t, caddr_t, int, int, int);
+static int ti_bcopy_swap (const void *, void *, size_t,
+ ti_swap_type);
+static void ti_loadfw (struct ti_softc *);
+static void ti_cmd (struct ti_softc *, struct ti_cmd_desc *);
+static void ti_cmd_ext (struct ti_softc *, struct ti_cmd_desc *,
+ caddr_t, int);
+static void ti_handle_events (struct ti_softc *);
+#ifdef TI_PRIVATE_JUMBOS
+static int ti_alloc_jumbo_mem (struct ti_softc *);
+static void *ti_jalloc (struct ti_softc *);
+static void ti_jfree (void *, void *);
+#endif /* TI_PRIVATE_JUMBOS */
+static int ti_newbuf_std (struct ti_softc *, int, struct mbuf *);
+static int ti_newbuf_mini (struct ti_softc *, int, struct mbuf *);
+static int ti_newbuf_jumbo (struct ti_softc *, int, struct mbuf *);
+static int ti_init_rx_ring_std (struct ti_softc *);
+static void ti_free_rx_ring_std (struct ti_softc *);
+static int ti_init_rx_ring_jumbo (struct ti_softc *);
+static void ti_free_rx_ring_jumbo (struct ti_softc *);
+static int ti_init_rx_ring_mini (struct ti_softc *);
+static void ti_free_rx_ring_mini (struct ti_softc *);
+static void ti_free_tx_ring (struct ti_softc *);
+static int ti_init_tx_ring (struct ti_softc *);
+
+static int ti_64bitslot_war (struct ti_softc *);
+static int ti_chipinit (struct ti_softc *);
+static int ti_gibinit (struct ti_softc *);
+
+#ifdef TI_JUMBO_HDRSPLIT
+static __inline void ti_hdr_split (struct mbuf *top, int hdr_len,
+ int pkt_len, int idx);
+#endif /* TI_JUMBO_HDRSPLIT */
+
+static device_method_t ti_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ti_probe),
+ DEVMETHOD(device_attach, ti_attach),
+ DEVMETHOD(device_detach, ti_detach),
+ DEVMETHOD(device_shutdown, ti_shutdown),
+ { 0, 0 }
+};
+
+static driver_t ti_driver = {
+ "ti",
+ ti_methods,
+ sizeof(struct ti_softc)
+};
+
+static devclass_t ti_devclass;
+
+DRIVER_MODULE(if_ti, pci, ti_driver, ti_devclass, 0, 0);
+
+/* List of Tigon softcs */
+static STAILQ_HEAD(ti_softc_list, ti_softc) ti_sc_list;
+
+static struct ti_softc *
+ti_lookup_softc(int unit)
+{
+ struct ti_softc *sc;
+ for (sc = STAILQ_FIRST(&ti_sc_list); sc != NULL;
+ sc = STAILQ_NEXT(sc, ti_links))
+ if (sc->ti_unit == unit)
+ return(sc);
+ return(NULL);
+}
+
+/*
+ * Send an instruction or address to the EEPROM, check for ACK.
+ */
+static u_int32_t ti_eeprom_putbyte(sc, byte)
+ struct ti_softc *sc;
+ int byte;
+{
+ register int i, ack = 0;
+
+ /*
+ * Make sure we're in TX mode.
+ */
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN);
+
+ /*
+ * Feed in each bit and stobe the clock.
+ */
+ for (i = 0x80; i; i >>= 1) {
+ if (byte & i) {
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT);
+ } else {
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT);
+ }
+ DELAY(1);
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+ DELAY(1);
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+ }
+
+ /*
+ * Turn off TX mode.
+ */
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN);
+
+ /*
+ * Check for ack.
+ */
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+ ack = CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN;
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+
+ return(ack);
+}
+
+/*
+ * Read a byte of data stored in the EEPROM at address 'addr.'
+ * We have to send two address bytes since the EEPROM can hold
+ * more than 256 bytes of data.
+ */
+static u_int8_t ti_eeprom_getbyte(sc, addr, dest)
+ struct ti_softc *sc;
+ int addr;
+ u_int8_t *dest;
+{
+ register int i;
+ u_int8_t byte = 0;
+
+ EEPROM_START;
+
+ /*
+ * Send write control code to EEPROM.
+ */
+ if (ti_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) {
+ printf("ti%d: failed to send write command, status: %x\n",
+ sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL));
+ return(1);
+ }
+
+ /*
+ * Send first byte of address of byte we want to read.
+ */
+ if (ti_eeprom_putbyte(sc, (addr >> 8) & 0xFF)) {
+ printf("ti%d: failed to send address, status: %x\n",
+ sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL));
+ return(1);
+ }
+ /*
+ * Send second byte address of byte we want to read.
+ */
+ if (ti_eeprom_putbyte(sc, addr & 0xFF)) {
+ printf("ti%d: failed to send address, status: %x\n",
+ sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL));
+ return(1);
+ }
+
+ EEPROM_STOP;
+ EEPROM_START;
+ /*
+ * Send read control code to EEPROM.
+ */
+ if (ti_eeprom_putbyte(sc, EEPROM_CTL_READ)) {
+ printf("ti%d: failed to send read command, status: %x\n",
+ sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL));
+ return(1);
+ }
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN);
+ for (i = 0x80; i; i >>= 1) {
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+ DELAY(1);
+ if (CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN)
+ byte |= i;
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK);
+ DELAY(1);
+ }
+
+ EEPROM_STOP;
+
+ /*
+ * No ACK generated for read, so just return byte.
+ */
+
+ *dest = byte;
+
+ return(0);
+}
+
+/*
+ * Read a sequence of bytes from the EEPROM.
+ */
+static int ti_read_eeprom(sc, dest, off, cnt)
+ struct ti_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+{
+ int err = 0, i;
+ u_int8_t byte = 0;
+
+ for (i = 0; i < cnt; i++) {
+ err = ti_eeprom_getbyte(sc, off + i, &byte);
+ if (err)
+ break;
+ *(dest + i) = byte;
+ }
+
+ return(err ? 1 : 0);
+}
+
+/*
+ * NIC memory access function. Can be used to either clear a section
+ * of NIC local memory or (if buf is non-NULL) copy data into it.
+ */
+static void ti_mem(sc, addr, len, buf)
+ struct ti_softc *sc;
+ u_int32_t addr, len;
+ caddr_t buf;
+{
+ int segptr, segsize, cnt;
+ caddr_t ti_winbase, ptr;
+
+ segptr = addr;
+ cnt = len;
+ ti_winbase = (caddr_t)(sc->ti_vhandle + TI_WINDOW);
+ ptr = buf;
+
+ while(cnt) {
+ if (cnt < TI_WINLEN)
+ segsize = cnt;
+ else
+ segsize = TI_WINLEN - (segptr % TI_WINLEN);
+ CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1)));
+ if (buf == NULL)
+ bzero((char *)ti_winbase + (segptr &
+ (TI_WINLEN - 1)), segsize);
+ else {
+ bcopy((char *)ptr, (char *)ti_winbase +
+ (segptr & (TI_WINLEN - 1)), segsize);
+ ptr += segsize;
+ }
+ segptr += segsize;
+ cnt -= segsize;
+ }
+
+ return;
+}
+
+static int
+ti_copy_mem(sc, tigon_addr, len, buf, useraddr, readdata)
+ struct ti_softc *sc;
+ u_int32_t tigon_addr, len;
+ caddr_t buf;
+ int useraddr, readdata;
+{
+ int segptr, segsize, cnt;
+ caddr_t ptr;
+ u_int32_t origwin;
+ u_int8_t tmparray[TI_WINLEN], tmparray2[TI_WINLEN];
+ int resid, segresid;
+ int first_pass;
+
+ /*
+ * At the moment, we don't handle non-aligned cases, we just bail.
+ * If this proves to be a problem, it will be fixed.
+ */
+ if ((readdata == 0)
+ && (tigon_addr & 0x3)) {
+ printf("ti%d: ti_copy_mem: tigon address %#x isn't "
+ "word-aligned\n", sc->ti_unit, tigon_addr);
+ printf("ti%d: ti_copy_mem: unaligned writes aren't yet "
+ "supported\n", sc->ti_unit);
+ return(EINVAL);
+ }
+
+ segptr = tigon_addr & ~0x3;
+ segresid = tigon_addr - segptr;
+
+ /*
+ * This is the non-aligned amount left over that we'll need to
+ * copy.
+ */
+ resid = len & 0x3;
+
+ /* Add in the left over amount at the front of the buffer */
+ resid += segresid;
+
+ cnt = len & ~0x3;
+ /*
+ * If resid + segresid is >= 4, add multiples of 4 to the count and
+ * decrease the residual by that much.
+ */
+ cnt += resid & ~0x3;
+ resid -= resid & ~0x3;
+
+ ptr = buf;
+
+ first_pass = 1;
+
+ /*
+ * Make sure we aren't interrupted while we're changing the window
+ * pointer.
+ */
+ TI_LOCK(sc);
+
+ /*
+ * Save the old window base value.
+ */
+ origwin = CSR_READ_4(sc, TI_WINBASE);
+
+ while(cnt) {
+ bus_size_t ti_offset;
+
+ if (cnt < TI_WINLEN)
+ segsize = cnt;
+ else
+ segsize = TI_WINLEN - (segptr % TI_WINLEN);
+ CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1)));
+
+ ti_offset = TI_WINDOW + (segptr & (TI_WINLEN -1));
+
+ if (readdata) {
+
+ bus_space_read_region_4(sc->ti_btag,
+ sc->ti_bhandle, ti_offset,
+ (u_int32_t *)tmparray,
+ segsize >> 2);
+ if (useraddr) {
+ /*
+ * Yeah, this is a little on the kludgy
+ * side, but at least this code is only
+ * used for debugging.
+ */
+ ti_bcopy_swap(tmparray, tmparray2, segsize,
+ TI_SWAP_NTOH);
+
+ if (first_pass) {
+ copyout(&tmparray2[segresid], ptr,
+ segsize - segresid);
+ first_pass = 0;
+ } else
+ copyout(tmparray2, ptr, segsize);
+ } else {
+ if (first_pass) {
+
+ ti_bcopy_swap(tmparray, tmparray2,
+ segsize, TI_SWAP_NTOH);
+ bcopy(&tmparray2[segresid], ptr,
+ segsize - segresid);
+ first_pass = 0;
+ } else
+ ti_bcopy_swap(tmparray, ptr, segsize,
+ TI_SWAP_NTOH);
+ }
+
+ } else {
+ if (useraddr) {
+ copyin(ptr, tmparray2, segsize);
+ ti_bcopy_swap(tmparray2, tmparray, segsize,
+ TI_SWAP_HTON);
+ } else
+ ti_bcopy_swap(ptr, tmparray, segsize,
+ TI_SWAP_HTON);
+
+ bus_space_write_region_4(sc->ti_btag,
+ sc->ti_bhandle, ti_offset,
+ (u_int32_t *)tmparray,
+ segsize >> 2);
+ }
+ segptr += segsize;
+ ptr += segsize;
+ cnt -= segsize;
+ }
+
+ /*
+ * Handle leftover, non-word-aligned bytes.
+ */
+ if (resid != 0) {
+ u_int32_t tmpval, tmpval2;
+ bus_size_t ti_offset;
+
+ /*
+ * Set the segment pointer.
+ */
+ CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1)));
+
+ ti_offset = TI_WINDOW + (segptr & (TI_WINLEN - 1));
+
+ /*
+ * First, grab whatever is in our source/destination.
+ * We'll obviously need this for reads, but also for
+ * writes, since we'll be doing read/modify/write.
+ */
+ bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle,
+ ti_offset, &tmpval, 1);
+
+ /*
+ * Next, translate this from little-endian to big-endian
+ * (at least on i386 boxes).
+ */
+ tmpval2 = ntohl(tmpval);
+
+ if (readdata) {
+ /*
+ * If we're reading, just copy the leftover number
+ * of bytes from the host byte order buffer to
+ * the user's buffer.
+ */
+ if (useraddr)
+ copyout(&tmpval2, ptr, resid);
+ else
+ bcopy(&tmpval2, ptr, resid);
+ } else {
+ /*
+ * If we're writing, first copy the bytes to be
+ * written into the network byte order buffer,
+ * leaving the rest of the buffer with whatever was
+ * originally in there. Then, swap the bytes
+ * around into host order and write them out.
+ *
+ * XXX KDM the read side of this has been verified
+ * to work, but the write side of it has not been
+ * verified. So user beware.
+ */
+ if (useraddr)
+ copyin(ptr, &tmpval2, resid);
+ else
+ bcopy(ptr, &tmpval2, resid);
+
+ tmpval = htonl(tmpval2);
+
+ bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle,
+ ti_offset, &tmpval, 1);
+ }
+ }
+
+ CSR_WRITE_4(sc, TI_WINBASE, origwin);
+
+ TI_UNLOCK(sc);
+
+ return(0);
+}
+
+static int
+ti_copy_scratch(sc, tigon_addr, len, buf, useraddr, readdata, cpu)
+ struct ti_softc *sc;
+ u_int32_t tigon_addr, len;
+ caddr_t buf;
+ int useraddr, readdata;
+ int cpu;
+{
+ u_int32_t segptr;
+ int cnt;
+ u_int32_t tmpval, tmpval2;
+ caddr_t ptr;
+
+ /*
+ * At the moment, we don't handle non-aligned cases, we just bail.
+ * If this proves to be a problem, it will be fixed.
+ */
+ if (tigon_addr & 0x3) {
+ printf("ti%d: ti_copy_scratch: tigon address %#x isn't "
+ "word-aligned\n", sc->ti_unit, tigon_addr);
+ return(EINVAL);
+ }
+
+ if (len & 0x3) {
+ printf("ti%d: ti_copy_scratch: transfer length %d isn't "
+ "word-aligned\n", sc->ti_unit, len);
+ return(EINVAL);
+ }
+
+ segptr = tigon_addr;
+ cnt = len;
+ ptr = buf;
+
+ TI_LOCK(sc);
+
+ while (cnt) {
+ CSR_WRITE_4(sc, CPU_REG(TI_SRAM_ADDR, cpu), segptr);
+
+ if (readdata) {
+ tmpval2 = CSR_READ_4(sc, CPU_REG(TI_SRAM_DATA, cpu));
+
+ tmpval = ntohl(tmpval2);
+
+ /*
+ * Note: I've used this debugging interface
+ * extensively with Alteon's 12.3.15 firmware,
+ * compiled with GCC 2.7.2.1 and binutils 2.9.1.
+ *
+ * When you compile the firmware without
+ * optimization, which is necessary sometimes in
+ * order to properly step through it, you sometimes
+ * read out a bogus value of 0xc0017c instead of
+ * whatever was supposed to be in that scratchpad
+ * location. That value is on the stack somewhere,
+ * but I've never been able to figure out what was
+ * causing the problem.
+ *
+ * The address seems to pop up in random places,
+ * often not in the same place on two subsequent
+ * reads.
+ *
+ * In any case, the underlying data doesn't seem
+ * to be affected, just the value read out.
+ *
+ * KDM, 3/7/2000
+ */
+
+ if (tmpval2 == 0xc0017c)
+ printf("ti%d: found 0xc0017c at %#x "
+ "(tmpval2)\n", sc->ti_unit, segptr);
+
+ if (tmpval == 0xc0017c)
+ printf("ti%d: found 0xc0017c at %#x "
+ "(tmpval)\n", sc->ti_unit, segptr);
+
+ if (useraddr)
+ copyout(&tmpval, ptr, 4);
+ else
+ bcopy(&tmpval, ptr, 4);
+ } else {
+ if (useraddr)
+ copyin(ptr, &tmpval2, 4);
+ else
+ bcopy(ptr, &tmpval2, 4);
+
+ tmpval = htonl(tmpval2);
+
+ CSR_WRITE_4(sc, CPU_REG(TI_SRAM_DATA, cpu), tmpval);
+ }
+
+ cnt -= 4;
+ segptr += 4;
+ ptr += 4;
+ }
+
+ TI_UNLOCK(sc);
+
+ return(0);
+}
+
+static int
+ti_bcopy_swap(src, dst, len, swap_type)
+ const void *src;
+ void *dst;
+ size_t len;
+ ti_swap_type swap_type;
+{
+ const u_int8_t *tmpsrc;
+ u_int8_t *tmpdst;
+ size_t tmplen;
+
+ if (len & 0x3) {
+ printf("ti_bcopy_swap: length %d isn't 32-bit aligned\n",
+ len);
+ return(-1);
+ }
+
+ tmpsrc = src;
+ tmpdst = dst;
+ tmplen = len;
+
+ while (tmplen) {
+ if (swap_type == TI_SWAP_NTOH)
+ *(u_int32_t *)tmpdst =
+ ntohl(*(const u_int32_t *)tmpsrc);
+ else
+ *(u_int32_t *)tmpdst =
+ htonl(*(const u_int32_t *)tmpsrc);
+
+ tmpsrc += 4;
+ tmpdst += 4;
+ tmplen -= 4;
+ }
+
+ return(0);
+}
+
+/*
+ * Load firmware image into the NIC. Check that the firmware revision
+ * is acceptable and see if we want the firmware for the Tigon 1 or
+ * Tigon 2.
+ */
+static void ti_loadfw(sc)
+ struct ti_softc *sc;
+{
+ switch(sc->ti_hwrev) {
+ case TI_HWREV_TIGON:
+ if (tigonFwReleaseMajor != TI_FIRMWARE_MAJOR ||
+ tigonFwReleaseMinor != TI_FIRMWARE_MINOR ||
+ tigonFwReleaseFix != TI_FIRMWARE_FIX) {
+ printf("ti%d: firmware revision mismatch; want "
+ "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit,
+ TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR,
+ TI_FIRMWARE_FIX, tigonFwReleaseMajor,
+ tigonFwReleaseMinor, tigonFwReleaseFix);
+ return;
+ }
+ ti_mem(sc, tigonFwTextAddr, tigonFwTextLen,
+ (caddr_t)tigonFwText);
+ ti_mem(sc, tigonFwDataAddr, tigonFwDataLen,
+ (caddr_t)tigonFwData);
+ ti_mem(sc, tigonFwRodataAddr, tigonFwRodataLen,
+ (caddr_t)tigonFwRodata);
+ ti_mem(sc, tigonFwBssAddr, tigonFwBssLen, NULL);
+ ti_mem(sc, tigonFwSbssAddr, tigonFwSbssLen, NULL);
+ CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigonFwStartAddr);
+ break;
+ case TI_HWREV_TIGON_II:
+ if (tigon2FwReleaseMajor != TI_FIRMWARE_MAJOR ||
+ tigon2FwReleaseMinor != TI_FIRMWARE_MINOR ||
+ tigon2FwReleaseFix != TI_FIRMWARE_FIX) {
+ printf("ti%d: firmware revision mismatch; want "
+ "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit,
+ TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR,
+ TI_FIRMWARE_FIX, tigon2FwReleaseMajor,
+ tigon2FwReleaseMinor, tigon2FwReleaseFix);
+ return;
+ }
+ ti_mem(sc, tigon2FwTextAddr, tigon2FwTextLen,
+ (caddr_t)tigon2FwText);
+ ti_mem(sc, tigon2FwDataAddr, tigon2FwDataLen,
+ (caddr_t)tigon2FwData);
+ ti_mem(sc, tigon2FwRodataAddr, tigon2FwRodataLen,
+ (caddr_t)tigon2FwRodata);
+ ti_mem(sc, tigon2FwBssAddr, tigon2FwBssLen, NULL);
+ ti_mem(sc, tigon2FwSbssAddr, tigon2FwSbssLen, NULL);
+ CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigon2FwStartAddr);
+ break;
+ default:
+ printf("ti%d: can't load firmware: unknown hardware rev\n",
+ sc->ti_unit);
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Send the NIC a command via the command ring.
+ */
+static void ti_cmd(sc, cmd)
+ struct ti_softc *sc;
+ struct ti_cmd_desc *cmd;
+{
+ u_int32_t index;
+
+ if (sc->ti_rdata->ti_cmd_ring == NULL)
+ return;
+
+ index = sc->ti_cmd_saved_prodidx;
+ CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd));
+ TI_INC(index, TI_CMD_RING_CNT);
+ CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index);
+ sc->ti_cmd_saved_prodidx = index;
+
+ return;
+}
+
+/*
+ * Send the NIC an extended command. The 'len' parameter specifies the
+ * number of command slots to include after the initial command.
+ */
+static void ti_cmd_ext(sc, cmd, arg, len)
+ struct ti_softc *sc;
+ struct ti_cmd_desc *cmd;
+ caddr_t arg;
+ int len;
+{
+ u_int32_t index;
+ register int i;
+
+ if (sc->ti_rdata->ti_cmd_ring == NULL)
+ return;
+
+ index = sc->ti_cmd_saved_prodidx;
+ CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd));
+ TI_INC(index, TI_CMD_RING_CNT);
+ for (i = 0; i < len; i++) {
+ CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4),
+ *(u_int32_t *)(&arg[i * 4]));
+ TI_INC(index, TI_CMD_RING_CNT);
+ }
+ CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index);
+ sc->ti_cmd_saved_prodidx = index;
+
+ return;
+}
+
+/*
+ * Handle events that have triggered interrupts.
+ */
+static void ti_handle_events(sc)
+ struct ti_softc *sc;
+{
+ struct ti_event_desc *e;
+
+ if (sc->ti_rdata->ti_event_ring == NULL)
+ return;
+
+ while (sc->ti_ev_saved_considx != sc->ti_ev_prodidx.ti_idx) {
+ e = &sc->ti_rdata->ti_event_ring[sc->ti_ev_saved_considx];
+ switch(e->ti_event) {
+ case TI_EV_LINKSTAT_CHANGED:
+ sc->ti_linkstat = e->ti_code;
+ if (e->ti_code == TI_EV_CODE_LINK_UP)
+ printf("ti%d: 10/100 link up\n", sc->ti_unit);
+ else if (e->ti_code == TI_EV_CODE_GIG_LINK_UP)
+ printf("ti%d: gigabit link up\n", sc->ti_unit);
+ else if (e->ti_code == TI_EV_CODE_LINK_DOWN)
+ printf("ti%d: link down\n", sc->ti_unit);
+ break;
+ case TI_EV_ERROR:
+ if (e->ti_code == TI_EV_CODE_ERR_INVAL_CMD)
+ printf("ti%d: invalid command\n", sc->ti_unit);
+ else if (e->ti_code == TI_EV_CODE_ERR_UNIMP_CMD)
+ printf("ti%d: unknown command\n", sc->ti_unit);
+ else if (e->ti_code == TI_EV_CODE_ERR_BADCFG)
+ printf("ti%d: bad config data\n", sc->ti_unit);
+ break;
+ case TI_EV_FIRMWARE_UP:
+ ti_init2(sc);
+ break;
+ case TI_EV_STATS_UPDATED:
+ ti_stats_update(sc);
+ break;
+ case TI_EV_RESET_JUMBO_RING:
+ case TI_EV_MCAST_UPDATED:
+ /* Who cares. */
+ break;
+ default:
+ printf("ti%d: unknown event: %d\n",
+ sc->ti_unit, e->ti_event);
+ break;
+ }
+ /* Advance the consumer index. */
+ TI_INC(sc->ti_ev_saved_considx, TI_EVENT_RING_CNT);
+ CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, sc->ti_ev_saved_considx);
+ }
+
+ return;
+}
+
+#ifdef TI_PRIVATE_JUMBOS
+
+/*
+ * Memory management for the jumbo receive ring is a pain in the
+ * butt. We need to allocate at least 9018 bytes of space per frame,
+ * _and_ it has to be contiguous (unless you use the extended
+ * jumbo descriptor format). Using malloc() all the time won't
+ * work: malloc() allocates memory in powers of two, which means we
+ * would end up wasting a considerable amount of space by allocating
+ * 9K chunks. We don't have a jumbo mbuf cluster pool. Thus, we have
+ * to do our own memory management.
+ *
+ * The driver needs to allocate a contiguous chunk of memory at boot
+ * time. We then chop this up ourselves into 9K pieces and use them
+ * as external mbuf storage.
+ *
+ * One issue here is how much memory to allocate. The jumbo ring has
+ * 256 slots in it, but at 9K per slot than can consume over 2MB of
+ * RAM. This is a bit much, especially considering we also need
+ * RAM for the standard ring and mini ring (on the Tigon 2). To
+ * save space, we only actually allocate enough memory for 64 slots
+ * by default, which works out to between 500 and 600K. This can
+ * be tuned by changing a #define in if_tireg.h.
+ */
+
+static int ti_alloc_jumbo_mem(sc)
+ struct ti_softc *sc;
+{
+ caddr_t ptr;
+ register int i;
+ struct ti_jpool_entry *entry;
+
+ /* Grab a big chunk o' storage. */
+ sc->ti_cdata.ti_jumbo_buf = contigmalloc(TI_JMEM, M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->ti_cdata.ti_jumbo_buf == NULL) {
+ printf("ti%d: no memory for jumbo buffers!\n", sc->ti_unit);
+ return(ENOBUFS);
+ }
+
+ SLIST_INIT(&sc->ti_jfree_listhead);
+ SLIST_INIT(&sc->ti_jinuse_listhead);
+
+ /*
+ * Now divide it up into 9K pieces and save the addresses
+ * in an array.
+ */
+ ptr = sc->ti_cdata.ti_jumbo_buf;
+ for (i = 0; i < TI_JSLOTS; i++) {
+ sc->ti_cdata.ti_jslots[i] = ptr;
+ ptr += TI_JLEN;
+ entry = malloc(sizeof(struct ti_jpool_entry),
+ M_DEVBUF, M_NOWAIT);
+ if (entry == NULL) {
+ contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM,
+ M_DEVBUF);
+ sc->ti_cdata.ti_jumbo_buf = NULL;
+ printf("ti%d: no memory for jumbo "
+ "buffer queue!\n", sc->ti_unit);
+ return(ENOBUFS);
+ }
+ entry->slot = i;
+ SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries);
+ }
+
+ return(0);
+}
+
+/*
+ * Allocate a jumbo buffer.
+ */
+static void *ti_jalloc(sc)
+ struct ti_softc *sc;
+{
+ struct ti_jpool_entry *entry;
+
+ entry = SLIST_FIRST(&sc->ti_jfree_listhead);
+
+ if (entry == NULL) {
+ printf("ti%d: no free jumbo buffers\n", sc->ti_unit);
+ return(NULL);
+ }
+
+ SLIST_REMOVE_HEAD(&sc->ti_jfree_listhead, jpool_entries);
+ SLIST_INSERT_HEAD(&sc->ti_jinuse_listhead, entry, jpool_entries);
+ return(sc->ti_cdata.ti_jslots[entry->slot]);
+}
+
+/*
+ * Release a jumbo buffer.
+ */
+static void ti_jfree(buf, args)
+ void *buf;
+ void *args;
+{
+ struct ti_softc *sc;
+ int i;
+ struct ti_jpool_entry *entry;
+
+ /* Extract the softc struct pointer. */
+ sc = (struct ti_softc *)args;
+
+ if (sc == NULL)
+ panic("ti_jfree: didn't get softc pointer!");
+
+ /* calculate the slot this buffer belongs to */
+ i = ((vm_offset_t)buf
+ - (vm_offset_t)sc->ti_cdata.ti_jumbo_buf) / TI_JLEN;
+
+ if ((i < 0) || (i >= TI_JSLOTS))
+ panic("ti_jfree: asked to free buffer that we don't manage!");
+
+ entry = SLIST_FIRST(&sc->ti_jinuse_listhead);
+ if (entry == NULL)
+ panic("ti_jfree: buffer not in use!");
+ entry->slot = i;
+ SLIST_REMOVE_HEAD(&sc->ti_jinuse_listhead, jpool_entries);
+ SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries);
+
+ return;
+}
+
+#endif /* TI_PRIVATE_JUMBOS */
+
+/*
+ * Intialize a standard receive ring descriptor.
+ */
+static int ti_newbuf_std(sc, i, m)
+ struct ti_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct ti_rx_desc *r;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+ sc->ti_cdata.ti_rx_std_chain[i] = m_new;
+ r = &sc->ti_rdata->ti_rx_std_ring[i];
+ TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t));
+ r->ti_type = TI_BDTYPE_RECV_BD;
+ r->ti_flags = 0;
+ if (sc->arpcom.ac_if.if_hwassist)
+ r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
+ r->ti_len = m_new->m_len;
+ r->ti_idx = i;
+
+ return(0);
+}
+
+/*
+ * Intialize a mini receive ring descriptor. This only applies to
+ * the Tigon 2.
+ */
+static int ti_newbuf_mini(sc, i, m)
+ struct ti_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct ti_rx_desc *r;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MHLEN;
+ } else {
+ m_new = m;
+ m_new->m_data = m_new->m_pktdat;
+ m_new->m_len = m_new->m_pkthdr.len = MHLEN;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+ r = &sc->ti_rdata->ti_rx_mini_ring[i];
+ sc->ti_cdata.ti_rx_mini_chain[i] = m_new;
+ TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t));
+ r->ti_type = TI_BDTYPE_RECV_BD;
+ r->ti_flags = TI_BDFLAG_MINI_RING;
+ if (sc->arpcom.ac_if.if_hwassist)
+ r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
+ r->ti_len = m_new->m_len;
+ r->ti_idx = i;
+
+ return(0);
+}
+
+#ifdef TI_PRIVATE_JUMBOS
+
+/*
+ * Initialize a jumbo receive ring descriptor. This allocates
+ * a jumbo buffer from the pool managed internally by the driver.
+ */
+static int ti_newbuf_jumbo(sc, i, m)
+ struct ti_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct ti_rx_desc *r;
+
+ if (m == NULL) {
+ caddr_t *buf = NULL;
+
+ /* Allocate the mbuf. */
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ return(ENOBUFS);
+ }
+
+ /* Allocate the jumbo buffer */
+ buf = ti_jalloc(sc);
+ if (buf == NULL) {
+ m_freem(m_new);
+ printf("ti%d: jumbo allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ return(ENOBUFS);
+ }
+
+ /* Attach the buffer to the mbuf. */
+ m_new->m_data = (void *) buf;
+ m_new->m_len = m_new->m_pkthdr.len = TI_JUMBO_FRAMELEN;
+ MEXTADD(m_new, buf, TI_JUMBO_FRAMELEN, ti_jfree,
+ (struct ti_softc *)sc, 0, EXT_NET_DRV);
+ } else {
+ m_new = m;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ m_new->m_ext.ext_size = TI_JUMBO_FRAMELEN;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+ /* Set up the descriptor. */
+ r = &sc->ti_rdata->ti_rx_jumbo_ring[i];
+ sc->ti_cdata.ti_rx_jumbo_chain[i] = m_new;
+ TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t));
+ r->ti_type = TI_BDTYPE_RECV_JUMBO_BD;
+ r->ti_flags = TI_BDFLAG_JUMBO_RING;
+ if (sc->arpcom.ac_if.if_hwassist)
+ r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
+ r->ti_len = m_new->m_len;
+ r->ti_idx = i;
+
+ return(0);
+}
+
+#else
+#include <vm/vm_page.h>
+
+#if (PAGE_SIZE == 4096)
+#define NPAYLOAD 2
+#else
+#define NPAYLOAD 1
+#endif
+
+#define TCP_HDR_LEN (52 + sizeof(struct ether_header))
+#define UDP_HDR_LEN (28 + sizeof(struct ether_header))
+#define NFS_HDR_LEN (UDP_HDR_LEN)
+int HDR_LEN = TCP_HDR_LEN;
+
+
+ /*
+ * Initialize a jumbo receive ring descriptor. This allocates
+ * a jumbo buffer from the pool managed internally by the driver.
+ */
+static int
+ti_newbuf_jumbo(sc, idx, m_old)
+ struct ti_softc *sc;
+ int idx;
+ struct mbuf *m_old;
+{
+ struct mbuf *cur, *m_new = NULL;
+ struct mbuf *m[3] = {NULL, NULL, NULL};
+ struct ti_rx_desc_ext *r;
+ vm_page_t frame;
+ /* 1 extra buf to make nobufs easy*/
+ caddr_t buf[3] = {NULL, NULL, NULL};
+ int i;
+
+ if (m_old != NULL) {
+ m_new = m_old;
+ cur = m_old->m_next;
+ for (i = 0; i <= NPAYLOAD; i++){
+ m[i] = cur;
+ cur = cur->m_next;
+ }
+ } else {
+ /* Allocate the mbufs. */
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("ti%d: mbuf allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ goto nobufs;
+ }
+ MGET(m[NPAYLOAD], M_DONTWAIT, MT_DATA);
+ if (m[NPAYLOAD] == NULL) {
+ printf("ti%d: cluster mbuf allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ goto nobufs;
+ }
+ MCLGET(m[NPAYLOAD], M_DONTWAIT);
+ if ((m[NPAYLOAD]->m_flags & M_EXT) == 0) {
+ printf("ti%d: mbuf allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ goto nobufs;
+ }
+ m[NPAYLOAD]->m_len = MCLBYTES;
+
+ for (i = 0; i < NPAYLOAD; i++){
+ MGET(m[i], M_DONTWAIT, MT_DATA);
+ if (m[i] == NULL) {
+ printf("ti%d: mbuf allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ goto nobufs;
+ }
+ if (!(frame = jumbo_pg_alloc())){
+ printf("ti%d: buffer allocation failed "
+ "-- packet dropped!\n", sc->ti_unit);
+ printf(" index %d page %d\n", idx, i);
+ goto nobufs;
+ }
+ buf[i] = jumbo_phys_to_kva(VM_PAGE_TO_PHYS(frame));
+ }
+ for (i = 0; i < NPAYLOAD; i++){
+ /* Attach the buffer to the mbuf. */
+ m[i]->m_data = (void *)buf[i];
+ m[i]->m_len = PAGE_SIZE;
+ MEXTADD(m[i], (void *)buf[i], PAGE_SIZE,
+ jumbo_freem, NULL, 0, EXT_DISPOSABLE);
+ m[i]->m_next = m[i+1];
+ }
+ /* link the buffers to the header */
+ m_new->m_next = m[0];
+ m_new->m_data += ETHER_ALIGN;
+ if (sc->ti_hdrsplit)
+ m_new->m_len = MHLEN - ETHER_ALIGN;
+ else
+ m_new->m_len = HDR_LEN;
+ m_new->m_pkthdr.len = NPAYLOAD * PAGE_SIZE + m_new->m_len;
+ }
+
+ /* Set up the descriptor. */
+ r = &sc->ti_rdata->ti_rx_jumbo_ring[idx];
+ sc->ti_cdata.ti_rx_jumbo_chain[idx] = m_new;
+ TI_HOSTADDR(r->ti_addr0) = vtophys(mtod(m_new, caddr_t));
+ r->ti_len0 = m_new->m_len;
+
+ TI_HOSTADDR(r->ti_addr1) = vtophys(mtod(m[0], caddr_t));
+ r->ti_len1 = PAGE_SIZE;
+
+ TI_HOSTADDR(r->ti_addr2) = vtophys(mtod(m[1], caddr_t));
+ r->ti_len2 = m[1]->m_ext.ext_size; /* could be PAGE_SIZE or MCLBYTES */
+
+ if (PAGE_SIZE == 4096) {
+ TI_HOSTADDR(r->ti_addr3) = vtophys(mtod(m[2], caddr_t));
+ r->ti_len3 = MCLBYTES;
+ } else {
+ r->ti_len3 = 0;
+ }
+ r->ti_type = TI_BDTYPE_RECV_JUMBO_BD;
+
+ r->ti_flags = TI_BDFLAG_JUMBO_RING|TI_RCB_FLAG_USE_EXT_RX_BD;
+
+ if (sc->arpcom.ac_if.if_hwassist)
+ r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM|TI_BDFLAG_IP_CKSUM;
+
+ r->ti_idx = idx;
+
+ return(0);
+
+ nobufs:
+
+ /*
+ * Warning! :
+ * This can only be called before the mbufs are strung together.
+ * If the mbufs are strung together, m_freem() will free the chain,
+ * so that the later mbufs will be freed multiple times.
+ */
+ if (m_new)
+ m_freem(m_new);
+
+ for(i = 0; i < 3; i++){
+ if (m[i])
+ m_freem(m[i]);
+ if (buf[i])
+ jumbo_pg_free((vm_offset_t)buf[i]);
+ }
+ return ENOBUFS;
+}
+#endif
+
+
+
+/*
+ * The standard receive ring has 512 entries in it. At 2K per mbuf cluster,
+ * that's 1MB or memory, which is a lot. For now, we fill only the first
+ * 256 ring entries and hope that our CPU is fast enough to keep up with
+ * the NIC.
+ */
+static int ti_init_rx_ring_std(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+ struct ti_cmd_desc cmd;
+
+ for (i = 0; i < TI_SSLOTS; i++) {
+ if (ti_newbuf_std(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ };
+
+ TI_UPDATE_STDPROD(sc, i - 1);
+ sc->ti_std = i - 1;
+
+ return(0);
+}
+
+static void ti_free_rx_ring_std(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < TI_STD_RX_RING_CNT; i++) {
+ if (sc->ti_cdata.ti_rx_std_chain[i] != NULL) {
+ m_freem(sc->ti_cdata.ti_rx_std_chain[i]);
+ sc->ti_cdata.ti_rx_std_chain[i] = NULL;
+ }
+ bzero((char *)&sc->ti_rdata->ti_rx_std_ring[i],
+ sizeof(struct ti_rx_desc));
+ }
+
+ return;
+}
+
+static int ti_init_rx_ring_jumbo(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+ struct ti_cmd_desc cmd;
+
+ for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) {
+ if (ti_newbuf_jumbo(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ };
+
+ TI_UPDATE_JUMBOPROD(sc, i - 1);
+ sc->ti_jumbo = i - 1;
+
+ return(0);
+}
+
+static void ti_free_rx_ring_jumbo(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) {
+ if (sc->ti_cdata.ti_rx_jumbo_chain[i] != NULL) {
+ m_freem(sc->ti_cdata.ti_rx_jumbo_chain[i]);
+ sc->ti_cdata.ti_rx_jumbo_chain[i] = NULL;
+ }
+ bzero((char *)&sc->ti_rdata->ti_rx_jumbo_ring[i],
+ sizeof(struct ti_rx_desc));
+ }
+
+ return;
+}
+
+static int ti_init_rx_ring_mini(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < TI_MSLOTS; i++) {
+ if (ti_newbuf_mini(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ };
+
+ TI_UPDATE_MINIPROD(sc, i - 1);
+ sc->ti_mini = i - 1;
+
+ return(0);
+}
+
+static void ti_free_rx_ring_mini(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < TI_MINI_RX_RING_CNT; i++) {
+ if (sc->ti_cdata.ti_rx_mini_chain[i] != NULL) {
+ m_freem(sc->ti_cdata.ti_rx_mini_chain[i]);
+ sc->ti_cdata.ti_rx_mini_chain[i] = NULL;
+ }
+ bzero((char *)&sc->ti_rdata->ti_rx_mini_ring[i],
+ sizeof(struct ti_rx_desc));
+ }
+
+ return;
+}
+
+static void ti_free_tx_ring(sc)
+ struct ti_softc *sc;
+{
+ register int i;
+
+ if (sc->ti_rdata->ti_tx_ring == NULL)
+ return;
+
+ for (i = 0; i < TI_TX_RING_CNT; i++) {
+ if (sc->ti_cdata.ti_tx_chain[i] != NULL) {
+ m_freem(sc->ti_cdata.ti_tx_chain[i]);
+ sc->ti_cdata.ti_tx_chain[i] = NULL;
+ }
+ bzero((char *)&sc->ti_rdata->ti_tx_ring[i],
+ sizeof(struct ti_tx_desc));
+ }
+
+ return;
+}
+
+static int ti_init_tx_ring(sc)
+ struct ti_softc *sc;
+{
+ sc->ti_txcnt = 0;
+ sc->ti_tx_saved_considx = 0;
+ CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, 0);
+ return(0);
+}
+
+/*
+ * The Tigon 2 firmware has a new way to add/delete multicast addresses,
+ * but we have to support the old way too so that Tigon 1 cards will
+ * work.
+ */
+void ti_add_mcast(sc, addr)
+ struct ti_softc *sc;
+ struct ether_addr *addr;
+{
+ struct ti_cmd_desc cmd;
+ u_int16_t *m;
+ u_int32_t ext[2] = {0, 0};
+
+ m = (u_int16_t *)&addr->octet[0];
+
+ switch(sc->ti_hwrev) {
+ case TI_HWREV_TIGON:
+ CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0]));
+ CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2]));
+ TI_DO_CMD(TI_CMD_ADD_MCAST_ADDR, 0, 0);
+ break;
+ case TI_HWREV_TIGON_II:
+ ext[0] = htons(m[0]);
+ ext[1] = (htons(m[1]) << 16) | htons(m[2]);
+ TI_DO_CMD_EXT(TI_CMD_EXT_ADD_MCAST, 0, 0, (caddr_t)&ext, 2);
+ break;
+ default:
+ printf("ti%d: unknown hwrev\n", sc->ti_unit);
+ break;
+ }
+
+ return;
+}
+
+void ti_del_mcast(sc, addr)
+ struct ti_softc *sc;
+ struct ether_addr *addr;
+{
+ struct ti_cmd_desc cmd;
+ u_int16_t *m;
+ u_int32_t ext[2] = {0, 0};
+
+ m = (u_int16_t *)&addr->octet[0];
+
+ switch(sc->ti_hwrev) {
+ case TI_HWREV_TIGON:
+ CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0]));
+ CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2]));
+ TI_DO_CMD(TI_CMD_DEL_MCAST_ADDR, 0, 0);
+ break;
+ case TI_HWREV_TIGON_II:
+ ext[0] = htons(m[0]);
+ ext[1] = (htons(m[1]) << 16) | htons(m[2]);
+ TI_DO_CMD_EXT(TI_CMD_EXT_DEL_MCAST, 0, 0, (caddr_t)&ext, 2);
+ break;
+ default:
+ printf("ti%d: unknown hwrev\n", sc->ti_unit);
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Configure the Tigon's multicast address filter.
+ *
+ * The actual multicast table management is a bit of a pain, thanks to
+ * slight brain damage on the part of both Alteon and us. With our
+ * multicast code, we are only alerted when the multicast address table
+ * changes and at that point we only have the current list of addresses:
+ * we only know the current state, not the previous state, so we don't
+ * actually know what addresses were removed or added. The firmware has
+ * state, but we can't get our grubby mits on it, and there is no 'delete
+ * all multicast addresses' command. Hence, we have to maintain our own
+ * state so we know what addresses have been programmed into the NIC at
+ * any given time.
+ */
+static void ti_setmulti(sc)
+ struct ti_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ struct ti_cmd_desc cmd;
+ struct ti_mc_entry *mc;
+ u_int32_t intrs;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (ifp->if_flags & IFF_ALLMULTI) {
+ TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_ENB, 0);
+ return;
+ } else {
+ TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_DIS, 0);
+ }
+
+ /* Disable interrupts. */
+ intrs = CSR_READ_4(sc, TI_MB_HOSTINTR);
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1);
+
+ /* First, zot all the existing filters. */
+ while (SLIST_FIRST(&sc->ti_mc_listhead) != NULL) {
+ mc = SLIST_FIRST(&sc->ti_mc_listhead);
+ ti_del_mcast(sc, &mc->mc_addr);
+ SLIST_REMOVE_HEAD(&sc->ti_mc_listhead, mc_entries);
+ free(mc, M_DEVBUF);
+ }
+
+ /* Now program new ones. */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF, M_NOWAIT);
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ (char *)&mc->mc_addr, ETHER_ADDR_LEN);
+ SLIST_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries);
+ ti_add_mcast(sc, &mc->mc_addr);
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs);
+
+ return;
+}
+
+/*
+ * Check to see if the BIOS has configured us for a 64 bit slot when
+ * we aren't actually in one. If we detect this condition, we can work
+ * around it on the Tigon 2 by setting a bit in the PCI state register,
+ * but for the Tigon 1 we must give up and abort the interface attach.
+ */
+static int ti_64bitslot_war(sc)
+ struct ti_softc *sc;
+{
+ if (!(CSR_READ_4(sc, TI_PCI_STATE) & TI_PCISTATE_32BIT_BUS)) {
+ CSR_WRITE_4(sc, 0x600, 0);
+ CSR_WRITE_4(sc, 0x604, 0);
+ CSR_WRITE_4(sc, 0x600, 0x5555AAAA);
+ if (CSR_READ_4(sc, 0x604) == 0x5555AAAA) {
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ return(EINVAL);
+ else {
+ TI_SETBIT(sc, TI_PCI_STATE,
+ TI_PCISTATE_32BIT_BUS);
+ return(0);
+ }
+ }
+ }
+
+ return(0);
+}
+
+/*
+ * Do endian, PCI and DMA initialization. Also check the on-board ROM
+ * self-test results.
+ */
+static int ti_chipinit(sc)
+ struct ti_softc *sc;
+{
+ u_int32_t cacheline;
+ u_int32_t pci_writemax = 0;
+ u_int32_t hdrsplit;
+
+ /* Initialize link to down state. */
+ sc->ti_linkstat = TI_EV_CODE_LINK_DOWN;
+
+ if (sc->arpcom.ac_if.if_capenable & IFCAP_HWCSUM)
+ sc->arpcom.ac_if.if_hwassist = TI_CSUM_FEATURES;
+ else
+ sc->arpcom.ac_if.if_hwassist = 0;
+
+ /* Set endianness before we access any non-PCI registers. */
+#if BYTE_ORDER == BIG_ENDIAN
+ CSR_WRITE_4(sc, TI_MISC_HOST_CTL,
+ TI_MHC_BIGENDIAN_INIT | (TI_MHC_BIGENDIAN_INIT << 24));
+#else
+ CSR_WRITE_4(sc, TI_MISC_HOST_CTL,
+ TI_MHC_LITTLEENDIAN_INIT | (TI_MHC_LITTLEENDIAN_INIT << 24));
+#endif
+
+ /* Check the ROM failed bit to see if self-tests passed. */
+ if (CSR_READ_4(sc, TI_CPU_STATE) & TI_CPUSTATE_ROMFAIL) {
+ printf("ti%d: board self-diagnostics failed!\n", sc->ti_unit);
+ return(ENODEV);
+ }
+
+ /* Halt the CPU. */
+ TI_SETBIT(sc, TI_CPU_STATE, TI_CPUSTATE_HALT);
+
+ /* Figure out the hardware revision. */
+ switch(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_CHIP_REV_MASK) {
+ case TI_REV_TIGON_I:
+ sc->ti_hwrev = TI_HWREV_TIGON;
+ break;
+ case TI_REV_TIGON_II:
+ sc->ti_hwrev = TI_HWREV_TIGON_II;
+ break;
+ default:
+ printf("ti%d: unsupported chip revision\n", sc->ti_unit);
+ return(ENODEV);
+ }
+
+ /* Do special setup for Tigon 2. */
+ if (sc->ti_hwrev == TI_HWREV_TIGON_II) {
+ TI_SETBIT(sc, TI_CPU_CTL_B, TI_CPUSTATE_HALT);
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_SRAM_BANK_512K);
+ TI_SETBIT(sc, TI_MISC_CONF, TI_MCR_SRAM_SYNCHRONOUS);
+ }
+
+ /*
+ * We don't have firmware source for the Tigon 1, so Tigon 1 boards
+ * can't do header splitting.
+ */
+#ifdef TI_JUMBO_HDRSPLIT
+ if (sc->ti_hwrev != TI_HWREV_TIGON)
+ sc->ti_hdrsplit = 1;
+ else
+ printf("ti%d: can't do header splitting on a Tigon I board\n",
+ sc->ti_unit);
+#endif /* TI_JUMBO_HDRSPLIT */
+
+ /* Set up the PCI state register. */
+ CSR_WRITE_4(sc, TI_PCI_STATE, TI_PCI_READ_CMD|TI_PCI_WRITE_CMD);
+ if (sc->ti_hwrev == TI_HWREV_TIGON_II) {
+ TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_USE_MEM_RD_MULT);
+ }
+
+ /* Clear the read/write max DMA parameters. */
+ TI_CLRBIT(sc, TI_PCI_STATE, (TI_PCISTATE_WRITE_MAXDMA|
+ TI_PCISTATE_READ_MAXDMA));
+
+ /* Get cache line size. */
+ cacheline = CSR_READ_4(sc, TI_PCI_BIST) & 0xFF;
+
+ /*
+ * If the system has set enabled the PCI memory write
+ * and invalidate command in the command register, set
+ * the write max parameter accordingly. This is necessary
+ * to use MWI with the Tigon 2.
+ */
+ if (CSR_READ_4(sc, TI_PCI_CMDSTAT) & PCIM_CMD_MWIEN) {
+ switch(cacheline) {
+ case 1:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ /* Disable PCI memory write and invalidate. */
+ if (bootverbose)
+ printf("ti%d: cache line size %d not "
+ "supported; disabling PCI MWI\n",
+ sc->ti_unit, cacheline);
+ CSR_WRITE_4(sc, TI_PCI_CMDSTAT, CSR_READ_4(sc,
+ TI_PCI_CMDSTAT) & ~PCIM_CMD_MWIEN);
+ break;
+ }
+ }
+
+#ifdef __brokenalpha__
+ /*
+ * From the Alteon sample driver:
+ * Must insure that we do not cross an 8K (bytes) boundary
+ * for DMA reads. Our highest limit is 1K bytes. This is a
+ * restriction on some ALPHA platforms with early revision
+ * 21174 PCI chipsets, such as the AlphaPC 164lx
+ */
+ TI_SETBIT(sc, TI_PCI_STATE, pci_writemax|TI_PCI_READMAX_1024);
+#else
+ TI_SETBIT(sc, TI_PCI_STATE, pci_writemax);
+#endif
+
+ /* This sets the min dma param all the way up (0xff). */
+ TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_MINDMA);
+
+ if (sc->ti_hdrsplit)
+ hdrsplit = TI_OPMODE_JUMBO_HDRSPLIT;
+ else
+ hdrsplit = 0;
+
+ /* Configure DMA variables. */
+#if BYTE_ORDER == BIG_ENDIAN
+ CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_BD |
+ TI_OPMODE_BYTESWAP_DATA | TI_OPMODE_WORDSWAP_BD |
+ TI_OPMODE_WARN_ENB | TI_OPMODE_FATAL_ENB |
+ TI_OPMODE_DONT_FRAG_JUMBO | hdrsplit);
+#else /* BYTE_ORDER */
+ CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_DATA|
+ TI_OPMODE_WORDSWAP_BD|TI_OPMODE_DONT_FRAG_JUMBO|
+ TI_OPMODE_WARN_ENB|TI_OPMODE_FATAL_ENB | hdrsplit);
+#endif /* BYTE_ORDER */
+
+ /*
+ * Only allow 1 DMA channel to be active at a time.
+ * I don't think this is a good idea, but without it
+ * the firmware racks up lots of nicDmaReadRingFull
+ * errors. This is not compatible with hardware checksums.
+ */
+ if (sc->arpcom.ac_if.if_hwassist == 0)
+ TI_SETBIT(sc, TI_GCR_OPMODE, TI_OPMODE_1_DMA_ACTIVE);
+
+ /* Recommended settings from Tigon manual. */
+ CSR_WRITE_4(sc, TI_GCR_DMA_WRITECFG, TI_DMA_STATE_THRESH_8W);
+ CSR_WRITE_4(sc, TI_GCR_DMA_READCFG, TI_DMA_STATE_THRESH_8W);
+
+ if (ti_64bitslot_war(sc)) {
+ printf("ti%d: bios thinks we're in a 64 bit slot, "
+ "but we aren't", sc->ti_unit);
+ return(EINVAL);
+ }
+
+ return(0);
+}
+
+/*
+ * Initialize the general information block and firmware, and
+ * start the CPU(s) running.
+ */
+static int ti_gibinit(sc)
+ struct ti_softc *sc;
+{
+ struct ti_rcb *rcb;
+ int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Disable interrupts for now. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1);
+
+ /* Tell the chip where to find the general information block. */
+ CSR_WRITE_4(sc, TI_GCR_GENINFO_HI, 0);
+ CSR_WRITE_4(sc, TI_GCR_GENINFO_LO, vtophys(&sc->ti_rdata->ti_info));
+
+ /* Load the firmware into SRAM. */
+ ti_loadfw(sc);
+
+ /* Set up the contents of the general info and ring control blocks. */
+
+ /* Set up the event ring and producer pointer. */
+ rcb = &sc->ti_rdata->ti_info.ti_ev_rcb;
+
+ TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_event_ring);
+ rcb->ti_flags = 0;
+ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_ev_prodidx_ptr) =
+ vtophys(&sc->ti_ev_prodidx);
+ sc->ti_ev_prodidx.ti_idx = 0;
+ CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, 0);
+ sc->ti_ev_saved_considx = 0;
+
+ /* Set up the command ring and producer mailbox. */
+ rcb = &sc->ti_rdata->ti_info.ti_cmd_rcb;
+
+ sc->ti_rdata->ti_cmd_ring =
+ (struct ti_cmd_desc *)(sc->ti_vhandle + TI_GCR_CMDRING);
+ TI_HOSTADDR(rcb->ti_hostaddr) = TI_GCR_NIC_ADDR(TI_GCR_CMDRING);
+ rcb->ti_flags = 0;
+ rcb->ti_max_len = 0;
+ for (i = 0; i < TI_CMD_RING_CNT; i++) {
+ CSR_WRITE_4(sc, TI_GCR_CMDRING + (i * 4), 0);
+ }
+ CSR_WRITE_4(sc, TI_GCR_CMDCONS_IDX, 0);
+ CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, 0);
+ sc->ti_cmd_saved_prodidx = 0;
+
+ /*
+ * Assign the address of the stats refresh buffer.
+ * We re-use the current stats buffer for this to
+ * conserve memory.
+ */
+ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_refresh_stats_ptr) =
+ vtophys(&sc->ti_rdata->ti_info.ti_stats);
+
+ /* Set up the standard receive ring. */
+ rcb = &sc->ti_rdata->ti_info.ti_std_rx_rcb;
+ TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_std_ring);
+ rcb->ti_max_len = TI_FRAMELEN;
+ rcb->ti_flags = 0;
+ if (sc->arpcom.ac_if.if_hwassist)
+ rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
+ TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
+ rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+
+ /* Set up the jumbo receive ring. */
+ rcb = &sc->ti_rdata->ti_info.ti_jumbo_rx_rcb;
+ TI_HOSTADDR(rcb->ti_hostaddr) =
+ vtophys(&sc->ti_rdata->ti_rx_jumbo_ring);
+
+#ifdef TI_PRIVATE_JUMBOS
+ rcb->ti_max_len = TI_JUMBO_FRAMELEN;
+ rcb->ti_flags = 0;
+#else
+ rcb->ti_max_len = PAGE_SIZE;
+ rcb->ti_flags = TI_RCB_FLAG_USE_EXT_RX_BD;
+#endif
+ if (sc->arpcom.ac_if.if_hwassist)
+ rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
+ TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
+ rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+
+ /*
+ * Set up the mini ring. Only activated on the
+ * Tigon 2 but the slot in the config block is
+ * still there on the Tigon 1.
+ */
+ rcb = &sc->ti_rdata->ti_info.ti_mini_rx_rcb;
+ TI_HOSTADDR(rcb->ti_hostaddr) =
+ vtophys(&sc->ti_rdata->ti_rx_mini_ring);
+ rcb->ti_max_len = MHLEN - ETHER_ALIGN;
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ rcb->ti_flags = TI_RCB_FLAG_RING_DISABLED;
+ else
+ rcb->ti_flags = 0;
+ if (sc->arpcom.ac_if.if_hwassist)
+ rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
+ TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
+ rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+
+ /*
+ * Set up the receive return ring.
+ */
+ rcb = &sc->ti_rdata->ti_info.ti_return_rcb;
+ TI_HOSTADDR(rcb->ti_hostaddr) =
+ vtophys(&sc->ti_rdata->ti_rx_return_ring);
+ rcb->ti_flags = 0;
+ rcb->ti_max_len = TI_RETURN_RING_CNT;
+ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_return_prodidx_ptr) =
+ vtophys(&sc->ti_return_prodidx);
+
+ /*
+ * Set up the tx ring. Note: for the Tigon 2, we have the option
+ * of putting the transmit ring in the host's address space and
+ * letting the chip DMA it instead of leaving the ring in the NIC's
+ * memory and accessing it through the shared memory region. We
+ * do this for the Tigon 2, but it doesn't work on the Tigon 1,
+ * so we have to revert to the shared memory scheme if we detect
+ * a Tigon 1 chip.
+ */
+ CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE);
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ sc->ti_rdata->ti_tx_ring_nic =
+ (struct ti_tx_desc *)(sc->ti_vhandle + TI_WINDOW);
+ }
+ bzero((char *)sc->ti_rdata->ti_tx_ring,
+ TI_TX_RING_CNT * sizeof(struct ti_tx_desc));
+ rcb = &sc->ti_rdata->ti_info.ti_tx_rcb;
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ rcb->ti_flags = 0;
+ else
+ rcb->ti_flags = TI_RCB_FLAG_HOST_RING;
+ rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+ if (sc->arpcom.ac_if.if_hwassist)
+ rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
+ TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
+ rcb->ti_max_len = TI_TX_RING_CNT;
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ TI_HOSTADDR(rcb->ti_hostaddr) = TI_TX_RING_BASE;
+ else
+ TI_HOSTADDR(rcb->ti_hostaddr) =
+ vtophys(&sc->ti_rdata->ti_tx_ring);
+ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_tx_considx_ptr) =
+ vtophys(&sc->ti_tx_considx);
+
+ /* Set up tuneables */
+#if 0
+ if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN))
+ CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS,
+ (sc->ti_rx_coal_ticks / 10));
+ else
+#endif
+ CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, sc->ti_rx_coal_ticks);
+ CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS, sc->ti_tx_coal_ticks);
+ CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks);
+ CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD, sc->ti_rx_max_coal_bds);
+ CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD, sc->ti_tx_max_coal_bds);
+ CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO, sc->ti_tx_buf_ratio);
+
+ /* Turn interrupts on. */
+ CSR_WRITE_4(sc, TI_GCR_MASK_INTRS, 0);
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
+
+ /* Start CPU. */
+ TI_CLRBIT(sc, TI_CPU_STATE, (TI_CPUSTATE_HALT|TI_CPUSTATE_STEP));
+
+ return(0);
+}
+
+/*
+ * Probe for a Tigon chip. Check the PCI vendor and device IDs
+ * against our list and return its name if we find a match.
+ */
+static int ti_probe(dev)
+ device_t dev;
+{
+ struct ti_type *t;
+
+ t = ti_devs;
+
+ while(t->ti_name != NULL) {
+ if ((pci_get_vendor(dev) == t->ti_vid) &&
+ (pci_get_device(dev) == t->ti_did)) {
+ device_set_desc(dev, t->ti_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+#ifdef KLD_MODULE
+static int
+log2rndup(int len)
+{
+ int log2size = 0, t = len;
+ while (t > 1) {
+ log2size++;
+ t >>= 1;
+ }
+ if (len != (1 << log2size))
+ log2size++;
+ return log2size;
+}
+
+static int
+ti_mbuf_sanity(device_t dev)
+{
+ if ((mbstat.m_msize != MSIZE) || mbstat.m_mclbytes != MCLBYTES){
+ device_printf(dev, "\n");
+ device_printf(dev, "This module was compiled with "
+ "-DMCLSHIFT=%d -DMSIZE=%d\n", MCLSHIFT,
+ MSIZE);
+ device_printf(dev, "The kernel was compiled with MCLSHIFT=%d,"
+ " MSIZE=%d\n", log2rndup(mbstat.m_mclbytes),
+ (int)mbstat.m_msize);
+ return(EINVAL);
+ }
+ return(0);
+}
+#endif
+
+
+static int ti_attach(dev)
+ device_t dev;
+{
+ u_int32_t command;
+ struct ifnet *ifp;
+ struct ti_softc *sc;
+ int unit, error = 0, rid;
+
+ sc = NULL;
+
+#ifdef KLD_MODULE
+ if (ti_mbuf_sanity(dev)){
+ device_printf(dev, "Module mbuf constants do not match "
+ "kernel constants!\n");
+ device_printf(dev, "Rebuild the module or the kernel so "
+ "they match\n");
+ device_printf(dev, "\n");
+ error = EINVAL;
+ goto fail;
+ }
+#endif
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct ti_softc));
+
+ mtx_init(&sc->ti_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ sc->arpcom.ac_if.if_capabilities = IFCAP_HWCSUM;
+ sc->arpcom.ac_if.if_capenable = sc->arpcom.ac_if.if_capabilities;
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("ti%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = TI_PCI_LOMEM;
+ sc->ti_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE|PCI_RF_DENSE);
+
+ if (sc->ti_res == NULL) {
+ printf ("ti%d: couldn't map memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->ti_btag = rman_get_bustag(sc->ti_res);
+ sc->ti_bhandle = rman_get_bushandle(sc->ti_res);
+ sc->ti_vhandle = (vm_offset_t)rman_get_virtual(sc->ti_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+
+ sc->ti_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->ti_irq == NULL) {
+ printf("ti%d: couldn't map interrupt\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->ti_irq, INTR_TYPE_NET,
+ ti_intr, sc, &sc->ti_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ printf("ti%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ sc->ti_unit = unit;
+
+ if (ti_chipinit(sc)) {
+ printf("ti%d: chip initialization failed\n", sc->ti_unit);
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Zero out the NIC's on-board SRAM. */
+ ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL);
+
+ /* Init again -- zeroing memory may have clobbered some registers. */
+ if (ti_chipinit(sc)) {
+ printf("ti%d: chip initialization failed\n", sc->ti_unit);
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Get station address from the EEPROM. Note: the manual states
+ * that the MAC address is at offset 0x8c, however the data is
+ * stored as two longwords (since that's how it's loaded into
+ * the NIC). This means the MAC address is actually preceded
+ * by two zero bytes. We need to skip over those.
+ */
+ if (ti_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
+ TI_EE_MAC_OFFSET + 2, ETHER_ADDR_LEN)) {
+ printf("ti%d: failed to read station address\n", unit);
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * A Tigon chip was detected. Inform the world.
+ */
+ printf("ti%d: Ethernet address: %6D\n", unit,
+ sc->arpcom.ac_enaddr, ":");
+
+ /* Allocate the general information block and ring buffers. */
+ sc->ti_rdata = contigmalloc(sizeof(struct ti_ring_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->ti_rdata == NULL) {
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ error = ENXIO;
+ printf("ti%d: no memory for list buffers!\n", sc->ti_unit);
+ goto fail;
+ }
+
+ bzero(sc->ti_rdata, sizeof(struct ti_ring_data));
+
+ /* Try to allocate memory for jumbo buffers. */
+#ifdef TI_PRIVATE_JUMBOS
+ if (ti_alloc_jumbo_mem(sc)) {
+ printf("ti%d: jumbo buffer allocation failed\n", sc->ti_unit);
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ contigfree(sc->ti_rdata, sizeof(struct ti_ring_data),
+ M_DEVBUF);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!jumbo_vm_init()) {
+ printf("ti%d: VM initialization failed!\n", sc->ti_unit);
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ TI_PCI_LOMEM, sc->ti_res);
+ free(sc->ti_rdata, M_DEVBUF);
+ error = ENOMEM;
+ goto fail;
+ }
+#endif
+
+ /*
+ * We really need a better way to tell a 1000baseTX card
+ * from a 1000baseSX one, since in theory there could be
+ * OEMed 1000baseTX cards from lame vendors who aren't
+ * clever enough to change the PCI ID. For the moment
+ * though, the AceNIC is the only copper card available.
+ */
+ if (pci_get_vendor(dev) == ALT_VENDORID &&
+ pci_get_device(dev) == ALT_DEVICEID_ACENIC_COPPER)
+ sc->ti_copper = 1;
+ /* Ok, it's not the only copper card available. */
+ if (pci_get_vendor(dev) == NG_VENDORID &&
+ pci_get_device(dev) == NG_DEVICEID_GA620T)
+ sc->ti_copper = 1;
+
+ /* Set default tuneable values. */
+ sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC;
+#if 0
+ sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000;
+#endif
+ sc->ti_rx_coal_ticks = 170;
+ sc->ti_tx_coal_ticks = TI_TICKS_PER_SEC / 500;
+ sc->ti_rx_max_coal_bds = 64;
+#if 0
+ sc->ti_tx_max_coal_bds = 128;
+#endif
+ sc->ti_tx_max_coal_bds = 32;
+ sc->ti_tx_buf_ratio = 21;
+
+ /* Set up ifnet structure */
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = sc->ti_unit;
+ ifp->if_name = "ti";
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ tis[unit] = sc;
+ ifp->if_ioctl = ti_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = ti_start;
+ ifp->if_watchdog = ti_watchdog;
+ ifp->if_init = ti_init;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_snd.ifq_maxlen = TI_TX_RING_CNT - 1;
+
+ /* Set up ifmedia support. */
+ ifmedia_init(&sc->ifmedia, IFM_IMASK, ti_ifmedia_upd, ti_ifmedia_sts);
+ if (sc->ti_copper) {
+ /*
+ * Copper cards allow manual 10/100 mode selection,
+ * but not manual 1000baseTX mode selection. Why?
+ * Becuase currently there's no way to specify the
+ * master/slave setting through the firmware interface,
+ * so Alteon decided to just bag it and handle it
+ * via autonegotiation.
+ */
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_T, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
+ } else {
+ /* Fiber cards don't support 10/100 modes. */
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+ }
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
+
+ /*
+ * We're assuming here that card initialization is a sequential
+ * thing. If it isn't, multiple cards probing at the same time
+ * could stomp on the list of softcs here.
+ */
+ /*
+ * If this is the first card to be initialized, initialize the
+ * softc queue.
+ */
+ if (unit == 0)
+ STAILQ_INIT(&ti_sc_list);
+
+ STAILQ_INSERT_TAIL(&ti_sc_list, sc, ti_links);
+
+ /* Register the device */
+ sc->dev = make_dev(&ti_cdevsw, sc->ti_unit, UID_ROOT, GID_OPERATOR,
+ 0600, "ti%d", sc->ti_unit);
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ return(0);
+
+fail:
+ mtx_destroy(&sc->ti_mtx);
+ return(error);
+}
+
+/*
+ * Verify that our character special device is not currently
+ * open. Also track down any cached vnodes & kill them before
+ * the module is unloaded
+ */
+static int
+ti_unref_special(device_t dev)
+{
+ struct vnode *ti_vn;
+ int count;
+ struct ti_softc *sc = sc = device_get_softc(dev);
+
+ if (!vfinddev(sc->dev, VCHR, &ti_vn)) {
+ return 0;
+ }
+
+ if ((count = vcount(ti_vn))) {
+ device_printf(dev, "%d refs to special device, "
+ "denying unload\n", count);
+ return count;
+ }
+ /* now we know that there's a vnode in the cache. We hunt it
+ down and kill it now, before unloading */
+ vgone(ti_vn);
+ return(0);
+}
+
+
+static int ti_detach(dev)
+ device_t dev;
+{
+ struct ti_softc *sc;
+ struct ifnet *ifp;
+
+ if (ti_unref_special(dev))
+ return EBUSY;
+
+ sc = device_get_softc(dev);
+ TI_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+ ti_stop(sc);
+
+ bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res);
+
+#ifdef TI_PRIVATE_JUMBOS
+ contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM, M_DEVBUF);
+#endif
+ contigfree(sc->ti_rdata, sizeof(struct ti_ring_data), M_DEVBUF);
+ ifmedia_removeall(&sc->ifmedia);
+
+ TI_UNLOCK(sc);
+ mtx_destroy(&sc->ti_mtx);
+
+ return(0);
+}
+
+#ifdef TI_JUMBO_HDRSPLIT
+/*
+ * If hdr_len is 0, that means that header splitting wasn't done on
+ * this packet for some reason. The two most likely reasons are that
+ * the protocol isn't a supported protocol for splitting, or this
+ * packet had a fragment offset that wasn't 0.
+ *
+ * The header length, if it is non-zero, will always be the length of
+ * the headers on the packet, but that length could be longer than the
+ * first mbuf. So we take the minimum of the two as the actual
+ * length.
+ */
+static __inline void
+ti_hdr_split(struct mbuf *top, int hdr_len, int pkt_len, int idx)
+{
+ int i = 0;
+ int lengths[4] = {0, 0, 0, 0};
+ struct mbuf *m, *mp;
+
+ if (hdr_len != 0)
+ top->m_len = min(hdr_len, top->m_len);
+ pkt_len -= top->m_len;
+ lengths[i++] = top->m_len;
+
+ mp = top;
+ for (m = top->m_next; m && pkt_len; m = m->m_next) {
+ m->m_len = m->m_ext.ext_size = min(m->m_len, pkt_len);
+ pkt_len -= m->m_len;
+ lengths[i++] = m->m_len;
+ mp = m;
+ }
+
+#if 0
+ if (hdr_len != 0)
+ printf("got split packet: ");
+ else
+ printf("got non-split packet: ");
+
+ printf("%d,%d,%d,%d = %d\n", lengths[0],
+ lengths[1], lengths[2], lengths[3],
+ lengths[0] + lengths[1] + lengths[2] +
+ lengths[3]);
+#endif
+
+ if (pkt_len)
+ panic("header splitting didn't");
+
+ if (m) {
+ m_freem(m);
+ mp->m_next = NULL;
+
+ }
+ if (mp->m_next != NULL)
+ panic("ti_hdr_split: last mbuf in chain should be null");
+}
+#endif /* TI_JUMBO_HDRSPLIT */
+
+/*
+ * Frame reception handling. This is called if there's a frame
+ * on the receive return list.
+ *
+ * Note: we have to be able to handle three possibilities here:
+ * 1) the frame is from the mini receive ring (can only happen)
+ * on Tigon 2 boards)
+ * 2) the frame is from the jumbo recieve ring
+ * 3) the frame is from the standard receive ring
+ */
+
+static void ti_rxeof(sc)
+ struct ti_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ti_cmd_desc cmd;
+
+ ifp = &sc->arpcom.ac_if;
+
+ while(sc->ti_rx_saved_considx != sc->ti_return_prodidx.ti_idx) {
+ struct ti_rx_desc *cur_rx;
+ u_int32_t rxidx;
+ struct ether_header *eh;
+ struct mbuf *m = NULL;
+ u_int16_t vlan_tag = 0;
+ int have_tag = 0;
+
+ cur_rx =
+ &sc->ti_rdata->ti_rx_return_ring[sc->ti_rx_saved_considx];
+ rxidx = cur_rx->ti_idx;
+ TI_INC(sc->ti_rx_saved_considx, TI_RETURN_RING_CNT);
+
+ if (cur_rx->ti_flags & TI_BDFLAG_VLAN_TAG) {
+ have_tag = 1;
+ vlan_tag = cur_rx->ti_vlan_tag & 0xfff;
+ }
+
+ if (cur_rx->ti_flags & TI_BDFLAG_JUMBO_RING) {
+
+ TI_INC(sc->ti_jumbo, TI_JUMBO_RX_RING_CNT);
+ m = sc->ti_cdata.ti_rx_jumbo_chain[rxidx];
+ sc->ti_cdata.ti_rx_jumbo_chain[rxidx] = NULL;
+ if (cur_rx->ti_flags & TI_BDFLAG_ERROR) {
+ ifp->if_ierrors++;
+ ti_newbuf_jumbo(sc, sc->ti_jumbo, m);
+ continue;
+ }
+ if (ti_newbuf_jumbo(sc, sc->ti_jumbo, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ ti_newbuf_jumbo(sc, sc->ti_jumbo, m);
+ continue;
+ }
+#ifdef TI_PRIVATE_JUMBOS
+ m->m_len = cur_rx->ti_len;
+#else /* TI_PRIVATE_JUMBOS */
+#ifdef TI_JUMBO_HDRSPLIT
+ if (sc->ti_hdrsplit)
+ ti_hdr_split(m, TI_HOSTADDR(cur_rx->ti_addr),
+ cur_rx->ti_len, rxidx);
+ else
+#endif /* TI_JUMBO_HDRSPLIT */
+ m_adj(m, cur_rx->ti_len - m->m_pkthdr.len);
+#endif /* TI_PRIVATE_JUMBOS */
+ } else if (cur_rx->ti_flags & TI_BDFLAG_MINI_RING) {
+ TI_INC(sc->ti_mini, TI_MINI_RX_RING_CNT);
+ m = sc->ti_cdata.ti_rx_mini_chain[rxidx];
+ sc->ti_cdata.ti_rx_mini_chain[rxidx] = NULL;
+ if (cur_rx->ti_flags & TI_BDFLAG_ERROR) {
+ ifp->if_ierrors++;
+ ti_newbuf_mini(sc, sc->ti_mini, m);
+ continue;
+ }
+ if (ti_newbuf_mini(sc, sc->ti_mini, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ ti_newbuf_mini(sc, sc->ti_mini, m);
+ continue;
+ }
+ m->m_len = cur_rx->ti_len;
+ } else {
+ TI_INC(sc->ti_std, TI_STD_RX_RING_CNT);
+ m = sc->ti_cdata.ti_rx_std_chain[rxidx];
+ sc->ti_cdata.ti_rx_std_chain[rxidx] = NULL;
+ if (cur_rx->ti_flags & TI_BDFLAG_ERROR) {
+ ifp->if_ierrors++;
+ ti_newbuf_std(sc, sc->ti_std, m);
+ continue;
+ }
+ if (ti_newbuf_std(sc, sc->ti_std, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ ti_newbuf_std(sc, sc->ti_std, m);
+ continue;
+ }
+ m->m_len = cur_rx->ti_len;
+ }
+
+ m->m_pkthdr.len = cur_rx->ti_len;
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+
+ if (ifp->if_hwassist) {
+ m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED |
+ CSUM_DATA_VALID;
+ if ((cur_rx->ti_ip_cksum ^ 0xffff) == 0)
+ m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+ m->m_pkthdr.csum_data = cur_rx->ti_tcp_udp_cksum;
+ }
+
+ /*
+ * If we received a packet with a vlan tag, pass it
+ * to vlan_input() instead of ether_input().
+ */
+ if (have_tag) {
+ VLAN_INPUT_TAG(eh, m, vlan_tag);
+ have_tag = vlan_tag = 0;
+ continue;
+ }
+ ether_input(ifp, eh, m);
+ }
+
+ /* Only necessary on the Tigon 1. */
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX,
+ sc->ti_rx_saved_considx);
+
+ TI_UPDATE_STDPROD(sc, sc->ti_std);
+ TI_UPDATE_MINIPROD(sc, sc->ti_mini);
+ TI_UPDATE_JUMBOPROD(sc, sc->ti_jumbo);
+
+ return;
+}
+
+static void ti_txeof(sc)
+ struct ti_softc *sc;
+{
+ struct ti_tx_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /*
+ * Go through our tx ring and free mbufs for those
+ * frames that have been sent.
+ */
+ while (sc->ti_tx_saved_considx != sc->ti_tx_considx.ti_idx) {
+ u_int32_t idx = 0;
+
+ idx = sc->ti_tx_saved_considx;
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ if (idx > 383)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 6144);
+ else if (idx > 255)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 4096);
+ else if (idx > 127)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 2048);
+ else
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE);
+ cur_tx = &sc->ti_rdata->ti_tx_ring_nic[idx % 128];
+ } else
+ cur_tx = &sc->ti_rdata->ti_tx_ring[idx];
+ if (cur_tx->ti_flags & TI_BDFLAG_END)
+ ifp->if_opackets++;
+ if (sc->ti_cdata.ti_tx_chain[idx] != NULL) {
+ m_freem(sc->ti_cdata.ti_tx_chain[idx]);
+ sc->ti_cdata.ti_tx_chain[idx] = NULL;
+ }
+ sc->ti_txcnt--;
+ TI_INC(sc->ti_tx_saved_considx, TI_TX_RING_CNT);
+ ifp->if_timer = 0;
+ }
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void ti_intr(xsc)
+ void *xsc;
+{
+ struct ti_softc *sc;
+ struct ifnet *ifp;
+
+ sc = xsc;
+ TI_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+/*#ifdef notdef*/
+ /* Avoid this for now -- checking this register is expensive. */
+ /* Make sure this is really our interrupt. */
+ if (!(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_INTSTATE)) {
+ TI_UNLOCK(sc);
+ return;
+ }
+/*#endif*/
+
+ /* Ack interrupt and stop others from occuring. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1);
+
+ if (ifp->if_flags & IFF_RUNNING) {
+ /* Check RX return ring producer/consumer */
+ ti_rxeof(sc);
+
+ /* Check TX ring producer/consumer */
+ ti_txeof(sc);
+ }
+
+ ti_handle_events(sc);
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
+
+ if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+ ti_start(ifp);
+
+ TI_UNLOCK(sc);
+
+ return;
+}
+
+static void ti_stats_update(sc)
+ struct ti_softc *sc;
+{
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ ifp->if_collisions +=
+ (sc->ti_rdata->ti_info.ti_stats.dot3StatsSingleCollisionFrames +
+ sc->ti_rdata->ti_info.ti_stats.dot3StatsMultipleCollisionFrames +
+ sc->ti_rdata->ti_info.ti_stats.dot3StatsExcessiveCollisions +
+ sc->ti_rdata->ti_info.ti_stats.dot3StatsLateCollisions) -
+ ifp->if_collisions;
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in the tx ring by coupling the mbuf data
+ * pointers to descriptors.
+ */
+static int ti_encap(sc, m_head, txidx)
+ struct ti_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct ti_tx_desc *f = NULL;
+ struct mbuf *m;
+ u_int32_t frag, cur, cnt = 0;
+ u_int16_t csum_flags = 0;
+ struct ifvlan *ifv = NULL;
+
+ if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+ m_head->m_pkthdr.rcvif != NULL &&
+ m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+ ifv = m_head->m_pkthdr.rcvif->if_softc;
+
+ m = m_head;
+ cur = frag = *txidx;
+
+ if (m_head->m_pkthdr.csum_flags) {
+ if (m_head->m_pkthdr.csum_flags & CSUM_IP)
+ csum_flags |= TI_BDFLAG_IP_CKSUM;
+ if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
+ csum_flags |= TI_BDFLAG_TCP_UDP_CKSUM;
+ if (m_head->m_flags & M_LASTFRAG)
+ csum_flags |= TI_BDFLAG_IP_FRAG_END;
+ else if (m_head->m_flags & M_FRAG)
+ csum_flags |= TI_BDFLAG_IP_FRAG;
+ }
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ if (frag > 383)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 6144);
+ else if (frag > 255)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 4096);
+ else if (frag > 127)
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE + 2048);
+ else
+ CSR_WRITE_4(sc, TI_WINBASE,
+ TI_TX_RING_BASE);
+ f = &sc->ti_rdata->ti_tx_ring_nic[frag % 128];
+ } else
+ f = &sc->ti_rdata->ti_tx_ring[frag];
+ if (sc->ti_cdata.ti_tx_chain[frag] != NULL)
+ break;
+ TI_HOSTADDR(f->ti_addr) = vtophys(mtod(m, vm_offset_t));
+ f->ti_len = m->m_len;
+ f->ti_flags = csum_flags;
+
+ if (ifv != NULL) {
+ f->ti_flags |= TI_BDFLAG_VLAN_TAG;
+ f->ti_vlan_tag = ifv->ifv_tag & 0xfff;
+ } else {
+ f->ti_vlan_tag = 0;
+ }
+
+ /*
+ * Sanity check: avoid coming within 16 descriptors
+ * of the end of the ring.
+ */
+ if ((TI_TX_RING_CNT - (sc->ti_txcnt + cnt)) < 16)
+ return(ENOBUFS);
+ cur = frag;
+ TI_INC(frag, TI_TX_RING_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ if (frag == sc->ti_tx_saved_considx)
+ return(ENOBUFS);
+
+ if (sc->ti_hwrev == TI_HWREV_TIGON)
+ sc->ti_rdata->ti_tx_ring_nic[cur % 128].ti_flags |=
+ TI_BDFLAG_END;
+ else
+ sc->ti_rdata->ti_tx_ring[cur].ti_flags |= TI_BDFLAG_END;
+ sc->ti_cdata.ti_tx_chain[cur] = m_head;
+ sc->ti_txcnt += cnt;
+
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit descriptors.
+ */
+static void ti_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ti_softc *sc;
+ struct mbuf *m_head = NULL;
+ u_int32_t prodidx = 0;
+
+ sc = ifp->if_softc;
+ TI_LOCK(sc);
+
+ prodidx = CSR_READ_4(sc, TI_MB_SENDPROD_IDX);
+
+ while(sc->ti_cdata.ti_tx_chain[prodidx] == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /*
+ * XXX
+ * safety overkill. If this is a fragmented packet chain
+ * with delayed TCP/UDP checksums, then only encapsulate
+ * it if we have enough descriptors to handle the entire
+ * chain at once.
+ * (paranoia -- may not actually be needed)
+ */
+ if (m_head->m_flags & M_FIRSTFRAG &&
+ m_head->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) {
+ if ((TI_TX_RING_CNT - sc->ti_txcnt) <
+ m_head->m_pkthdr.csum_data + 16) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ }
+
+ /*
+ * Pack the data into the transmit ring. If we
+ * don't have room, set the OACTIVE flag and wait
+ * for the NIC to drain the ring.
+ */
+ if (ti_encap(sc, m_head, &prodidx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+ }
+
+ /* Transmit */
+ CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, prodidx);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ TI_UNLOCK(sc);
+
+ return;
+}
+
+static void ti_init(xsc)
+ void *xsc;
+{
+ struct ti_softc *sc = xsc;
+
+ /* Cancel pending I/O and flush buffers. */
+ ti_stop(sc);
+
+ TI_LOCK(sc);
+ /* Init the gen info block, ring control blocks and firmware. */
+ if (ti_gibinit(sc)) {
+ printf("ti%d: initialization failure\n", sc->ti_unit);
+ TI_UNLOCK(sc);
+ return;
+ }
+
+ TI_UNLOCK(sc);
+
+ return;
+}
+
+static void ti_init2(sc)
+ struct ti_softc *sc;
+{
+ struct ti_cmd_desc cmd;
+ struct ifnet *ifp;
+ u_int16_t *m;
+ struct ifmedia *ifm;
+ int tmp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Specify MTU and interface index. */
+ CSR_WRITE_4(sc, TI_GCR_IFINDEX, ifp->if_unit);
+ CSR_WRITE_4(sc, TI_GCR_IFMTU, ifp->if_mtu +
+ ETHER_HDR_LEN + ETHER_CRC_LEN);
+ TI_DO_CMD(TI_CMD_UPDATE_GENCOM, 0, 0);
+
+ /* Load our MAC address. */
+ m = (u_int16_t *)&sc->arpcom.ac_enaddr[0];
+ CSR_WRITE_4(sc, TI_GCR_PAR0, htons(m[0]));
+ CSR_WRITE_4(sc, TI_GCR_PAR1, (htons(m[1]) << 16) | htons(m[2]));
+ TI_DO_CMD(TI_CMD_SET_MAC_ADDR, 0, 0);
+
+ /* Enable or disable promiscuous mode as needed. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_ENB, 0);
+ } else {
+ TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_DIS, 0);
+ }
+
+ /* Program multicast filter. */
+ ti_setmulti(sc);
+
+ /*
+ * If this is a Tigon 1, we should tell the
+ * firmware to use software packet filtering.
+ */
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ TI_DO_CMD(TI_CMD_FDR_FILTERING, TI_CMD_CODE_FILT_ENB, 0);
+ }
+
+ /* Init RX ring. */
+ ti_init_rx_ring_std(sc);
+
+ /* Init jumbo RX ring. */
+ if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN))
+ ti_init_rx_ring_jumbo(sc);
+
+ /*
+ * If this is a Tigon 2, we can also configure the
+ * mini ring.
+ */
+ if (sc->ti_hwrev == TI_HWREV_TIGON_II)
+ ti_init_rx_ring_mini(sc);
+
+ CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX, 0);
+ sc->ti_rx_saved_considx = 0;
+
+ /* Init TX ring. */
+ ti_init_tx_ring(sc);
+
+ /* Tell firmware we're alive. */
+ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_UP, 0);
+
+ /* Enable host interrupts. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Make sure to set media properly. We have to do this
+ * here since we have to issue commands in order to set
+ * the link negotiation and we can't issue commands until
+ * the firmware is running.
+ */
+ ifm = &sc->ifmedia;
+ tmp = ifm->ifm_media;
+ ifm->ifm_media = ifm->ifm_cur->ifm_media;
+ ti_ifmedia_upd(ifp);
+ ifm->ifm_media = tmp;
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int ti_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct ti_softc *sc;
+ struct ifmedia *ifm;
+ struct ti_cmd_desc cmd;
+ u_int32_t flowctl;
+
+ sc = ifp->if_softc;
+ ifm = &sc->ifmedia;
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return(EINVAL);
+
+ flowctl = 0;
+
+ switch(IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * Transmit flow control doesn't work on the Tigon 1.
+ */
+ flowctl = TI_GLNK_RX_FLOWCTL_Y;
+
+ /*
+ * Transmit flow control can also cause problems on the
+ * Tigon 2, apparantly with both the copper and fiber
+ * boards. The symptom is that the interface will just
+ * hang. This was reproduced with Alteon 180 switches.
+ */
+#if 0
+ if (sc->ti_hwrev != TI_HWREV_TIGON)
+ flowctl |= TI_GLNK_TX_FLOWCTL_Y;
+#endif
+
+ CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB|
+ TI_GLNK_FULL_DUPLEX| flowctl |
+ TI_GLNK_AUTONEGENB|TI_GLNK_ENB);
+
+ flowctl = TI_LNK_RX_FLOWCTL_Y;
+#if 0
+ if (sc->ti_hwrev != TI_HWREV_TIGON)
+ flowctl |= TI_LNK_TX_FLOWCTL_Y;
+#endif
+
+ CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_100MB|TI_LNK_10MB|
+ TI_LNK_FULL_DUPLEX|TI_LNK_HALF_DUPLEX| flowctl |
+ TI_LNK_AUTONEGENB|TI_LNK_ENB);
+ TI_DO_CMD(TI_CMD_LINK_NEGOTIATION,
+ TI_CMD_CODE_NEGOTIATE_BOTH, 0);
+ break;
+ case IFM_1000_SX:
+ case IFM_1000_T:
+ flowctl = TI_GLNK_RX_FLOWCTL_Y;
+#if 0
+ if (sc->ti_hwrev != TI_HWREV_TIGON)
+ flowctl |= TI_GLNK_TX_FLOWCTL_Y;
+#endif
+
+ CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB|
+ flowctl |TI_GLNK_ENB);
+ CSR_WRITE_4(sc, TI_GCR_LINK, 0);
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
+ TI_SETBIT(sc, TI_GCR_GLINK, TI_GLNK_FULL_DUPLEX);
+ }
+ TI_DO_CMD(TI_CMD_LINK_NEGOTIATION,
+ TI_CMD_CODE_NEGOTIATE_GIGABIT, 0);
+ break;
+ case IFM_100_FX:
+ case IFM_10_FL:
+ case IFM_100_TX:
+ case IFM_10_T:
+ flowctl = TI_LNK_RX_FLOWCTL_Y;
+#if 0
+ if (sc->ti_hwrev != TI_HWREV_TIGON)
+ flowctl |= TI_LNK_TX_FLOWCTL_Y;
+#endif
+
+ CSR_WRITE_4(sc, TI_GCR_GLINK, 0);
+ CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_ENB|TI_LNK_PREF|flowctl);
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX ||
+ IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
+ TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_100MB);
+ } else {
+ TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_10MB);
+ }
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
+ TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_FULL_DUPLEX);
+ } else {
+ TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_HALF_DUPLEX);
+ }
+ TI_DO_CMD(TI_CMD_LINK_NEGOTIATION,
+ TI_CMD_CODE_NEGOTIATE_10_100, 0);
+ break;
+ }
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void ti_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct ti_softc *sc;
+ u_int32_t media = 0;
+
+ sc = ifp->if_softc;
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN)
+ return;
+
+ ifmr->ifm_status |= IFM_ACTIVE;
+
+ if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) {
+ media = CSR_READ_4(sc, TI_GCR_GLINK_STAT);
+ if (sc->ti_copper)
+ ifmr->ifm_active |= IFM_1000_T;
+ else
+ ifmr->ifm_active |= IFM_1000_SX;
+ if (media & TI_GLNK_FULL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ } else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
+ media = CSR_READ_4(sc, TI_GCR_LINK_STAT);
+ if (sc->ti_copper) {
+ if (media & TI_LNK_100MB)
+ ifmr->ifm_active |= IFM_100_TX;
+ if (media & TI_LNK_10MB)
+ ifmr->ifm_active |= IFM_10_T;
+ } else {
+ if (media & TI_LNK_100MB)
+ ifmr->ifm_active |= IFM_100_FX;
+ if (media & TI_LNK_10MB)
+ ifmr->ifm_active |= IFM_10_FL;
+ }
+ if (media & TI_LNK_FULL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ if (media & TI_LNK_HALF_DUPLEX)
+ ifmr->ifm_active |= IFM_HDX;
+ }
+
+ return;
+}
+
+static int ti_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct ti_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int mask, error = 0;
+ struct ti_cmd_desc cmd;
+
+ TI_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > TI_JUMBO_MTU)
+ error = EINVAL;
+ else {
+ ifp->if_mtu = ifr->ifr_mtu;
+ ti_init(sc);
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ /*
+ * If only the state of the PROMISC flag changed,
+ * then just use the 'set promisc mode' command
+ * instead of reinitializing the entire NIC. Doing
+ * a full re-init means reloading the firmware and
+ * waiting for it to start up, which may take a
+ * second or two.
+ */
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->ti_if_flags & IFF_PROMISC)) {
+ TI_DO_CMD(TI_CMD_SET_PROMISC_MODE,
+ TI_CMD_CODE_PROMISC_ENB, 0);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->ti_if_flags & IFF_PROMISC) {
+ TI_DO_CMD(TI_CMD_SET_PROMISC_MODE,
+ TI_CMD_CODE_PROMISC_DIS, 0);
+ } else
+ ti_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING) {
+ ti_stop(sc);
+ }
+ }
+ sc->ti_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifp->if_flags & IFF_RUNNING) {
+ ti_setmulti(sc);
+ error = 0;
+ }
+ break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ break;
+ case SIOCSIFCAP:
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if (mask & IFCAP_HWCSUM) {
+ if (IFCAP_HWCSUM & ifp->if_capenable)
+ ifp->if_capenable &= ~IFCAP_HWCSUM;
+ else
+ ifp->if_capenable |= IFCAP_HWCSUM;
+ if (ifp->if_flags & IFF_RUNNING)
+ ti_init(sc);
+ }
+ error = 0;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ TI_UNLOCK(sc);
+
+ return(error);
+}
+
+static int
+ti_open(dev_t dev, int flags, int fmt, struct thread *td)
+{
+ int unit;
+ struct ti_softc *sc;
+
+ unit = minor(dev) & 0xff;
+
+ sc = ti_lookup_softc(unit);
+
+ if (sc == NULL)
+ return(ENODEV);
+
+ TI_LOCK(sc);
+ sc->ti_flags |= TI_FLAG_DEBUGING;
+ TI_UNLOCK(sc);
+
+ return(0);
+}
+
+static int
+ti_close(dev_t dev, int flag, int fmt, struct thread *td)
+{
+ int unit;
+ struct ti_softc *sc;
+
+ unit = minor(dev) & 0xff;
+
+ sc = ti_lookup_softc(unit);
+
+ if (sc == NULL)
+ return(ENODEV);
+
+ TI_LOCK(sc);
+ sc->ti_flags &= ~TI_FLAG_DEBUGING;
+ TI_UNLOCK(sc);
+
+ return(0);
+}
+
+/*
+ * This ioctl routine goes along with the Tigon character device.
+ */
+static int
+ti_ioctl2(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
+{
+ int unit, error;
+ struct ti_softc *sc;
+
+ unit = minor(dev) & 0xff;
+
+ sc = ti_lookup_softc(unit);
+
+ if (sc == NULL)
+ return(ENODEV);
+
+ error = 0;
+
+ switch(cmd) {
+ case TIIOCGETSTATS:
+ {
+ struct ti_stats *outstats;
+
+ outstats = (struct ti_stats *)addr;
+
+ bcopy(&sc->ti_rdata->ti_info.ti_stats, outstats,
+ sizeof(struct ti_stats));
+ break;
+ }
+ case TIIOCGETPARAMS:
+ {
+ struct ti_params *params;
+
+ params = (struct ti_params *)addr;
+
+ params->ti_stat_ticks = sc->ti_stat_ticks;
+ params->ti_rx_coal_ticks = sc->ti_rx_coal_ticks;
+ params->ti_tx_coal_ticks = sc->ti_tx_coal_ticks;
+ params->ti_rx_max_coal_bds = sc->ti_rx_max_coal_bds;
+ params->ti_tx_max_coal_bds = sc->ti_tx_max_coal_bds;
+ params->ti_tx_buf_ratio = sc->ti_tx_buf_ratio;
+ params->param_mask = TI_PARAM_ALL;
+
+ error = 0;
+
+ break;
+ }
+ case TIIOCSETPARAMS:
+ {
+ struct ti_params *params;
+
+ params = (struct ti_params *)addr;
+
+ if (params->param_mask & TI_PARAM_STAT_TICKS) {
+ sc->ti_stat_ticks = params->ti_stat_ticks;
+ CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks);
+ }
+
+ if (params->param_mask & TI_PARAM_RX_COAL_TICKS) {
+ sc->ti_rx_coal_ticks = params->ti_rx_coal_ticks;
+ CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS,
+ sc->ti_rx_coal_ticks);
+ }
+
+ if (params->param_mask & TI_PARAM_TX_COAL_TICKS) {
+ sc->ti_tx_coal_ticks = params->ti_tx_coal_ticks;
+ CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS,
+ sc->ti_tx_coal_ticks);
+ }
+
+ if (params->param_mask & TI_PARAM_RX_COAL_BDS) {
+ sc->ti_rx_max_coal_bds = params->ti_rx_max_coal_bds;
+ CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD,
+ sc->ti_rx_max_coal_bds);
+ }
+
+ if (params->param_mask & TI_PARAM_TX_COAL_BDS) {
+ sc->ti_tx_max_coal_bds = params->ti_tx_max_coal_bds;
+ CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD,
+ sc->ti_tx_max_coal_bds);
+ }
+
+ if (params->param_mask & TI_PARAM_TX_BUF_RATIO) {
+ sc->ti_tx_buf_ratio = params->ti_tx_buf_ratio;
+ CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO,
+ sc->ti_tx_buf_ratio);
+ }
+
+ error = 0;
+
+ break;
+ }
+ case TIIOCSETTRACE: {
+ ti_trace_type trace_type;
+
+ trace_type = *(ti_trace_type *)addr;
+
+ /*
+ * Set tracing to whatever the user asked for. Setting
+ * this register to 0 should have the effect of disabling
+ * tracing.
+ */
+ CSR_WRITE_4(sc, TI_GCR_NIC_TRACING, trace_type);
+
+ error = 0;
+
+ break;
+ }
+ case TIIOCGETTRACE: {
+ struct ti_trace_buf *trace_buf;
+ u_int32_t trace_start, cur_trace_ptr, trace_len;
+
+ trace_buf = (struct ti_trace_buf *)addr;
+
+ trace_start = CSR_READ_4(sc, TI_GCR_NICTRACE_START);
+ cur_trace_ptr = CSR_READ_4(sc, TI_GCR_NICTRACE_PTR);
+ trace_len = CSR_READ_4(sc, TI_GCR_NICTRACE_LEN);
+
+#if 0
+ printf("ti%d: trace_start = %#x, cur_trace_ptr = %#x, "
+ "trace_len = %d\n", sc->ti_unit, trace_start,
+ cur_trace_ptr, trace_len);
+ printf("ti%d: trace_buf->buf_len = %d\n", sc->ti_unit,
+ trace_buf->buf_len);
+#endif
+
+ error = ti_copy_mem(sc, trace_start, min(trace_len,
+ trace_buf->buf_len),
+ (caddr_t)trace_buf->buf, 1, 1);
+
+ if (error == 0) {
+ trace_buf->fill_len = min(trace_len,
+ trace_buf->buf_len);
+ if (cur_trace_ptr < trace_start)
+ trace_buf->cur_trace_ptr =
+ trace_start - cur_trace_ptr;
+ else
+ trace_buf->cur_trace_ptr =
+ cur_trace_ptr - trace_start;
+ } else
+ trace_buf->fill_len = 0;
+
+
+ break;
+ }
+
+ /*
+ * For debugging, five ioctls are needed:
+ * ALT_ATTACH
+ * ALT_READ_TG_REG
+ * ALT_WRITE_TG_REG
+ * ALT_READ_TG_MEM
+ * ALT_WRITE_TG_MEM
+ */
+ case ALT_ATTACH:
+ /*
+ * From what I can tell, Alteon's Solaris Tigon driver
+ * only has one character device, so you have to attach
+ * to the Tigon board you're interested in. This seems
+ * like a not-so-good way to do things, since unless you
+ * subsequently specify the unit number of the device
+ * you're interested in in every ioctl, you'll only be
+ * able to debug one board at a time.
+ */
+ error = 0;
+ break;
+ case ALT_READ_TG_MEM:
+ case ALT_WRITE_TG_MEM:
+ {
+ struct tg_mem *mem_param;
+ u_int32_t sram_end, scratch_end;
+
+ mem_param = (struct tg_mem *)addr;
+
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ sram_end = TI_END_SRAM_I;
+ scratch_end = TI_END_SCRATCH_I;
+ } else {
+ sram_end = TI_END_SRAM_II;
+ scratch_end = TI_END_SCRATCH_II;
+ }
+
+ /*
+ * For now, we'll only handle accessing regular SRAM,
+ * nothing else.
+ */
+ if ((mem_param->tgAddr >= TI_BEG_SRAM)
+ && ((mem_param->tgAddr + mem_param->len) <= sram_end)) {
+ /*
+ * In this instance, we always copy to/from user
+ * space, so the user space argument is set to 1.
+ */
+ error = ti_copy_mem(sc, mem_param->tgAddr,
+ mem_param->len,
+ mem_param->userAddr, 1,
+ (cmd == ALT_READ_TG_MEM) ? 1 : 0);
+ } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH)
+ && (mem_param->tgAddr <= scratch_end)) {
+ error = ti_copy_scratch(sc, mem_param->tgAddr,
+ mem_param->len,
+ mem_param->userAddr, 1,
+ (cmd == ALT_READ_TG_MEM) ?
+ 1 : 0, TI_PROCESSOR_A);
+ } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH_B_DEBUG)
+ && (mem_param->tgAddr <= TI_BEG_SCRATCH_B_DEBUG)) {
+ if (sc->ti_hwrev == TI_HWREV_TIGON) {
+ printf("ti%d: invalid memory range for "
+ "Tigon I\n", sc->ti_unit);
+ error = EINVAL;
+ break;
+ }
+ error = ti_copy_scratch(sc, mem_param->tgAddr -
+ TI_SCRATCH_DEBUG_OFF,
+ mem_param->len,
+ mem_param->userAddr, 1,
+ (cmd == ALT_READ_TG_MEM) ?
+ 1 : 0, TI_PROCESSOR_B);
+ } else {
+ printf("ti%d: memory address %#x len %d is out of "
+ "supported range\n", sc->ti_unit,
+ mem_param->tgAddr, mem_param->len);
+ error = EINVAL;
+ }
+
+ break;
+ }
+ case ALT_READ_TG_REG:
+ case ALT_WRITE_TG_REG:
+ {
+ struct tg_reg *regs;
+ u_int32_t tmpval;
+
+ regs = (struct tg_reg *)addr;
+
+ /*
+ * Make sure the address in question isn't out of range.
+ */
+ if (regs->addr > TI_REG_MAX) {
+ error = EINVAL;
+ break;
+ }
+ if (cmd == ALT_READ_TG_REG) {
+ bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle,
+ regs->addr, &tmpval, 1);
+ regs->data = ntohl(tmpval);
+#if 0
+ if ((regs->addr == TI_CPU_STATE)
+ || (regs->addr == TI_CPU_CTL_B)) {
+ printf("ti%d: register %#x = %#x\n",
+ sc->ti_unit, regs->addr, tmpval);
+ }
+#endif
+ } else {
+ tmpval = htonl(regs->data);
+ bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle,
+ regs->addr, &tmpval, 1);
+ }
+
+ break;
+ }
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return(error);
+}
+
+static void ti_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct ti_softc *sc;
+
+ sc = ifp->if_softc;
+ TI_LOCK(sc);
+
+ /*
+ * When we're debugging, the chip is often stopped for long periods
+ * of time, and that would normally cause the watchdog timer to fire.
+ * Since that impedes debugging, we don't want to do that.
+ */
+ if (sc->ti_flags & TI_FLAG_DEBUGING) {
+ TI_UNLOCK(sc);
+ return;
+ }
+
+ printf("ti%d: watchdog timeout -- resetting\n", sc->ti_unit);
+ ti_stop(sc);
+ ti_init(sc);
+
+ ifp->if_oerrors++;
+ TI_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void ti_stop(sc)
+ struct ti_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ti_cmd_desc cmd;
+
+ TI_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Disable host interrupts. */
+ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1);
+ /*
+ * Tell firmware we're shutting down.
+ */
+ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_DOWN, 0);
+
+ /* Halt and reinitialize. */
+ ti_chipinit(sc);
+ ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL);
+ ti_chipinit(sc);
+
+ /* Free the RX lists. */
+ ti_free_rx_ring_std(sc);
+
+ /* Free jumbo RX list. */
+ ti_free_rx_ring_jumbo(sc);
+
+ /* Free mini RX list. */
+ ti_free_rx_ring_mini(sc);
+
+ /* Free TX buffers. */
+ ti_free_tx_ring(sc);
+
+ sc->ti_ev_prodidx.ti_idx = 0;
+ sc->ti_return_prodidx.ti_idx = 0;
+ sc->ti_tx_considx.ti_idx = 0;
+ sc->ti_tx_saved_considx = TI_TXCONS_UNSET;
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ TI_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void ti_shutdown(dev)
+ device_t dev;
+{
+ struct ti_softc *sc;
+
+ sc = device_get_softc(dev);
+ TI_LOCK(sc);
+ ti_chipinit(sc);
+ TI_UNLOCK(sc);
+
+ return;
+}
diff --git a/sys/pci/if_tireg.h b/sys/pci/if_tireg.h
new file mode 100644
index 0000000..e1d56f8
--- /dev/null
+++ b/sys/pci/if_tireg.h
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Tigon register offsets. These are memory mapped registers
+ * which can be accessed with the CSR_READ_4()/CSR_WRITE_4() macros.
+ * Each register must be accessed using 32 bit operations.
+ *
+ * All reegisters are accessed through a 16K shared memory block.
+ * The first group of registers are actually copies of the PCI
+ * configuration space registers.
+ */
+
+#define TI_PCI_ID 0x000 /* PCI device/vendor ID */
+#define TI_PCI_CMDSTAT 0x004
+#define TI_PCI_CLASSCODE 0x008
+#define TI_PCI_BIST 0x00C
+#define TI_PCI_LOMEM 0x010 /* Shared memory base address */
+#define TI_PCI_SUBSYS 0x02C
+#define TI_PCI_ROMBASE 0x030
+#define TI_PCI_INT 0x03C
+
+#ifndef PCIM_CMD_MWIEN
+#define PCIM_CMD_MWIEN 0x0010
+#endif
+
+/*
+ * Alteon AceNIC PCI vendor/device ID.
+ */
+#define ALT_VENDORID 0x12AE
+#define ALT_DEVICEID_ACENIC 0x0001
+#define ALT_DEVICEID_ACENIC_COPPER 0x0002
+
+/*
+ * 3Com 3c985 PCI vendor/device ID.
+ */
+#define TC_VENDORID 0x10B7
+#define TC_DEVICEID_3C985 0x0001
+
+/*
+ * Netgear GA620 PCI vendor/device ID.
+ */
+#define NG_VENDORID 0x1385
+#define NG_DEVICEID_GA620 0x620A
+#define NG_DEVICEID_GA620T 0x630A
+
+/*
+ * SGI device/vendor ID.
+ */
+#define SGI_VENDORID 0x10A9
+#define SGI_DEVICEID_TIGON 0x0009
+
+/*
+ * DEC vendor ID, Farallon device ID. Apparently, Farallon used
+ * the DEC vendor ID in their cards by mistake.
+ */
+#define DEC_VENDORID 0x1011
+#define DEC_DEVICEID_FARALLON_PN9000SX 0x001a
+
+/*
+ * Tigon configuration and control registers.
+ */
+#define TI_MISC_HOST_CTL 0x040
+#define TI_MISC_LOCAL_CTL 0x044
+#define TI_SEM_AB 0x048 /* Tigon 2 only */
+#define TI_MISC_CONF 0x050 /* Tigon 2 only */
+#define TI_TIMER_BITS 0x054
+#define TI_TIMERREF 0x058
+#define TI_PCI_STATE 0x05C
+#define TI_MAIN_EVENT_A 0x060
+#define TI_MAILBOX_EVENT_A 0x064
+#define TI_WINBASE 0x068
+#define TI_WINDATA 0x06C
+#define TI_MAIN_EVENT_B 0x070 /* Tigon 2 only */
+#define TI_MAILBOX_EVENT_B 0x074 /* Tigon 2 only */
+#define TI_TIMERREF_B 0x078 /* Tigon 2 only */
+#define TI_SERIAL 0x07C
+
+/*
+ * Misc host control bits.
+ */
+#define TI_MHC_INTSTATE 0x00000001
+#define TI_MHC_CLEARINT 0x00000002
+#define TI_MHC_RESET 0x00000008
+#define TI_MHC_BYTE_SWAP_ENB 0x00000010
+#define TI_MHC_WORD_SWAP_ENB 0x00000020
+#define TI_MHC_MASK_INTS 0x00000040
+#define TI_MHC_CHIP_REV_MASK 0xF0000000
+
+#define TI_MHC_BIGENDIAN_INIT \
+ (TI_MHC_BYTE_SWAP_ENB|TI_MHC_WORD_SWAP_ENB|TI_MHC_CLEARINT)
+
+#define TI_MHC_LITTLEENDIAN_INIT \
+ (TI_MHC_WORD_SWAP_ENB|TI_MHC_CLEARINT)
+
+/*
+ * Tigon chip rev values. Rev 4 is the Tigon 1. Rev 6 is the Tigon 2.
+ * Rev 5 is also the Tigon 2, but is a broken version which was never
+ * used in any actual hardware, so we ignore it.
+ */
+#define TI_REV_TIGON_I 0x40000000
+#define TI_REV_TIGON_II 0x60000000
+
+/*
+ * Firmware revision that we want.
+ */
+#define TI_FIRMWARE_MAJOR 0xc
+#define TI_FIRMWARE_MINOR 0x4
+#define TI_FIRMWARE_FIX 0xb
+
+/*
+ * Miscelaneous Local Control register.
+ */
+#define TI_MLC_EE_WRITE_ENB 0x00000010
+#define TI_MLC_SRAM_BANK_SIZE 0x00000300 /* Tigon 2 only */
+#define TI_MLC_LOCALADDR_21 0x00004000
+#define TI_MLC_LOCALADDR_22 0x00008000
+#define TI_MLC_SBUS_WRITEERR 0x00080000
+#define TI_MLC_EE_CLK 0x00100000
+#define TI_MLC_EE_TXEN 0x00200000
+#define TI_MLC_EE_DOUT 0x00400000
+#define TI_MLC_EE_DIN 0x00800000
+
+/* Possible memory sizes. */
+#define TI_MLC_SRAM_BANK_DISA 0x00000000
+#define TI_MLC_SRAM_BANK_1024K 0x00000100
+#define TI_MLC_SRAM_BANK_512K 0x00000200
+#define TI_MLC_SRAM_BANK_256K 0x00000300
+
+/*
+ * Offset of MAC address inside EEPROM.
+ */
+#define TI_EE_MAC_OFFSET 0x8c
+
+#define TI_DMA_ASSIST 0x11C
+#define TI_CPU_STATE 0x140
+#define TI_CPU_PROGRAM_COUNTER 0x144
+#define TI_SRAM_ADDR 0x154
+#define TI_SRAM_DATA 0x158
+#define TI_GEN_0 0x180
+#define TI_GEN_X 0x1FC
+#define TI_MAC_TX_STATE 0x200
+#define TI_MAC_RX_STATE 0x220
+#define TI_CPU_CTL_B 0x240 /* Tigon 2 only */
+#define TI_CPU_PROGRAM_COUNTER_B 0x244 /* Tigon 2 only */
+#define TI_SRAM_ADDR_B 0x254 /* Tigon 2 only */
+#define TI_SRAM_DATA_B 0x258 /* Tigon 2 only */
+#define TI_GEN_B_0 0x280 /* Tigon 2 only */
+#define TI_GEN_B_X 0x2FC /* Tigon 2 only */
+
+/*
+ * Misc config register.
+ */
+#define TI_MCR_SRAM_SYNCHRONOUS 0x00100000 /* Tigon 2 only */
+
+/*
+ * PCI state register.
+ */
+#define TI_PCISTATE_FORCE_RESET 0x00000001
+#define TI_PCISTATE_PROVIDE_LEN 0x00000002
+#define TI_PCISTATE_READ_MAXDMA 0x0000001C
+#define TI_PCISTATE_WRITE_MAXDMA 0x000000E0
+#define TI_PCISTATE_MINDMA 0x0000FF00
+#define TI_PCISTATE_FIFO_RETRY_ENB 0x00010000
+#define TI_PCISTATE_USE_MEM_RD_MULT 0x00020000
+#define TI_PCISTATE_NO_SWAP_READ_DMA 0x00040000
+#define TI_PCISTATE_NO_SWAP_WRITE_DMA 0x00080000
+#define TI_PCISTATE_66MHZ_BUS 0x00080000 /* Tigon 2 only */
+#define TI_PCISTATE_32BIT_BUS 0x00100000 /* Tigon 2 only */
+#define TI_PCISTATE_ENB_BYTE_ENABLES 0x00800000 /* Tigon 2 only */
+#define TI_PCISTATE_READ_CMD 0x0F000000
+#define TI_PCISTATE_WRITE_CMD 0xF0000000
+
+#define TI_PCI_READMAX_4 0x04
+#define TI_PCI_READMAX_16 0x08
+#define TI_PCI_READMAX_32 0x0C
+#define TI_PCI_READMAX_64 0x10
+#define TI_PCI_READMAX_128 0x14
+#define TI_PCI_READMAX_256 0x18
+#define TI_PCI_READMAX_1024 0x1C
+
+#define TI_PCI_WRITEMAX_4 0x20
+#define TI_PCI_WRITEMAX_16 0x40
+#define TI_PCI_WRITEMAX_32 0x60
+#define TI_PCI_WRITEMAX_64 0x80
+#define TI_PCI_WRITEMAX_128 0xA0
+#define TI_PCI_WRITEMAX_256 0xC0
+#define TI_PCI_WRITEMAX_1024 0xE0
+
+#define TI_PCI_READ_CMD 0x06000000
+#define TI_PCI_WRITE_CMD 0x70000000
+
+/*
+ * DMA state register.
+ */
+#define TI_DMASTATE_ENABLE 0x00000001
+#define TI_DMASTATE_PAUSE 0x00000002
+
+/*
+ * CPU state register.
+ */
+#define TI_CPUSTATE_RESET 0x00000001
+#define TI_CPUSTATE_STEP 0x00000002
+#define TI_CPUSTATE_ROMFAIL 0x00000010
+#define TI_CPUSTATE_HALT 0x00010000
+/*
+ * MAC TX state register
+ */
+#define TI_TXSTATE_RESET 0x00000001
+#define TI_TXSTATE_ENB 0x00000002
+#define TI_TXSTATE_STOP 0x00000004
+
+/*
+ * MAC RX state register
+ */
+#define TI_RXSTATE_RESET 0x00000001
+#define TI_RXSTATE_ENB 0x00000002
+#define TI_RXSTATE_STOP 0x00000004
+
+/*
+ * Tigon 2 mailbox registers. The mailbox area consists of 256 bytes
+ * split into 64 bit registers. Only the lower 32 bits of each mailbox
+ * are used.
+ */
+#define TI_MB_HOSTINTR_HI 0x500
+#define TI_MB_HOSTINTR_LO 0x504
+#define TI_MB_HOSTINTR TI_MB_HOSTINTR_LO
+#define TI_MB_CMDPROD_IDX_HI 0x508
+#define TI_MB_CMDPROD_IDX_LO 0x50C
+#define TI_MB_CMDPROD_IDX TI_MB_CMDPROD_IDX_LO
+#define TI_MB_SENDPROD_IDX_HI 0x510
+#define TI_MB_SENDPROD_IDX_LO 0x514
+#define TI_MB_SENDPROD_IDX TI_MB_SENDPROD_IDX_LO
+#define TI_MB_STDRXPROD_IDX_HI 0x518 /* Tigon 2 only */
+#define TI_MB_STDRXPROD_IDX_LO 0x51C /* Tigon 2 only */
+#define TI_MB_STDRXPROD_IDX TI_MB_STDRXPROD_IDX_LO
+#define TI_MB_JUMBORXPROD_IDX_HI 0x520 /* Tigon 2 only */
+#define TI_MB_JUMBORXPROD_IDX_LO 0x524 /* Tigon 2 only */
+#define TI_MB_JUMBORXPROD_IDX TI_MB_JUMBORXPROD_IDX_LO
+#define TI_MB_MINIRXPROD_IDX_HI 0x528 /* Tigon 2 only */
+#define TI_MB_MINIRXPROD_IDX_LO 0x52C /* Tigon 2 only */
+#define TI_MB_MINIRXPROD_IDX TI_MB_MINIRXPROD_IDX_LO
+#define TI_MB_RSVD 0x530
+
+/*
+ * Tigon 2 general communication registers. These are 64 and 32 bit
+ * registers which are only valid after the firmware has been
+ * loaded and started. They actually exist in NIC memory but are
+ * mapped into the host memory via the shared memory region.
+ *
+ * The NIC internally maps these registers starting at address 0,
+ * so to determine the NIC address of any of these registers, we
+ * subtract 0x600 (the address of the first register).
+ */
+
+#define TI_GCR_BASE 0x600
+#define TI_GCR_MACADDR 0x600
+#define TI_GCR_PAR0 0x600
+#define TI_GCR_PAR1 0x604
+#define TI_GCR_GENINFO_HI 0x608
+#define TI_GCR_GENINFO_LO 0x60C
+#define TI_GCR_MCASTADDR 0x610 /* obsolete */
+#define TI_GCR_MAR0 0x610 /* obsolete */
+#define TI_GCR_MAR1 0x614 /* obsolete */
+#define TI_GCR_OPMODE 0x618
+#define TI_GCR_DMA_READCFG 0x61C
+#define TI_GCR_DMA_WRITECFG 0x620
+#define TI_GCR_TX_BUFFER_RATIO 0x624
+#define TI_GCR_EVENTCONS_IDX 0x628
+#define TI_GCR_CMDCONS_IDX 0x62C
+#define TI_GCR_TUNEPARMS 0x630
+#define TI_GCR_RX_COAL_TICKS 0x630
+#define TI_GCR_TX_COAL_TICKS 0x634
+#define TI_GCR_STAT_TICKS 0x638
+#define TI_GCR_TX_MAX_COAL_BD 0x63C
+#define TI_GCR_RX_MAX_COAL_BD 0x640
+#define TI_GCR_NIC_TRACING 0x644
+#define TI_GCR_GLINK 0x648
+#define TI_GCR_LINK 0x64C
+#define TI_GCR_NICTRACE_PTR 0x650
+#define TI_GCR_NICTRACE_START 0x654
+#define TI_GCR_NICTRACE_LEN 0x658
+#define TI_GCR_IFINDEX 0x65C
+#define TI_GCR_IFMTU 0x660
+#define TI_GCR_MASK_INTRS 0x664
+#define TI_GCR_GLINK_STAT 0x668
+#define TI_GCR_LINK_STAT 0x66C
+#define TI_GCR_RXRETURNCONS_IDX 0x680
+#define TI_GCR_CMDRING 0x700
+
+#define TI_GCR_NIC_ADDR(x) (x - TI_GCR_BASE);
+
+/*
+ * Local memory window. The local memory window is a 2K shared
+ * memory region which can be used to access the NIC's internal
+ * SRAM. The window can be mapped to a given 2K region using
+ * the TI_WINDOW_BASE register.
+ */
+#define TI_WINDOW 0x800
+#define TI_WINLEN 0x800
+
+#define TI_TICKS_PER_SEC 1000000
+
+/*
+ * Operation mode register.
+ */
+#define TI_OPMODE_BYTESWAP_BD 0x00000002
+#define TI_OPMODE_WORDSWAP_BD 0x00000004
+#define TI_OPMODE_WARN_ENB 0x00000008 /* not yet implimented */
+#define TI_OPMODE_BYTESWAP_DATA 0x00000010
+#define TI_OPMODE_1_DMA_ACTIVE 0x00000040
+#define TI_OPMODE_SBUS 0x00000100
+#define TI_OPMODE_DONT_FRAG_JUMBO 0x00000200
+#define TI_OPMODE_INCLUDE_CRC 0x00000400
+#define TI_OPMODE_RX_BADFRAMES 0x00000800
+#define TI_OPMODE_NO_EVENT_INTRS 0x00001000
+#define TI_OPMODE_NO_TX_INTRS 0x00002000
+#define TI_OPMODE_NO_RX_INTRS 0x00004000
+#define TI_OPMODE_FATAL_ENB 0x40000000 /* not yet implimented */
+#define TI_OPMODE_JUMBO_HDRSPLIT 0x00008000
+
+/*
+ * DMA configuration thresholds.
+ */
+#define TI_DMA_STATE_THRESH_16W 0x00000100
+#define TI_DMA_STATE_THRESH_8W 0x00000080
+#define TI_DMA_STATE_THRESH_4W 0x00000040
+#define TI_DMA_STATE_THRESH_2W 0x00000020
+#define TI_DMA_STATE_THRESH_1W 0x00000010
+
+#define TI_DMA_STATE_FORCE_32_BIT 0x00000008
+
+/*
+ * Gigabit link status bits.
+ */
+#define TI_GLNK_SENSE_NO_BEG 0x00002000
+#define TI_GLNK_LOOPBACK 0x00004000
+#define TI_GLNK_PREF 0x00008000
+#define TI_GLNK_1000MB 0x00040000
+#define TI_GLNK_FULL_DUPLEX 0x00080000
+#define TI_GLNK_TX_FLOWCTL_Y 0x00200000 /* Tigon 2 only */
+#define TI_GLNK_RX_FLOWCTL_Y 0x00800000
+#define TI_GLNK_AUTONEGENB 0x20000000
+#define TI_GLNK_ENB 0x40000000
+
+/*
+ * Link status bits.
+ */
+#define TI_LNK_LOOPBACK 0x00004000
+#define TI_LNK_PREF 0x00008000
+#define TI_LNK_10MB 0x00010000
+#define TI_LNK_100MB 0x00020000
+#define TI_LNK_1000MB 0x00040000
+#define TI_LNK_FULL_DUPLEX 0x00080000
+#define TI_LNK_HALF_DUPLEX 0x00100000
+#define TI_LNK_TX_FLOWCTL_Y 0x00200000 /* Tigon 2 only */
+#define TI_LNK_RX_FLOWCTL_Y 0x00800000
+#define TI_LNK_AUTONEGENB 0x20000000
+#define TI_LNK_ENB 0x40000000
+
+/*
+ * Ring size constants.
+ */
+#define TI_EVENT_RING_CNT 256
+#define TI_CMD_RING_CNT 64
+#define TI_STD_RX_RING_CNT 512
+#define TI_JUMBO_RX_RING_CNT 256
+#define TI_MINI_RX_RING_CNT 1024
+#define TI_RETURN_RING_CNT 2048
+
+/*
+ * Possible TX ring sizes.
+ */
+#define TI_TX_RING_CNT_128 128
+#define TI_TX_RING_BASE_128 0x3800
+
+#define TI_TX_RING_CNT_256 256
+#define TI_TX_RING_BASE_256 0x3000
+
+#define TI_TX_RING_CNT_512 512
+#define TI_TX_RING_BASE_512 0x2000
+
+#define TI_TX_RING_CNT TI_TX_RING_CNT_512
+#define TI_TX_RING_BASE TI_TX_RING_BASE_512
+
+/*
+ * The Tigon can have up to 8MB of external SRAM, however the Tigon 1
+ * is limited to 2MB total, and in general I think most adapters have
+ * around 1MB. We use this value for zeroing the NIC's SRAM, so to
+ * be safe we use the largest possible value (zeroing memory that
+ * isn't there doesn't hurt anything).
+ */
+#define TI_MEM_MAX 0x7FFFFF
+
+/*
+ * Maximum register address on the Tigon.
+ */
+#define TI_REG_MAX 0x3fff
+
+/*
+ * These values were taken from Alteon's tg.h.
+ */
+#define TI_BEG_SRAM 0x0 /* host thinks it's here */
+#define TI_BEG_SCRATCH 0xc00000 /* beg of scratch pad area */
+#define TI_END_SRAM_II 0x800000 /* end of SRAM, for 2 MB stuffed */
+#define TI_END_SCRATCH_II 0xc04000 /* end of scratch pad CPU A (16KB) */
+#define TI_END_SCRATCH_B 0xc02000 /* end of scratch pad CPU B (8KB) */
+#define TI_BEG_SCRATCH_B_DEBUG 0xd00000 /* beg of scratch pad for ioctl */
+#define TI_END_SCRATCH_B_DEBUG 0xd02000 /* end of scratch pad for ioctl */
+#define TI_SCRATCH_DEBUG_OFF 0x100000 /* offset for ioctl usage */
+#define TI_END_SRAM_I 0x200000 /* end of SRAM, for 2 MB stuffed */
+#define TI_END_SCRATCH_I 0xc00800 /* end of scratch pad area (2KB) */
+#define TI_BEG_PROM 0x40000000 /* beg of PROM, special access */
+#define TI_BEG_FLASH 0x80000000 /* beg of EEPROM, special access */
+#define TI_END_FLASH 0x80100000 /* end of EEPROM for 1 MB stuff */
+#define TI_BEG_SER_EEPROM 0xa0000000 /* beg of Serial EEPROM (fake out) */
+#define TI_END_SER_EEPROM 0xa0002000 /* end of Serial EEPROM (fake out) */
+#define TI_BEG_REGS 0xc0000000 /* beg of register area */
+#define TI_END_REGS 0xc0000400 /* end of register area */
+#define TI_END_WRITE_REGS 0xc0000180 /* can't write GPRs currently */
+#define TI_BEG_REGS2 0xc0000200 /* beg of second writeable reg area */
+/* the EEPROM is byte addressable in a pretty odd way */
+#define EEPROM_BYTE_LOC 0xff000000
+
+/*
+ * From Alteon's tg.h.
+ */
+#define TI_PROCESSOR_A 0
+#define TI_PROCESSOR_B 1
+#define TI_CPU_A TG_PROCESSOR_A
+#define TI_CPU_B TG_PROCESSOR_B
+
+/*
+ * Following macro can be used to access to any of the CPU registers
+ * It will adjust the address appropriately.
+ * Parameters:
+ * reg - The register to access, e.g TI_CPU_CONTROL
+ * cpu - cpu, i.e PROCESSOR_A or PROCESSOR_B (or TI_CPU_A or TI_CPU_B)
+ */
+#define CPU_REG(reg, cpu) ((reg) + (cpu) * 0x100)
+
+/*
+ * Even on the alpha, pci addresses are 32-bit quantities
+ */
+
+#ifdef __64_bit_pci_addressing__
+typedef struct {
+ u_int64_t ti_addr;
+} ti_hostaddr;
+#define TI_HOSTADDR(x) x.ti_addr
+#else
+typedef struct {
+ u_int32_t ti_addr_hi;
+ u_int32_t ti_addr_lo;
+} ti_hostaddr;
+#define TI_HOSTADDR(x) x.ti_addr_lo
+#endif
+
+/*
+ * Ring control block structure. The rules for the max_len field
+ * are as follows:
+ *
+ * For the send ring, max_len indicates the number of entries in the
+ * ring (128, 256 or 512).
+ *
+ * For the standard receive ring, max_len indicates the threshold
+ * used to decide when a frame should be put in the jumbo receive ring
+ * instead of the standard one.
+ *
+ * For the mini ring, max_len indicates the size of the buffers in the
+ * ring. This is the value used to decide when a frame is small enough
+ * to be placed in the mini ring.
+ *
+ * For the return receive ring, max_len indicates the number of entries
+ * in the ring. It can be one of 2048, 1024 or 0 (which is the same as
+ * 2048 for backwards compatibility). The value 1024 can only be used
+ * if the mini ring is disabled.
+ */
+struct ti_rcb {
+ ti_hostaddr ti_hostaddr;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_max_len;
+ u_int16_t ti_flags;
+#else
+ u_int16_t ti_flags;
+ u_int16_t ti_max_len;
+#endif
+ u_int32_t ti_unused;
+};
+
+#define TI_RCB_FLAG_TCP_UDP_CKSUM 0x00000001
+#define TI_RCB_FLAG_IP_CKSUM 0x00000002
+#define TI_RCB_FLAG_NO_PHDR_CKSUM 0x00000008
+#define TI_RCB_FLAG_VLAN_ASSIST 0x00000010
+#define TI_RCB_FLAG_COAL_UPD_ONLY 0x00000020
+#define TI_RCB_FLAG_HOST_RING 0x00000040
+#define TI_RCB_FLAG_IEEE_SNAP_CKSUM 0x00000080
+#define TI_RCB_FLAG_USE_EXT_RX_BD 0x00000100
+#define TI_RCB_FLAG_RING_DISABLED 0x00000200
+
+struct ti_producer {
+ u_int32_t ti_idx;
+ u_int32_t ti_unused;
+};
+
+/*
+ * Tigon general information block. This resides in host memory
+ * and contains the status counters, ring control blocks and
+ * producer pointers.
+ */
+
+struct ti_gib {
+ struct ti_stats ti_stats;
+ struct ti_rcb ti_ev_rcb;
+ struct ti_rcb ti_cmd_rcb;
+ struct ti_rcb ti_tx_rcb;
+ struct ti_rcb ti_std_rx_rcb;
+ struct ti_rcb ti_jumbo_rx_rcb;
+ struct ti_rcb ti_mini_rx_rcb;
+ struct ti_rcb ti_return_rcb;
+ ti_hostaddr ti_ev_prodidx_ptr;
+ ti_hostaddr ti_return_prodidx_ptr;
+ ti_hostaddr ti_tx_considx_ptr;
+ ti_hostaddr ti_refresh_stats_ptr;
+};
+
+/*
+ * Buffer descriptor structures. There are basically three types
+ * of structures: normal receive descriptors, extended receive
+ * descriptors and transmit descriptors. The extended receive
+ * descriptors are optionally used only for the jumbo receive ring.
+ */
+
+struct ti_rx_desc {
+ ti_hostaddr ti_addr;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_idx;
+ u_int16_t ti_len;
+#else
+ u_int16_t ti_len;
+ u_int16_t ti_idx;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_type;
+ u_int16_t ti_flags;
+#else
+ u_int16_t ti_flags;
+ u_int16_t ti_type;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_ip_cksum;
+ u_int16_t ti_tcp_udp_cksum;
+#else
+ u_int16_t ti_tcp_udp_cksum;
+ u_int16_t ti_ip_cksum;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_error_flags;
+ u_int16_t ti_vlan_tag;
+#else
+ u_int16_t ti_vlan_tag;
+ u_int16_t ti_error_flags;
+#endif
+ u_int32_t ti_rsvd;
+ u_int32_t ti_opaque;
+};
+
+struct ti_rx_desc_ext {
+ ti_hostaddr ti_addr1;
+ ti_hostaddr ti_addr2;
+ ti_hostaddr ti_addr3;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_len1;
+ u_int16_t ti_len2;
+#else
+ u_int16_t ti_len2;
+ u_int16_t ti_len1;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_len3;
+ u_int16_t ti_rsvd0;
+#else
+ u_int16_t ti_rsvd0;
+ u_int16_t ti_len3;
+#endif
+ ti_hostaddr ti_addr0;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_idx;
+ u_int16_t ti_len0;
+#else
+ u_int16_t ti_len0;
+ u_int16_t ti_idx;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_type;
+ u_int16_t ti_flags;
+#else
+ u_int16_t ti_flags;
+ u_int16_t ti_type;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_ip_cksum;
+ u_int16_t ti_tcp_udp_cksum;
+#else
+ u_int16_t ti_tcp_udp_cksum;
+ u_int16_t ti_ip_cksum;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_error_flags;
+ u_int16_t ti_vlan_tag;
+#else
+ u_int16_t ti_vlan_tag;
+ u_int16_t ti_error_flags;
+#endif
+ u_int32_t ti_rsvd1;
+ u_int32_t ti_opaque;
+};
+
+/*
+ * Transmit descriptors are, mercifully, very small.
+ */
+struct ti_tx_desc {
+ ti_hostaddr ti_addr;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_len;
+ u_int16_t ti_flags;
+#else
+ u_int16_t ti_flags;
+ u_int16_t ti_len;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t ti_rsvd;
+ u_int16_t ti_vlan_tag;
+#else
+ u_int16_t ti_vlan_tag;
+ u_int16_t ti_rsvd;
+#endif
+};
+
+/*
+ * NOTE! On the Alpha, we have an alignment constraint.
+ * The first thing in the packet is a 14-byte Ethernet header.
+ * This means that the packet is misaligned. To compensate,
+ * we actually offset the data 2 bytes into the cluster. This
+ * alignes the packet after the Ethernet header at a 32-bit
+ * boundary.
+ */
+
+#define ETHER_ALIGN 2
+
+#define TI_FRAMELEN 1518
+#define TI_JUMBO_FRAMELEN 9018
+#define TI_JUMBO_MTU (TI_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define TI_PAGE_SIZE PAGE_SIZE
+#define TI_MIN_FRAMELEN 60
+
+/*
+ * Buffer descriptor error flags.
+ */
+#define TI_BDERR_CRC 0x0001
+#define TI_BDERR_COLLDETECT 0x0002
+#define TI_BDERR_LINKLOST 0x0004
+#define TI_BDERR_DECODE 0x0008
+#define TI_BDERR_ODD_NIBBLES 0x0010
+#define TI_BDERR_MAC_ABRT 0x0020
+#define TI_BDERR_RUNT 0x0040
+#define TI_BDERR_TRUNC 0x0080
+#define TI_BDERR_GIANT 0x0100
+
+/*
+ * Buffer descriptor flags.
+ */
+#define TI_BDFLAG_TCP_UDP_CKSUM 0x0001
+#define TI_BDFLAG_IP_CKSUM 0x0002
+#define TI_BDFLAG_END 0x0004
+#define TI_BDFLAG_MORE 0x0008
+#define TI_BDFLAG_JUMBO_RING 0x0010
+#define TI_BDFLAG_UCAST_PKT 0x0020
+#define TI_BDFLAG_MCAST_PKT 0x0040
+#define TI_BDFLAG_BCAST_PKT 0x0060
+#define TI_BDFLAG_IP_FRAG 0x0080
+#define TI_BDFLAG_IP_FRAG_END 0x0100
+#define TI_BDFLAG_VLAN_TAG 0x0200
+#define TI_BDFLAG_ERROR 0x0400
+#define TI_BDFLAG_COAL_NOW 0x0800
+#define TI_BDFLAG_MINI_RING 0x1000
+
+/*
+ * Descriptor type flags. I think these only have meaning for
+ * the Tigon 1. I had to extract them from the sample driver source
+ * since they aren't in the manual.
+ */
+#define TI_BDTYPE_TYPE_NULL 0x0000
+#define TI_BDTYPE_SEND_BD 0x0001
+#define TI_BDTYPE_RECV_BD 0x0002
+#define TI_BDTYPE_RECV_JUMBO_BD 0x0003
+#define TI_BDTYPE_RECV_BD_LAST 0x0004
+#define TI_BDTYPE_SEND_DATA 0x0005
+#define TI_BDTYPE_SEND_DATA_LAST 0x0006
+#define TI_BDTYPE_RECV_DATA 0x0007
+#define TI_BDTYPE_RECV_DATA_LAST 0x000b
+#define TI_BDTYPE_EVENT_RUPT 0x000c
+#define TI_BDTYPE_EVENT_NO_RUPT 0x000d
+#define TI_BDTYPE_ODD_START 0x000e
+#define TI_BDTYPE_UPDATE_STATS 0x000f
+#define TI_BDTYPE_SEND_DUMMY_DMA 0x0010
+#define TI_BDTYPE_EVENT_PROD 0x0011
+#define TI_BDTYPE_TX_CONS 0x0012
+#define TI_BDTYPE_RX_PROD 0x0013
+#define TI_BDTYPE_REFRESH_STATS 0x0014
+#define TI_BDTYPE_SEND_DATA_LAST_VLAN 0x0015
+#define TI_BDTYPE_SEND_DATA_COAL 0x0016
+#define TI_BDTYPE_SEND_DATA_LAST_COAL 0x0017
+#define TI_BDTYPE_SEND_DATA_LAST_VLAN_COAL 0x0018
+#define TI_BDTYPE_TX_CONS_NO_INTR 0x0019
+
+/*
+ * Tigon command structure.
+ */
+struct ti_cmd_desc {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t ti_cmd:8;
+ u_int32_t ti_code:12;
+ u_int32_t ti_idx:12;
+#else
+ u_int32_t ti_idx:12;
+ u_int32_t ti_code:12;
+ u_int32_t ti_cmd:8;
+#endif
+};
+
+#define TI_CMD_HOST_STATE 0x01
+#define TI_CMD_CODE_STACK_UP 0x01
+#define TI_CMD_CODE_STACK_DOWN 0x02
+
+/*
+ * This command enables software address filtering. It's a workaround
+ * for a bug in the Tigon 1 and not implemented for the Tigon 2.
+ */
+#define TI_CMD_FDR_FILTERING 0x02
+#define TI_CMD_CODE_FILT_ENB 0x01
+#define TI_CMD_CODE_FILT_DIS 0x02
+
+#define TI_CMD_SET_RX_PROD_IDX 0x03 /* obsolete */
+#define TI_CMD_UPDATE_GENCOM 0x04
+#define TI_CMD_RESET_JUMBO_RING 0x05
+#define TI_CMD_SET_PARTIAL_RX_CNT 0x06
+#define TI_CMD_ADD_MCAST_ADDR 0x08 /* obsolete */
+#define TI_CMD_DEL_MCAST_ADDR 0x09 /* obsolete */
+
+#define TI_CMD_SET_PROMISC_MODE 0x0A
+#define TI_CMD_CODE_PROMISC_ENB 0x01
+#define TI_CMD_CODE_PROMISC_DIS 0x02
+
+#define TI_CMD_LINK_NEGOTIATION 0x0B
+#define TI_CMD_CODE_NEGOTIATE_BOTH 0x00
+#define TI_CMD_CODE_NEGOTIATE_GIGABIT 0x01
+#define TI_CMD_CODE_NEGOTIATE_10_100 0x02
+
+#define TI_CMD_SET_MAC_ADDR 0x0C
+#define TI_CMD_CLR_PROFILE 0x0D
+
+#define TI_CMD_SET_ALLMULTI 0x0E
+#define TI_CMD_CODE_ALLMULTI_ENB 0x01
+#define TI_CMD_CODE_ALLMULTI_DIS 0x02
+
+#define TI_CMD_CLR_STATS 0x0F
+#define TI_CMD_SET_RX_JUMBO_PROD_IDX 0x10 /* obsolete */
+#define TI_CMD_RFRSH_STATS 0x11
+
+#define TI_CMD_EXT_ADD_MCAST 0x12
+#define TI_CMD_EXT_DEL_MCAST 0x13
+
+/*
+ * Utility macros to make issuing commands a little simpler. Assumes
+ * that 'sc' and 'cmd' are in local scope.
+ */
+#define TI_DO_CMD(x, y, z) \
+ cmd.ti_cmd = x; \
+ cmd.ti_code = y; \
+ cmd.ti_idx = z; \
+ ti_cmd(sc, &cmd);
+
+#define TI_DO_CMD_EXT(x, y, z, v, w) \
+ cmd.ti_cmd = x; \
+ cmd.ti_code = y; \
+ cmd.ti_idx = z; \
+ ti_cmd_ext(sc, &cmd, v, w);
+
+/*
+ * Other utility macros.
+ */
+#define TI_INC(x, y) (x) = (x + 1) % y
+
+#define TI_UPDATE_JUMBOPROD(x, y) \
+ if (x->ti_hwrev == TI_HWREV_TIGON) { \
+ TI_DO_CMD(TI_CMD_SET_RX_JUMBO_PROD_IDX, 0, y); \
+ } else { \
+ CSR_WRITE_4(x, TI_MB_JUMBORXPROD_IDX, y); \
+ }
+
+#define TI_UPDATE_MINIPROD(x, y) \
+ CSR_WRITE_4(x, TI_MB_MINIRXPROD_IDX, y);
+
+#define TI_UPDATE_STDPROD(x, y) \
+ if (x->ti_hwrev == TI_HWREV_TIGON) { \
+ TI_DO_CMD(TI_CMD_SET_RX_PROD_IDX, 0, y); \
+ } else { \
+ CSR_WRITE_4(x, TI_MB_STDRXPROD_IDX, y); \
+ }
+
+
+/*
+ * Tigon event structure.
+ */
+struct ti_event_desc {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t ti_event:8;
+ u_int32_t ti_code:12;
+ u_int32_t ti_idx:12;
+#else
+ u_int32_t ti_idx:12;
+ u_int32_t ti_code:12;
+ u_int32_t ti_event:8;
+#endif
+ u_int32_t ti_rsvd;
+};
+
+/*
+ * Tigon events.
+ */
+#define TI_EV_FIRMWARE_UP 0x01
+#define TI_EV_STATS_UPDATED 0x04
+
+#define TI_EV_LINKSTAT_CHANGED 0x06
+#define TI_EV_CODE_GIG_LINK_UP 0x01
+#define TI_EV_CODE_LINK_DOWN 0x02
+#define TI_EV_CODE_LINK_UP 0x03
+
+#define TI_EV_ERROR 0x07
+#define TI_EV_CODE_ERR_INVAL_CMD 0x01
+#define TI_EV_CODE_ERR_UNIMP_CMD 0x02
+#define TI_EV_CODE_ERR_BADCFG 0x03
+
+#define TI_EV_MCAST_UPDATED 0x08
+#define TI_EV_CODE_MCAST_ADD 0x01
+#define TI_EV_CODE_MCAST_DEL 0x02
+
+#define TI_EV_RESET_JUMBO_RING 0x09
+/*
+ * Register access macros. The Tigon always uses memory mapped register
+ * accesses and all registers must be accessed with 32 bit operations.
+ */
+
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->ti_btag, sc->ti_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->ti_btag, sc->ti_bhandle, reg)
+
+#define TI_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, (CSR_READ_4(sc, reg) | x))
+#define TI_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, (CSR_READ_4(sc, reg) & ~x))
+
+/*
+ * Memory management stuff. Note: the SSLOTS, MSLOTS and JSLOTS
+ * values are tuneable. They control the actual amount of buffers
+ * allocated for the standard, mini and jumbo receive rings.
+ */
+
+#define TI_SSLOTS 256
+#define TI_MSLOTS 256
+#define TI_JSLOTS 384
+
+#define TI_JRAWLEN (TI_JUMBO_FRAMELEN + ETHER_ALIGN)
+#define TI_JLEN (TI_JRAWLEN + (sizeof(u_int64_t) - \
+ (TI_JRAWLEN % sizeof(u_int64_t))))
+#define TI_JPAGESZ PAGE_SIZE
+#define TI_RESID (TI_JPAGESZ - (TI_JLEN * TI_JSLOTS) % TI_JPAGESZ)
+#define TI_JMEM ((TI_JLEN * TI_JSLOTS) + TI_RESID)
+
+/*
+ * Ring structures. Most of these reside in host memory and we tell
+ * the NIC where they are via the ring control blocks. The exceptions
+ * are the tx and command rings, which live in NIC memory and which
+ * we access via the shared memory window.
+ */
+struct ti_ring_data {
+ struct ti_rx_desc ti_rx_std_ring[TI_STD_RX_RING_CNT];
+#ifdef PRIVATE_JUMBOS
+ struct ti_rx_desc ti_rx_jumbo_ring[TI_JUMBO_RX_RING_CNT];
+#else
+ struct ti_rx_desc_ext ti_rx_jumbo_ring[TI_JUMBO_RX_RING_CNT];
+#endif
+ struct ti_rx_desc ti_rx_mini_ring[TI_MINI_RX_RING_CNT];
+ struct ti_rx_desc ti_rx_return_ring[TI_RETURN_RING_CNT];
+ struct ti_event_desc ti_event_ring[TI_EVENT_RING_CNT];
+ struct ti_tx_desc ti_tx_ring[TI_TX_RING_CNT];
+ /*
+ * Make sure producer structures are aligned on 32-byte cache
+ * line boundaries.
+ */
+ struct ti_producer ti_ev_prodidx_r;
+ u_int32_t ti_pad0[6];
+ struct ti_producer ti_return_prodidx_r;
+ u_int32_t ti_pad1[6];
+ struct ti_producer ti_tx_considx_r;
+ u_int32_t ti_pad2[6];
+ struct ti_tx_desc *ti_tx_ring_nic;/* pointer to shared mem */
+ struct ti_cmd_desc *ti_cmd_ring; /* pointer to shared mem */
+ struct ti_gib ti_info;
+};
+
+/*
+ * Mbuf pointers. We need these to keep track of the virtual addresses
+ * of our mbuf chains since we can only convert from physical to virtual,
+ * not the other way around.
+ */
+struct ti_chain_data {
+ struct mbuf *ti_tx_chain[TI_TX_RING_CNT];
+ struct mbuf *ti_rx_std_chain[TI_STD_RX_RING_CNT];
+ struct mbuf *ti_rx_jumbo_chain[TI_JUMBO_RX_RING_CNT];
+ struct mbuf *ti_rx_mini_chain[TI_MINI_RX_RING_CNT];
+ /* Stick the jumbo mem management stuff here too. */
+ caddr_t ti_jslots[TI_JSLOTS];
+ void *ti_jumbo_buf;
+};
+
+struct ti_type {
+ u_int16_t ti_vid;
+ u_int16_t ti_did;
+ char *ti_name;
+};
+
+#define TI_HWREV_TIGON 0x01
+#define TI_HWREV_TIGON_II 0x02
+#define TI_TIMEOUT 1000
+#define TI_TXCONS_UNSET 0xFFFF /* impossible value */
+
+struct ti_mc_entry {
+ struct ether_addr mc_addr;
+ SLIST_ENTRY(ti_mc_entry) mc_entries;
+};
+
+struct ti_jpool_entry {
+ int slot;
+ SLIST_ENTRY(ti_jpool_entry) jpool_entries;
+};
+
+typedef enum {
+ TI_FLAG_NONE = 0x00,
+ TI_FLAG_DEBUGING = 0x01,
+ TI_FLAG_WAIT_FOR_LINK = 0x02
+} ti_flag_vals;
+
+struct ti_softc {
+ STAILQ_ENTRY(ti_softc) ti_links;
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t ti_bhandle;
+ vm_offset_t ti_vhandle;
+ bus_space_tag_t ti_btag;
+ void *ti_intrhand;
+ struct resource *ti_irq;
+ struct resource *ti_res;
+ struct ifmedia ifmedia; /* media info */
+ u_int8_t ti_unit; /* interface number */
+ u_int8_t ti_hwrev; /* Tigon rev (1 or 2) */
+ u_int8_t ti_copper; /* 1000baseTX card */
+ u_int8_t ti_linkstat; /* Link state */
+ int ti_hdrsplit; /* enable header splitting */
+ struct ti_ring_data *ti_rdata; /* rings */
+ struct ti_chain_data ti_cdata; /* mbufs */
+#define ti_ev_prodidx ti_rdata->ti_ev_prodidx_r
+#define ti_return_prodidx ti_rdata->ti_return_prodidx_r
+#define ti_tx_considx ti_rdata->ti_tx_considx_r
+ u_int16_t ti_tx_saved_considx;
+ u_int16_t ti_rx_saved_considx;
+ u_int16_t ti_ev_saved_considx;
+ u_int16_t ti_cmd_saved_prodidx;
+ u_int16_t ti_std; /* current std ring head */
+ u_int16_t ti_mini; /* current mini ring head */
+ u_int16_t ti_jumbo; /* current jumo ring head */
+ SLIST_HEAD(__ti_mchead, ti_mc_entry) ti_mc_listhead;
+ SLIST_HEAD(__ti_jfreehead, ti_jpool_entry) ti_jfree_listhead;
+ SLIST_HEAD(__ti_jinusehead, ti_jpool_entry) ti_jinuse_listhead;
+ u_int32_t ti_stat_ticks;
+ u_int32_t ti_rx_coal_ticks;
+ u_int32_t ti_tx_coal_ticks;
+ u_int32_t ti_rx_max_coal_bds;
+ u_int32_t ti_tx_max_coal_bds;
+ u_int32_t ti_tx_buf_ratio;
+ int ti_if_flags;
+ int ti_txcnt;
+ struct mtx ti_mtx;
+ ti_flag_vals ti_flags;
+ dev_t dev;
+};
+
+#define TI_LOCK(_sc) mtx_lock(&(_sc)->ti_mtx)
+#define TI_UNLOCK(_sc) mtx_unlock(&(_sc)->ti_mtx)
+
+/*
+ * Microchip Technology 24Cxx EEPROM control bytes
+ */
+#define EEPROM_CTL_READ 0xA1 /* 0101 0001 */
+#define EEPROM_CTL_WRITE 0xA0 /* 0101 0000 */
+
+/*
+ * Note that EEPROM_START leaves transmission enabled.
+ */
+#define EEPROM_START \
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); /* Pull clock pin high */\
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); /* Set DATA bit to 1 */ \
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* Enable xmit to write bit */\
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); /* Pull DATA bit to 0 again */\
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); /* Pull clock low again */
+
+/*
+ * EEPROM_STOP ends access to the EEPROM and clears the ETXEN bit so
+ * that no further data can be written to the EEPROM I/O pin.
+ */
+#define EEPROM_STOP \
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* Disable xmit */ \
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); /* Pull DATA to 0 */ \
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); /* Pull clock high */ \
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* Enable xmit */ \
+ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); /* Toggle DATA to 1 */ \
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* Disable xmit. */ \
+ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); /* Pull clock low again */
+
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_tl.c b/sys/pci/if_tl.c
new file mode 100644
index 0000000..1c52f9a
--- /dev/null
+++ b/sys/pci/if_tl.c
@@ -0,0 +1,2335 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Texas Instruments ThunderLAN driver for FreeBSD 2.2.6 and 3.x.
+ * Supports many Compaq PCI NICs based on the ThunderLAN ethernet controller,
+ * the National Semiconductor DP83840A physical interface and the
+ * Microchip Technology 24Cxx series serial EEPROM.
+ *
+ * Written using the following four documents:
+ *
+ * Texas Instruments ThunderLAN Programmer's Guide (www.ti.com)
+ * National Semiconductor DP83840A data sheet (www.national.com)
+ * Microchip Technology 24C02C data sheet (www.microchip.com)
+ * Micro Linear ML6692 100BaseTX only PHY data sheet (www.microlinear.com)
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * Some notes about the ThunderLAN:
+ *
+ * The ThunderLAN controller is a single chip containing PCI controller
+ * logic, approximately 3K of on-board SRAM, a LAN controller, and media
+ * independent interface (MII) bus. The MII allows the ThunderLAN chip to
+ * control up to 32 different physical interfaces (PHYs). The ThunderLAN
+ * also has a built-in 10baseT PHY, allowing a single ThunderLAN controller
+ * to act as a complete ethernet interface.
+ *
+ * Other PHYs may be attached to the ThunderLAN; the Compaq 10/100 cards
+ * use a National Semiconductor DP83840A PHY that supports 10 or 100Mb/sec
+ * in full or half duplex. Some of the Compaq Deskpro machines use a
+ * Level 1 LXT970 PHY with the same capabilities. Certain Olicom adapters
+ * use a Micro Linear ML6692 100BaseTX only PHY, which can be used in
+ * concert with the ThunderLAN's internal PHY to provide full 10/100
+ * support. This is cheaper than using a standalone external PHY for both
+ * 10/100 modes and letting the ThunderLAN's internal PHY go to waste.
+ * A serial EEPROM is also attached to the ThunderLAN chip to provide
+ * power-up default register settings and for storing the adapter's
+ * station address. Although not supported by this driver, the ThunderLAN
+ * chip can also be connected to token ring PHYs.
+ *
+ * The ThunderLAN has a set of registers which can be used to issue
+ * commands, acknowledge interrupts, and to manipulate other internal
+ * registers on its DIO bus. The primary registers can be accessed
+ * using either programmed I/O (inb/outb) or via PCI memory mapping,
+ * depending on how the card is configured during the PCI probing
+ * phase. It is even possible to have both PIO and memory mapped
+ * access turned on at the same time.
+ *
+ * Frame reception and transmission with the ThunderLAN chip is done
+ * using frame 'lists.' A list structure looks more or less like this:
+ *
+ * struct tl_frag {
+ * u_int32_t fragment_address;
+ * u_int32_t fragment_size;
+ * };
+ * struct tl_list {
+ * u_int32_t forward_pointer;
+ * u_int16_t cstat;
+ * u_int16_t frame_size;
+ * struct tl_frag fragments[10];
+ * };
+ *
+ * The forward pointer in the list header can be either a 0 or the address
+ * of another list, which allows several lists to be linked together. Each
+ * list contains up to 10 fragment descriptors. This means the chip allows
+ * ethernet frames to be broken up into up to 10 chunks for transfer to
+ * and from the SRAM. Note that the forward pointer and fragment buffer
+ * addresses are physical memory addresses, not virtual. Note also that
+ * a single ethernet frame can not span lists: if the host wants to
+ * transmit a frame and the frame data is split up over more than 10
+ * buffers, the frame has to collapsed before it can be transmitted.
+ *
+ * To receive frames, the driver sets up a number of lists and populates
+ * the fragment descriptors, then it sends an RX GO command to the chip.
+ * When a frame is received, the chip will DMA it into the memory regions
+ * specified by the fragment descriptors and then trigger an RX 'end of
+ * frame interrupt' when done. The driver may choose to use only one
+ * fragment per list; this may result is slighltly less efficient use
+ * of memory in exchange for improving performance.
+ *
+ * To transmit frames, the driver again sets up lists and fragment
+ * descriptors, only this time the buffers contain frame data that
+ * is to be DMA'ed into the chip instead of out of it. Once the chip
+ * has transfered the data into its on-board SRAM, it will trigger a
+ * TX 'end of frame' interrupt. It will also generate an 'end of channel'
+ * interrupt when it reaches the end of the list.
+ */
+
+/*
+ * Some notes about this driver:
+ *
+ * The ThunderLAN chip provides a couple of different ways to organize
+ * reception, transmission and interrupt handling. The simplest approach
+ * is to use one list each for transmission and reception. In this mode,
+ * the ThunderLAN will generate two interrupts for every received frame
+ * (one RX EOF and one RX EOC) and two for each transmitted frame (one
+ * TX EOF and one TX EOC). This may make the driver simpler but it hurts
+ * performance to have to handle so many interrupts.
+ *
+ * Initially I wanted to create a circular list of receive buffers so
+ * that the ThunderLAN chip would think there was an infinitely long
+ * receive channel and never deliver an RXEOC interrupt. However this
+ * doesn't work correctly under heavy load: while the manual says the
+ * chip will trigger an RXEOF interrupt each time a frame is copied into
+ * memory, you can't count on the chip waiting around for you to acknowledge
+ * the interrupt before it starts trying to DMA the next frame. The result
+ * is that the chip might traverse the entire circular list and then wrap
+ * around before you have a chance to do anything about it. Consequently,
+ * the receive list is terminated (with a 0 in the forward pointer in the
+ * last element). Each time an RXEOF interrupt arrives, the used list
+ * is shifted to the end of the list. This gives the appearance of an
+ * infinitely large RX chain so long as the driver doesn't fall behind
+ * the chip and allow all of the lists to be filled up.
+ *
+ * If all the lists are filled, the adapter will deliver an RX 'end of
+ * channel' interrupt when it hits the 0 forward pointer at the end of
+ * the chain. The RXEOC handler then cleans out the RX chain and resets
+ * the list head pointer in the ch_parm register and restarts the receiver.
+ *
+ * For frame transmission, it is possible to program the ThunderLAN's
+ * transmit interrupt threshold so that the chip can acknowledge multiple
+ * lists with only a single TX EOF interrupt. This allows the driver to
+ * queue several frames in one shot, and only have to handle a total
+ * two interrupts (one TX EOF and one TX EOC) no matter how many frames
+ * are transmitted. Frame transmission is done directly out of the
+ * mbufs passed to the tl_start() routine via the interface send queue.
+ * The driver simply sets up the fragment descriptors in the transmit
+ * lists to point to the mbuf data regions and sends a TX GO command.
+ *
+ * Note that since the RX and TX lists themselves are always used
+ * only by the driver, the are malloc()ed once at driver initialization
+ * time and never free()ed.
+ *
+ * Also, in order to remain as platform independent as possible, this
+ * driver uses memory mapped register access to manipulate the card
+ * as opposed to programmed I/O. This avoids the use of the inb/outb
+ * (and related) instructions which are specific to the i386 platform.
+ *
+ * Using these techniques, this driver achieves very high performance
+ * by minimizing the amount of interrupts generated during large
+ * transfers and by completely avoiding buffer copies. Frame transfer
+ * to and from the ThunderLAN chip is performed entirely by the chip
+ * itself thereby reducing the load on the host CPU.
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_memio.h>
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+/*
+ * Default to using PIO register access mode to pacify certain
+ * laptop docking stations with built-in ThunderLAN chips that
+ * don't seem to handle memory mapped mode properly.
+ */
+#define TL_USEIOSPACE
+
+#include <pci/if_tlreg.h>
+
+MODULE_DEPEND(tl, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+
+static struct tl_type tl_devs[] = {
+ { TI_VENDORID, TI_DEVICEID_THUNDERLAN,
+ "Texas Instruments ThunderLAN" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10,
+ "Compaq Netelligent 10" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100,
+ "Compaq Netelligent 10/100" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_PROLIANT,
+ "Compaq Netelligent 10/100 Proliant" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_DUAL,
+ "Compaq Netelligent 10/100 Dual Port" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_INTEGRATED,
+ "Compaq NetFlex-3/P Integrated" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P,
+ "Compaq NetFlex-3/P" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_BNC,
+ "Compaq NetFlex 3/P w/ BNC" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_EMBEDDED,
+ "Compaq Netelligent 10/100 TX Embedded UTP" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_T2_UTP_COAX,
+ "Compaq Netelligent 10 T/2 PCI UTP/Coax" },
+ { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_TX_UTP,
+ "Compaq Netelligent 10/100 TX UTP" },
+ { OLICOM_VENDORID, OLICOM_DEVICEID_OC2183,
+ "Olicom OC-2183/2185" },
+ { OLICOM_VENDORID, OLICOM_DEVICEID_OC2325,
+ "Olicom OC-2325" },
+ { OLICOM_VENDORID, OLICOM_DEVICEID_OC2326,
+ "Olicom OC-2326 10/100 TX UTP" },
+ { 0, 0, NULL }
+};
+
+static int tl_probe (device_t);
+static int tl_attach (device_t);
+static int tl_detach (device_t);
+static int tl_intvec_rxeoc (void *, u_int32_t);
+static int tl_intvec_txeoc (void *, u_int32_t);
+static int tl_intvec_txeof (void *, u_int32_t);
+static int tl_intvec_rxeof (void *, u_int32_t);
+static int tl_intvec_adchk (void *, u_int32_t);
+static int tl_intvec_netsts (void *, u_int32_t);
+
+static int tl_newbuf (struct tl_softc *, struct tl_chain_onefrag *);
+static void tl_stats_update (void *);
+static int tl_encap (struct tl_softc *, struct tl_chain *,
+ struct mbuf *);
+
+static void tl_intr (void *);
+static void tl_start (struct ifnet *);
+static int tl_ioctl (struct ifnet *, u_long, caddr_t);
+static void tl_init (void *);
+static void tl_stop (struct tl_softc *);
+static void tl_watchdog (struct ifnet *);
+static void tl_shutdown (device_t);
+static int tl_ifmedia_upd (struct ifnet *);
+static void tl_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static u_int8_t tl_eeprom_putbyte (struct tl_softc *, int);
+static u_int8_t tl_eeprom_getbyte (struct tl_softc *, int, u_int8_t *);
+static int tl_read_eeprom (struct tl_softc *, caddr_t, int, int);
+
+static void tl_mii_sync (struct tl_softc *);
+static void tl_mii_send (struct tl_softc *, u_int32_t, int);
+static int tl_mii_readreg (struct tl_softc *, struct tl_mii_frame *);
+static int tl_mii_writereg (struct tl_softc *, struct tl_mii_frame *);
+static int tl_miibus_readreg (device_t, int, int);
+static int tl_miibus_writereg (device_t, int, int, int);
+static void tl_miibus_statchg (device_t);
+
+static void tl_setmode (struct tl_softc *, int);
+static int tl_calchash (caddr_t);
+static void tl_setmulti (struct tl_softc *);
+static void tl_setfilt (struct tl_softc *, caddr_t, int);
+static void tl_softreset (struct tl_softc *, int);
+static void tl_hardreset (device_t);
+static int tl_list_rx_init (struct tl_softc *);
+static int tl_list_tx_init (struct tl_softc *);
+
+static u_int8_t tl_dio_read8 (struct tl_softc *, int);
+static u_int16_t tl_dio_read16 (struct tl_softc *, int);
+static u_int32_t tl_dio_read32 (struct tl_softc *, int);
+static void tl_dio_write8 (struct tl_softc *, int, int);
+static void tl_dio_write16 (struct tl_softc *, int, int);
+static void tl_dio_write32 (struct tl_softc *, int, int);
+static void tl_dio_setbit (struct tl_softc *, int, int);
+static void tl_dio_clrbit (struct tl_softc *, int, int);
+static void tl_dio_setbit16 (struct tl_softc *, int, int);
+static void tl_dio_clrbit16 (struct tl_softc *, int, int);
+
+#ifdef TL_USEIOSPACE
+#define TL_RES SYS_RES_IOPORT
+#define TL_RID TL_PCI_LOIO
+#else
+#define TL_RES SYS_RES_MEMORY
+#define TL_RID TL_PCI_LOMEM
+#endif
+
+static device_method_t tl_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tl_probe),
+ DEVMETHOD(device_attach, tl_attach),
+ DEVMETHOD(device_detach, tl_detach),
+ DEVMETHOD(device_shutdown, tl_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, tl_miibus_readreg),
+ DEVMETHOD(miibus_writereg, tl_miibus_writereg),
+ DEVMETHOD(miibus_statchg, tl_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t tl_driver = {
+ "tl",
+ tl_methods,
+ sizeof(struct tl_softc)
+};
+
+static devclass_t tl_devclass;
+
+DRIVER_MODULE(if_tl, pci, tl_driver, tl_devclass, 0, 0);
+DRIVER_MODULE(miibus, tl, miibus_driver, miibus_devclass, 0, 0);
+
+static u_int8_t tl_dio_read8(sc, reg)
+ struct tl_softc *sc;
+ int reg;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ return(CSR_READ_1(sc, TL_DIO_DATA + (reg & 3)));
+}
+
+static u_int16_t tl_dio_read16(sc, reg)
+ struct tl_softc *sc;
+ int reg;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ return(CSR_READ_2(sc, TL_DIO_DATA + (reg & 3)));
+}
+
+static u_int32_t tl_dio_read32(sc, reg)
+ struct tl_softc *sc;
+ int reg;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ return(CSR_READ_4(sc, TL_DIO_DATA + (reg & 3)));
+}
+
+static void tl_dio_write8(sc, reg, val)
+ struct tl_softc *sc;
+ int reg;
+ int val;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), val);
+ return;
+}
+
+static void tl_dio_write16(sc, reg, val)
+ struct tl_softc *sc;
+ int reg;
+ int val;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), val);
+ return;
+}
+
+static void tl_dio_write32(sc, reg, val)
+ struct tl_softc *sc;
+ int reg;
+ int val;
+{
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ CSR_WRITE_4(sc, TL_DIO_DATA + (reg & 3), val);
+ return;
+}
+
+static void tl_dio_setbit(sc, reg, bit)
+ struct tl_softc *sc;
+ int reg;
+ int bit;
+{
+ u_int8_t f;
+
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3));
+ f |= bit;
+ CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f);
+
+ return;
+}
+
+static void tl_dio_clrbit(sc, reg, bit)
+ struct tl_softc *sc;
+ int reg;
+ int bit;
+{
+ u_int8_t f;
+
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3));
+ f &= ~bit;
+ CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f);
+
+ return;
+}
+
+static void tl_dio_setbit16(sc, reg, bit)
+ struct tl_softc *sc;
+ int reg;
+ int bit;
+{
+ u_int16_t f;
+
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3));
+ f |= bit;
+ CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f);
+
+ return;
+}
+
+static void tl_dio_clrbit16(sc, reg, bit)
+ struct tl_softc *sc;
+ int reg;
+ int bit;
+{
+ u_int16_t f;
+
+ CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
+ f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3));
+ f &= ~bit;
+ CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f);
+
+ return;
+}
+
+/*
+ * Send an instruction or address to the EEPROM, check for ACK.
+ */
+static u_int8_t tl_eeprom_putbyte(sc, byte)
+ struct tl_softc *sc;
+ int byte;
+{
+ register int i, ack = 0;
+
+ /*
+ * Make sure we're in TX mode.
+ */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ETXEN);
+
+ /*
+ * Feed in each bit and stobe the clock.
+ */
+ for (i = 0x80; i; i >>= 1) {
+ if (byte & i) {
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_EDATA);
+ } else {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_EDATA);
+ }
+ DELAY(1);
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+ DELAY(1);
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+ }
+
+ /*
+ * Turn off TX mode.
+ */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN);
+
+ /*
+ * Check for ack.
+ */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+ ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA;
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+
+ return(ack);
+}
+
+/*
+ * Read a byte of data stored in the EEPROM at address 'addr.'
+ */
+static u_int8_t tl_eeprom_getbyte(sc, addr, dest)
+ struct tl_softc *sc;
+ int addr;
+ u_int8_t *dest;
+{
+ register int i;
+ u_int8_t byte = 0;
+
+ tl_dio_write8(sc, TL_NETSIO, 0);
+
+ EEPROM_START;
+
+ /*
+ * Send write control code to EEPROM.
+ */
+ if (tl_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) {
+ printf("tl%d: failed to send write command, status: %x\n",
+ sc->tl_unit, tl_dio_read8(sc, TL_NETSIO));
+ return(1);
+ }
+
+ /*
+ * Send address of byte we want to read.
+ */
+ if (tl_eeprom_putbyte(sc, addr)) {
+ printf("tl%d: failed to send address, status: %x\n",
+ sc->tl_unit, tl_dio_read8(sc, TL_NETSIO));
+ return(1);
+ }
+
+ EEPROM_STOP;
+ EEPROM_START;
+ /*
+ * Send read control code to EEPROM.
+ */
+ if (tl_eeprom_putbyte(sc, EEPROM_CTL_READ)) {
+ printf("tl%d: failed to send write command, status: %x\n",
+ sc->tl_unit, tl_dio_read8(sc, TL_NETSIO));
+ return(1);
+ }
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN);
+ for (i = 0x80; i; i >>= 1) {
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+ DELAY(1);
+ if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA)
+ byte |= i;
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
+ DELAY(1);
+ }
+
+ EEPROM_STOP;
+
+ /*
+ * No ACK generated for read, so just return byte.
+ */
+
+ *dest = byte;
+
+ return(0);
+}
+
+/*
+ * Read a sequence of bytes from the EEPROM.
+ */
+static int tl_read_eeprom(sc, dest, off, cnt)
+ struct tl_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+{
+ int err = 0, i;
+ u_int8_t byte = 0;
+
+ for (i = 0; i < cnt; i++) {
+ err = tl_eeprom_getbyte(sc, off + i, &byte);
+ if (err)
+ break;
+ *(dest + i) = byte;
+ }
+
+ return(err ? 1 : 0);
+}
+
+static void tl_mii_sync(sc)
+ struct tl_softc *sc;
+{
+ register int i;
+
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
+
+ for (i = 0; i < 32; i++) {
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ }
+
+ return;
+}
+
+static void tl_mii_send(sc, bits, cnt)
+ struct tl_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ if (bits & i) {
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MDATA);
+ } else {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MDATA);
+ }
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ }
+}
+
+static int tl_mii_readreg(sc, frame)
+ struct tl_softc *sc;
+ struct tl_mii_frame *frame;
+
+{
+ int i, ack;
+ int minten = 0;
+
+ TL_LOCK(sc);
+
+ tl_mii_sync(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = TL_MII_STARTDELIM;
+ frame->mii_opcode = TL_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Turn off MII interrupt by forcing MINTEN low.
+ */
+ minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN;
+ if (minten) {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN);
+ }
+
+ /*
+ * Turn on data xmit.
+ */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN);
+
+ /*
+ * Send command/address info.
+ */
+ tl_mii_send(sc, frame->mii_stdelim, 2);
+ tl_mii_send(sc, frame->mii_opcode, 2);
+ tl_mii_send(sc, frame->mii_phyaddr, 5);
+ tl_mii_send(sc, frame->mii_regaddr, 5);
+
+ /*
+ * Turn off xmit.
+ */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
+
+ /* Idle bit */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+
+ /* Check for ack */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA;
+
+ /* Complete the cycle */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHYs in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ if (!ack) {
+ if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA)
+ frame->mii_data |= i;
+ }
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ }
+
+fail:
+
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+
+ /* Reenable interrupts */
+ if (minten) {
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
+ }
+
+ TL_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+static int tl_mii_writereg(sc, frame)
+ struct tl_softc *sc;
+ struct tl_mii_frame *frame;
+
+{
+ int minten;
+
+ TL_LOCK(sc);
+
+ tl_mii_sync(sc);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = TL_MII_STARTDELIM;
+ frame->mii_opcode = TL_MII_WRITEOP;
+ frame->mii_turnaround = TL_MII_TURNAROUND;
+
+ /*
+ * Turn off MII interrupt by forcing MINTEN low.
+ */
+ minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN;
+ if (minten) {
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN);
+ }
+
+ /*
+ * Turn on data output.
+ */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN);
+
+ tl_mii_send(sc, frame->mii_stdelim, 2);
+ tl_mii_send(sc, frame->mii_opcode, 2);
+ tl_mii_send(sc, frame->mii_phyaddr, 5);
+ tl_mii_send(sc, frame->mii_regaddr, 5);
+ tl_mii_send(sc, frame->mii_turnaround, 2);
+ tl_mii_send(sc, frame->mii_data, 16);
+
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
+
+ /*
+ * Turn off xmit.
+ */
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
+
+ /* Reenable interrupts */
+ if (minten)
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
+
+ TL_UNLOCK(sc);
+
+ return(0);
+}
+
+static int tl_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct tl_softc *sc;
+ struct tl_mii_frame frame;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ tl_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int tl_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct tl_softc *sc;
+ struct tl_mii_frame frame;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ tl_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+static void tl_miibus_statchg(dev)
+ device_t dev;
+{
+ struct tl_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ TL_LOCK(sc);
+ mii = device_get_softc(sc->tl_miibus);
+
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
+ } else {
+ tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
+ }
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set modes for bitrate devices.
+ */
+static void tl_setmode(sc, media)
+ struct tl_softc *sc;
+ int media;
+{
+ if (IFM_SUBTYPE(media) == IFM_10_5)
+ tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD1);
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD1);
+ if ((media & IFM_GMASK) == IFM_FDX) {
+ tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD3);
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
+ } else {
+ tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD3);
+ tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
+ }
+ }
+
+ return;
+}
+
+/*
+ * Calculate the hash of a MAC address for programming the multicast hash
+ * table. This hash is simply the address split into 6-bit chunks
+ * XOR'd, e.g.
+ * byte: 000000|00 1111|1111 22|222222|333333|33 4444|4444 55|555555
+ * bit: 765432|10 7654|3210 76|543210|765432|10 7654|3210 76|543210
+ * Bytes 0-2 and 3-5 are symmetrical, so are folded together. Then
+ * the folded 24-bit value is split into 6-bit portions and XOR'd.
+ */
+static int tl_calchash(addr)
+ caddr_t addr;
+{
+ int t;
+
+ t = (addr[0] ^ addr[3]) << 16 | (addr[1] ^ addr[4]) << 8 |
+ (addr[2] ^ addr[5]);
+ return ((t >> 18) ^ (t >> 12) ^ (t >> 6) ^ t) & 0x3f;
+}
+
+/*
+ * The ThunderLAN has a perfect MAC address filter in addition to
+ * the multicast hash filter. The perfect filter can be programmed
+ * with up to four MAC addresses. The first one is always used to
+ * hold the station address, which leaves us free to use the other
+ * three for multicast addresses.
+ */
+static void tl_setfilt(sc, addr, slot)
+ struct tl_softc *sc;
+ caddr_t addr;
+ int slot;
+{
+ int i;
+ u_int16_t regaddr;
+
+ regaddr = TL_AREG0_B5 + (slot * ETHER_ADDR_LEN);
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ tl_dio_write8(sc, regaddr + i, *(addr + i));
+
+ return;
+}
+
+/*
+ * XXX In FreeBSD 3.0, multicast addresses are managed using a doubly
+ * linked list. This is fine, except addresses are added from the head
+ * end of the list. We want to arrange for 224.0.0.1 (the "all hosts")
+ * group to always be in the perfect filter, but as more groups are added,
+ * the 224.0.0.1 entry (which is always added first) gets pushed down
+ * the list and ends up at the tail. So after 3 or 4 multicast groups
+ * are added, the all-hosts entry gets pushed out of the perfect filter
+ * and into the hash table.
+ *
+ * Because the multicast list is a doubly-linked list as opposed to a
+ * circular queue, we don't have the ability to just grab the tail of
+ * the list and traverse it backwards. Instead, we have to traverse
+ * the list once to find the tail, then traverse it again backwards to
+ * update the multicast filter.
+ */
+static void tl_setmulti(sc)
+ struct tl_softc *sc;
+{
+ struct ifnet *ifp;
+ u_int32_t hashes[2] = { 0, 0 };
+ int h, i;
+ struct ifmultiaddr *ifma;
+ u_int8_t dummy[] = { 0, 0, 0, 0, 0 ,0 };
+ ifp = &sc->arpcom.ac_if;
+
+ /* First, zot all the existing filters. */
+ for (i = 1; i < 4; i++)
+ tl_setfilt(sc, (caddr_t)&dummy, i);
+ tl_dio_write32(sc, TL_HASH1, 0);
+ tl_dio_write32(sc, TL_HASH2, 0);
+
+ /* Now program new ones. */
+ if (ifp->if_flags & IFF_ALLMULTI) {
+ hashes[0] = 0xFFFFFFFF;
+ hashes[1] = 0xFFFFFFFF;
+ } else {
+ i = 1;
+ TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ /*
+ * Program the first three multicast groups
+ * into the perfect filter. For all others,
+ * use the hash table.
+ */
+ if (i < 4) {
+ tl_setfilt(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i);
+ i++;
+ continue;
+ }
+
+ h = tl_calchash(
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+ }
+
+ tl_dio_write32(sc, TL_HASH1, hashes[0]);
+ tl_dio_write32(sc, TL_HASH2, hashes[1]);
+
+ return;
+}
+
+/*
+ * This routine is recommended by the ThunderLAN manual to insure that
+ * the internal PHY is powered up correctly. It also recommends a one
+ * second pause at the end to 'wait for the clocks to start' but in my
+ * experience this isn't necessary.
+ */
+static void tl_hardreset(dev)
+ device_t dev;
+{
+ struct tl_softc *sc;
+ int i;
+ u_int16_t flags;
+
+ sc = device_get_softc(dev);
+
+ tl_mii_sync(sc);
+
+ flags = BMCR_LOOP|BMCR_ISO|BMCR_PDOWN;
+
+ for (i = 0; i < MII_NPHY; i++)
+ tl_miibus_writereg(dev, i, MII_BMCR, flags);
+
+ tl_miibus_writereg(dev, 31, MII_BMCR, BMCR_ISO);
+ DELAY(50000);
+ tl_miibus_writereg(dev, 31, MII_BMCR, BMCR_LOOP|BMCR_ISO);
+ tl_mii_sync(sc);
+ while(tl_miibus_readreg(dev, 31, MII_BMCR) & BMCR_RESET);
+
+ DELAY(50000);
+ return;
+}
+
+static void tl_softreset(sc, internal)
+ struct tl_softc *sc;
+ int internal;
+{
+ u_int32_t cmd, dummy, i;
+
+ /* Assert the adapter reset bit. */
+ CMD_SET(sc, TL_CMD_ADRST);
+
+ /* Turn off interrupts */
+ CMD_SET(sc, TL_CMD_INTSOFF);
+
+ /* First, clear the stats registers. */
+ for (i = 0; i < 5; i++)
+ dummy = tl_dio_read32(sc, TL_TXGOODFRAMES);
+
+ /* Clear Areg and Hash registers */
+ for (i = 0; i < 8; i++)
+ tl_dio_write32(sc, TL_AREG0_B5, 0x00000000);
+
+ /*
+ * Set up Netconfig register. Enable one channel and
+ * one fragment mode.
+ */
+ tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_ONECHAN|TL_CFG_ONEFRAG);
+ if (internal && !sc->tl_bitrate) {
+ tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN);
+ } else {
+ tl_dio_clrbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN);
+ }
+
+ /* Handle cards with bitrate devices. */
+ if (sc->tl_bitrate)
+ tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_BITRATE);
+
+ /*
+ * Load adapter irq pacing timer and tx threshold.
+ * We make the transmit threshold 1 initially but we may
+ * change that later.
+ */
+ cmd = CSR_READ_4(sc, TL_HOSTCMD);
+ cmd |= TL_CMD_NES;
+ cmd &= ~(TL_CMD_RT|TL_CMD_EOC|TL_CMD_ACK_MASK|TL_CMD_CHSEL_MASK);
+ CMD_PUT(sc, cmd | (TL_CMD_LDTHR | TX_THR));
+ CMD_PUT(sc, cmd | (TL_CMD_LDTMR | 0x00000003));
+
+ /* Unreset the MII */
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_NMRST);
+
+ /* Take the adapter out of reset */
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NRESET|TL_CMD_NWRAP);
+
+ /* Wait for things to settle down a little. */
+ DELAY(500);
+
+ return;
+}
+
+/*
+ * Probe for a ThunderLAN chip. Check the PCI vendor and device IDs
+ * against our list and return its name if we find a match.
+ */
+static int tl_probe(dev)
+ device_t dev;
+{
+ struct tl_type *t;
+
+ t = tl_devs;
+
+ while(t->tl_name != NULL) {
+ if ((pci_get_vendor(dev) == t->tl_vid) &&
+ (pci_get_device(dev) == t->tl_did)) {
+ device_set_desc(dev, t->tl_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+static int tl_attach(dev)
+ device_t dev;
+{
+ int i;
+ u_int32_t command;
+ u_int16_t did, vid;
+ struct tl_type *t;
+ struct ifnet *ifp;
+ struct tl_softc *sc;
+ int unit, error = 0, rid;
+
+ vid = pci_get_vendor(dev);
+ did = pci_get_device(dev);
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct tl_softc));
+
+ t = tl_devs;
+ while(t->tl_name != NULL) {
+ if (vid == t->tl_vid && did == t->tl_did)
+ break;
+ t++;
+ }
+
+ if (t->tl_name == NULL) {
+ printf("tl%d: unknown device!?\n", unit);
+ goto fail;
+ }
+
+ mtx_init(&sc->tl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ TL_LOCK(sc);
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef TL_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("tl%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = TL_PCI_LOIO;
+ sc->tl_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ /*
+ * Some cards have the I/O and memory mapped address registers
+ * reversed. Try both combinations before giving up.
+ */
+ if (sc->tl_res == NULL) {
+ rid = TL_PCI_LOMEM;
+ sc->tl_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("tl%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = TL_PCI_LOMEM;
+ sc->tl_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (sc->tl_res == NULL) {
+ rid = TL_PCI_LOIO;
+ sc->tl_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ }
+#endif
+
+ if (sc->tl_res == NULL) {
+ printf("tl%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->tl_btag = rman_get_bustag(sc->tl_res);
+ sc->tl_bhandle = rman_get_bushandle(sc->tl_res);
+
+#ifdef notdef
+ /*
+ * The ThunderLAN manual suggests jacking the PCI latency
+ * timer all the way up to its maximum value. I'm not sure
+ * if this is really necessary, but what the manual wants,
+ * the manual gets.
+ */
+ command = pci_read_config(dev, TL_PCI_LATENCY_TIMER, 4);
+ command |= 0x0000FF00;
+ pci_write_config(dev, TL_PCI_LATENCY_TIMER, command, 4);
+#endif
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->tl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->tl_irq == NULL) {
+ bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
+ printf("tl%d: couldn't map interrupt\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->tl_irq, INTR_TYPE_NET,
+ tl_intr, sc, &sc->tl_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->tl_irq);
+ bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
+ printf("tl%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /*
+ * Now allocate memory for the TX and RX lists.
+ */
+ sc->tl_ldata = contigmalloc(sizeof(struct tl_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->tl_ldata == NULL) {
+ bus_teardown_intr(dev, sc->tl_irq, sc->tl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->tl_irq);
+ bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
+ printf("tl%d: no memory for list buffers!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->tl_ldata, sizeof(struct tl_list_data));
+
+ sc->tl_unit = unit;
+ sc->tl_dinfo = t;
+ if (t->tl_vid == COMPAQ_VENDORID || t->tl_vid == TI_VENDORID)
+ sc->tl_eeaddr = TL_EEPROM_EADDR;
+ if (t->tl_vid == OLICOM_VENDORID)
+ sc->tl_eeaddr = TL_EEPROM_EADDR_OC;
+
+ /* Reset the adapter. */
+ tl_softreset(sc, 1);
+ tl_hardreset(dev);
+ tl_softreset(sc, 1);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ if (tl_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
+ sc->tl_eeaddr, ETHER_ADDR_LEN)) {
+ bus_teardown_intr(dev, sc->tl_irq, sc->tl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->tl_irq);
+ bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
+ contigfree(sc->tl_ldata,
+ sizeof(struct tl_list_data), M_DEVBUF);
+ printf("tl%d: failed to read station address\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * XXX Olicom, in its desire to be different from the
+ * rest of the world, has done strange things with the
+ * encoding of the station address in the EEPROM. First
+ * of all, they store the address at offset 0xF8 rather
+ * than at 0x83 like the ThunderLAN manual suggests.
+ * Second, they store the address in three 16-bit words in
+ * network byte order, as opposed to storing it sequentially
+ * like all the other ThunderLAN cards. In order to get
+ * the station address in a form that matches what the Olicom
+ * diagnostic utility specifies, we have to byte-swap each
+ * word. To make things even more confusing, neither 00:00:28
+ * nor 00:00:24 appear in the IEEE OUI database.
+ */
+ if (sc->tl_dinfo->tl_vid == OLICOM_VENDORID) {
+ for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
+ u_int16_t *p;
+ p = (u_int16_t *)&sc->arpcom.ac_enaddr[i];
+ *p = ntohs(*p);
+ }
+ }
+
+ /*
+ * A ThunderLAN chip was detected. Inform the world.
+ */
+ printf("tl%d: Ethernet address: %6D\n", unit,
+ sc->arpcom.ac_enaddr, ":");
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = sc->tl_unit;
+ ifp->if_name = "tl";
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = tl_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = tl_start;
+ ifp->if_watchdog = tl_watchdog;
+ ifp->if_init = tl_init;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_snd.ifq_maxlen = TL_TX_LIST_CNT - 1;
+ callout_handle_init(&sc->tl_stat_ch);
+
+ /* Reset the adapter again. */
+ tl_softreset(sc, 1);
+ tl_hardreset(dev);
+ tl_softreset(sc, 1);
+
+ /*
+ * Do MII setup. If no PHYs are found, then this is a
+ * bitrate ThunderLAN chip that only supports 10baseT
+ * and AUI/BNC.
+ */
+ if (mii_phy_probe(dev, &sc->tl_miibus,
+ tl_ifmedia_upd, tl_ifmedia_sts)) {
+ struct ifmedia *ifm;
+ sc->tl_bitrate = 1;
+ ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
+ ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_10_T);
+ /* Reset again, this time setting bitrate mode. */
+ tl_softreset(sc, 1);
+ ifm = &sc->ifmedia;
+ ifm->ifm_media = ifm->ifm_cur->ifm_media;
+ tl_ifmedia_upd(ifp);
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ TL_UNLOCK(sc);
+ return(0);
+
+fail:
+ TL_UNLOCK(sc);
+ mtx_destroy(&sc->tl_mtx);
+ return(error);
+}
+
+static int tl_detach(dev)
+ device_t dev;
+{
+ struct tl_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ TL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ tl_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->tl_miibus);
+
+ contigfree(sc->tl_ldata, sizeof(struct tl_list_data), M_DEVBUF);
+ if (sc->tl_bitrate)
+ ifmedia_removeall(&sc->ifmedia);
+
+ bus_teardown_intr(dev, sc->tl_irq, sc->tl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->tl_irq);
+ bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
+
+ TL_UNLOCK(sc);
+ mtx_destroy(&sc->tl_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit lists.
+ */
+static int tl_list_tx_init(sc)
+ struct tl_softc *sc;
+{
+ struct tl_chain_data *cd;
+ struct tl_list_data *ld;
+ int i;
+
+ cd = &sc->tl_cdata;
+ ld = sc->tl_ldata;
+ for (i = 0; i < TL_TX_LIST_CNT; i++) {
+ cd->tl_tx_chain[i].tl_ptr = &ld->tl_tx_list[i];
+ if (i == (TL_TX_LIST_CNT - 1))
+ cd->tl_tx_chain[i].tl_next = NULL;
+ else
+ cd->tl_tx_chain[i].tl_next = &cd->tl_tx_chain[i + 1];
+ }
+
+ cd->tl_tx_free = &cd->tl_tx_chain[0];
+ cd->tl_tx_tail = cd->tl_tx_head = NULL;
+ sc->tl_txeoc = 1;
+
+ return(0);
+}
+
+/*
+ * Initialize the RX lists and allocate mbufs for them.
+ */
+static int tl_list_rx_init(sc)
+ struct tl_softc *sc;
+{
+ struct tl_chain_data *cd;
+ struct tl_list_data *ld;
+ int i;
+
+ cd = &sc->tl_cdata;
+ ld = sc->tl_ldata;
+
+ for (i = 0; i < TL_RX_LIST_CNT; i++) {
+ cd->tl_rx_chain[i].tl_ptr =
+ (struct tl_list_onefrag *)&ld->tl_rx_list[i];
+ if (tl_newbuf(sc, &cd->tl_rx_chain[i]) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (TL_RX_LIST_CNT - 1)) {
+ cd->tl_rx_chain[i].tl_next = NULL;
+ ld->tl_rx_list[i].tlist_fptr = 0;
+ } else {
+ cd->tl_rx_chain[i].tl_next = &cd->tl_rx_chain[i + 1];
+ ld->tl_rx_list[i].tlist_fptr =
+ vtophys(&ld->tl_rx_list[i + 1]);
+ }
+ }
+
+ cd->tl_rx_head = &cd->tl_rx_chain[0];
+ cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1];
+
+ return(0);
+}
+
+static int tl_newbuf(sc, c)
+ struct tl_softc *sc;
+ struct tl_chain_onefrag *c;
+{
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+
+#ifdef __alpha__
+ m_new->m_data += 2;
+#endif
+
+ c->tl_mbuf = m_new;
+ c->tl_next = NULL;
+ c->tl_ptr->tlist_frsize = MCLBYTES;
+ c->tl_ptr->tlist_fptr = 0;
+ c->tl_ptr->tl_frag.tlist_dadr = vtophys(mtod(m_new, caddr_t));
+ c->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES;
+ c->tl_ptr->tlist_cstat = TL_CSTAT_READY;
+
+ return(0);
+}
+/*
+ * Interrupt handler for RX 'end of frame' condition (EOF). This
+ * tells us that a full ethernet frame has been captured and we need
+ * to handle it.
+ *
+ * Reception is done using 'lists' which consist of a header and a
+ * series of 10 data count/data address pairs that point to buffers.
+ * Initially you're supposed to create a list, populate it with pointers
+ * to buffers, then load the physical address of the list into the
+ * ch_parm register. The adapter is then supposed to DMA the received
+ * frame into the buffers for you.
+ *
+ * To make things as fast as possible, we have the chip DMA directly
+ * into mbufs. This saves us from having to do a buffer copy: we can
+ * just hand the mbufs directly to ether_input(). Once the frame has
+ * been sent on its way, the 'list' structure is assigned a new buffer
+ * and moved to the end of the RX chain. As long we we stay ahead of
+ * the chip, it will always think it has an endless receive channel.
+ *
+ * If we happen to fall behind and the chip manages to fill up all of
+ * the buffers, it will generate an end of channel interrupt and wait
+ * for us to empty the chain and restart the receiver.
+ */
+static int tl_intvec_rxeof(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+ int r = 0, total_len = 0;
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct tl_chain_onefrag *cur_rx;
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+
+ while(sc->tl_cdata.tl_rx_head != NULL) {
+ cur_rx = sc->tl_cdata.tl_rx_head;
+ if (!(cur_rx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP))
+ break;
+ r++;
+ sc->tl_cdata.tl_rx_head = cur_rx->tl_next;
+ m = cur_rx->tl_mbuf;
+ total_len = cur_rx->tl_ptr->tlist_frsize;
+
+ if (tl_newbuf(sc, cur_rx) == ENOBUFS) {
+ ifp->if_ierrors++;
+ cur_rx->tl_ptr->tlist_frsize = MCLBYTES;
+ cur_rx->tl_ptr->tlist_cstat = TL_CSTAT_READY;
+ cur_rx->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES;
+ continue;
+ }
+
+ sc->tl_cdata.tl_rx_tail->tl_ptr->tlist_fptr =
+ vtophys(cur_rx->tl_ptr);
+ sc->tl_cdata.tl_rx_tail->tl_next = cur_rx;
+ sc->tl_cdata.tl_rx_tail = cur_rx;
+
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+
+ /*
+ * Note: when the ThunderLAN chip is in 'capture all
+ * frames' mode, it will receive its own transmissions.
+ * We drop don't need to process our own transmissions,
+ * so we drop them here and continue.
+ */
+ /*if (ifp->if_flags & IFF_PROMISC && */
+ if (!bcmp(eh->ether_shost, sc->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN)) {
+ m_freem(m);
+ continue;
+ }
+
+ /* Remove header from mbuf and pass it on. */
+ m->m_pkthdr.len = m->m_len =
+ total_len - sizeof(struct ether_header);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+ }
+
+ return(r);
+}
+
+/*
+ * The RX-EOC condition hits when the ch_parm address hasn't been
+ * initialized or the adapter reached a list with a forward pointer
+ * of 0 (which indicates the end of the chain). In our case, this means
+ * the card has hit the end of the receive buffer chain and we need to
+ * empty out the buffers and shift the pointer back to the beginning again.
+ */
+static int tl_intvec_rxeoc(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+ int r;
+ struct tl_chain_data *cd;
+
+
+ sc = xsc;
+ cd = &sc->tl_cdata;
+
+ /* Flush out the receive queue and ack RXEOF interrupts. */
+ r = tl_intvec_rxeof(xsc, type);
+ CMD_PUT(sc, TL_CMD_ACK | r | (type & ~(0x00100000)));
+ r = 1;
+ cd->tl_rx_head = &cd->tl_rx_chain[0];
+ cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1];
+ CSR_WRITE_4(sc, TL_CH_PARM, vtophys(sc->tl_cdata.tl_rx_head->tl_ptr));
+ r |= (TL_CMD_GO|TL_CMD_RT);
+ return(r);
+}
+
+static int tl_intvec_txeof(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+ int r = 0;
+ struct tl_chain *cur_tx;
+
+ sc = xsc;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been sent.
+ */
+ while (sc->tl_cdata.tl_tx_head != NULL) {
+ cur_tx = sc->tl_cdata.tl_tx_head;
+ if (!(cur_tx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP))
+ break;
+ sc->tl_cdata.tl_tx_head = cur_tx->tl_next;
+
+ r++;
+ m_freem(cur_tx->tl_mbuf);
+ cur_tx->tl_mbuf = NULL;
+
+ cur_tx->tl_next = sc->tl_cdata.tl_tx_free;
+ sc->tl_cdata.tl_tx_free = cur_tx;
+ if (!cur_tx->tl_ptr->tlist_fptr)
+ break;
+ }
+
+ return(r);
+}
+
+/*
+ * The transmit end of channel interrupt. The adapter triggers this
+ * interrupt to tell us it hit the end of the current transmit list.
+ *
+ * A note about this: it's possible for a condition to arise where
+ * tl_start() may try to send frames between TXEOF and TXEOC interrupts.
+ * You have to avoid this since the chip expects things to go in a
+ * particular order: transmit, acknowledge TXEOF, acknowledge TXEOC.
+ * When the TXEOF handler is called, it will free all of the transmitted
+ * frames and reset the tx_head pointer to NULL. However, a TXEOC
+ * interrupt should be received and acknowledged before any more frames
+ * are queued for transmission. If tl_statrt() is called after TXEOF
+ * resets the tx_head pointer but _before_ the TXEOC interrupt arrives,
+ * it could attempt to issue a transmit command prematurely.
+ *
+ * To guard against this, tl_start() will only issue transmit commands
+ * if the tl_txeoc flag is set, and only the TXEOC interrupt handler
+ * can set this flag once tl_start() has cleared it.
+ */
+static int tl_intvec_txeoc(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t cmd;
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ if (sc->tl_cdata.tl_tx_head == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->tl_cdata.tl_tx_tail = NULL;
+ sc->tl_txeoc = 1;
+ } else {
+ sc->tl_txeoc = 0;
+ /* First we have to ack the EOC interrupt. */
+ CMD_PUT(sc, TL_CMD_ACK | 0x00000001 | type);
+ /* Then load the address of the next TX list. */
+ CSR_WRITE_4(sc, TL_CH_PARM,
+ vtophys(sc->tl_cdata.tl_tx_head->tl_ptr));
+ /* Restart TX channel. */
+ cmd = CSR_READ_4(sc, TL_HOSTCMD);
+ cmd &= ~TL_CMD_RT;
+ cmd |= TL_CMD_GO|TL_CMD_INTSON;
+ CMD_PUT(sc, cmd);
+ return(0);
+ }
+
+ return(1);
+}
+
+static int tl_intvec_adchk(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+
+ sc = xsc;
+
+ if (type)
+ printf("tl%d: adapter check: %x\n", sc->tl_unit,
+ (unsigned int)CSR_READ_4(sc, TL_CH_PARM));
+
+ tl_softreset(sc, 1);
+ tl_stop(sc);
+ tl_init(sc);
+ CMD_SET(sc, TL_CMD_INTSON);
+
+ return(0);
+}
+
+static int tl_intvec_netsts(xsc, type)
+ void *xsc;
+ u_int32_t type;
+{
+ struct tl_softc *sc;
+ u_int16_t netsts;
+
+ sc = xsc;
+
+ netsts = tl_dio_read16(sc, TL_NETSTS);
+ tl_dio_write16(sc, TL_NETSTS, netsts);
+
+ printf("tl%d: network status: %x\n", sc->tl_unit, netsts);
+
+ return(1);
+}
+
+static void tl_intr(xsc)
+ void *xsc;
+{
+ struct tl_softc *sc;
+ struct ifnet *ifp;
+ int r = 0;
+ u_int32_t type = 0;
+ u_int16_t ints = 0;
+ u_int8_t ivec = 0;
+
+ sc = xsc;
+ TL_LOCK(sc);
+
+ /* Disable interrupts */
+ ints = CSR_READ_2(sc, TL_HOST_INT);
+ CSR_WRITE_2(sc, TL_HOST_INT, ints);
+ type = (ints << 16) & 0xFFFF0000;
+ ivec = (ints & TL_VEC_MASK) >> 5;
+ ints = (ints & TL_INT_MASK) >> 2;
+
+ ifp = &sc->arpcom.ac_if;
+
+ switch(ints) {
+ case (TL_INTR_INVALID):
+#ifdef DIAGNOSTIC
+ printf("tl%d: got an invalid interrupt!\n", sc->tl_unit);
+#endif
+ /* Re-enable interrupts but don't ack this one. */
+ CMD_PUT(sc, type);
+ r = 0;
+ break;
+ case (TL_INTR_TXEOF):
+ r = tl_intvec_txeof((void *)sc, type);
+ break;
+ case (TL_INTR_TXEOC):
+ r = tl_intvec_txeoc((void *)sc, type);
+ break;
+ case (TL_INTR_STATOFLOW):
+ tl_stats_update(sc);
+ r = 1;
+ break;
+ case (TL_INTR_RXEOF):
+ r = tl_intvec_rxeof((void *)sc, type);
+ break;
+ case (TL_INTR_DUMMY):
+ printf("tl%d: got a dummy interrupt\n", sc->tl_unit);
+ r = 1;
+ break;
+ case (TL_INTR_ADCHK):
+ if (ivec)
+ r = tl_intvec_adchk((void *)sc, type);
+ else
+ r = tl_intvec_netsts((void *)sc, type);
+ break;
+ case (TL_INTR_RXEOC):
+ r = tl_intvec_rxeoc((void *)sc, type);
+ break;
+ default:
+ printf("tl%d: bogus interrupt type\n", ifp->if_unit);
+ break;
+ }
+
+ /* Re-enable interrupts */
+ if (r) {
+ CMD_PUT(sc, TL_CMD_ACK | r | type);
+ }
+
+ if (ifp->if_snd.ifq_head != NULL)
+ tl_start(ifp);
+
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+static void tl_stats_update(xsc)
+ void *xsc;
+{
+ struct tl_softc *sc;
+ struct ifnet *ifp;
+ struct tl_stats tl_stats;
+ struct mii_data *mii;
+ u_int32_t *p;
+
+ bzero((char *)&tl_stats, sizeof(struct tl_stats));
+
+ sc = xsc;
+ TL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ p = (u_int32_t *)&tl_stats;
+
+ CSR_WRITE_2(sc, TL_DIO_ADDR, TL_TXGOODFRAMES|TL_DIO_ADDR_INC);
+ *p++ = CSR_READ_4(sc, TL_DIO_DATA);
+ *p++ = CSR_READ_4(sc, TL_DIO_DATA);
+ *p++ = CSR_READ_4(sc, TL_DIO_DATA);
+ *p++ = CSR_READ_4(sc, TL_DIO_DATA);
+ *p++ = CSR_READ_4(sc, TL_DIO_DATA);
+
+ ifp->if_opackets += tl_tx_goodframes(tl_stats);
+ ifp->if_collisions += tl_stats.tl_tx_single_collision +
+ tl_stats.tl_tx_multi_collision;
+ ifp->if_ipackets += tl_rx_goodframes(tl_stats);
+ ifp->if_ierrors += tl_stats.tl_crc_errors + tl_stats.tl_code_errors +
+ tl_rx_overrun(tl_stats);
+ ifp->if_oerrors += tl_tx_underrun(tl_stats);
+
+ if (tl_tx_underrun(tl_stats)) {
+ u_int8_t tx_thresh;
+ tx_thresh = tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_TXTHRESH;
+ if (tx_thresh != TL_AC_TXTHRESH_WHOLEPKT) {
+ tx_thresh >>= 4;
+ tx_thresh++;
+ printf("tl%d: tx underrun -- increasing "
+ "tx threshold to %d bytes\n", sc->tl_unit,
+ (64 * (tx_thresh * 4)));
+ tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH);
+ tl_dio_setbit(sc, TL_ACOMMIT, tx_thresh << 4);
+ }
+ }
+
+ sc->tl_stat_ch = timeout(tl_stats_update, sc, hz);
+
+ if (!sc->tl_bitrate) {
+ mii = device_get_softc(sc->tl_miibus);
+ mii_tick(mii);
+ }
+
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a list by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int tl_encap(sc, c, m_head)
+ struct tl_softc *sc;
+ struct tl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct tl_frag *f = NULL;
+ int total_len;
+ struct mbuf *m;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ total_len = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == TL_MAXFRAGS)
+ break;
+ total_len+= m->m_len;
+ c->tl_ptr->tl_frag[frag].tlist_dadr =
+ vtophys(mtod(m, vm_offset_t));
+ c->tl_ptr->tl_frag[frag].tlist_dcnt = m->m_len;
+ frag++;
+ }
+ }
+
+ /*
+ * Handle special cases.
+ * Special case #1: we used up all 10 fragments, but
+ * we have more mbufs left in the chain. Copy the
+ * data into an mbuf cluster. Note that we don't
+ * bother clearing the values in the other fragment
+ * pointers/counters; it wouldn't gain us anything,
+ * and would waste cycles.
+ */
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("tl%d: no memory for tx list\n", sc->tl_unit);
+ return(1);
+ }
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ printf("tl%d: no memory for tx list\n",
+ sc->tl_unit);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ f = &c->tl_ptr->tl_frag[0];
+ f->tlist_dadr = vtophys(mtod(m_new, caddr_t));
+ f->tlist_dcnt = total_len = m_new->m_len;
+ frag = 1;
+ }
+
+ /*
+ * Special case #2: the frame is smaller than the minimum
+ * frame size. We have to pad it to make the chip happy.
+ */
+ if (total_len < TL_MIN_FRAMELEN) {
+ if (frag == TL_MAXFRAGS)
+ printf("tl%d: all frags filled but "
+ "frame still to small!\n", sc->tl_unit);
+ f = &c->tl_ptr->tl_frag[frag];
+ f->tlist_dcnt = TL_MIN_FRAMELEN - total_len;
+ f->tlist_dadr = vtophys(&sc->tl_ldata->tl_pad);
+ total_len += f->tlist_dcnt;
+ frag++;
+ }
+
+ c->tl_mbuf = m_head;
+ c->tl_ptr->tl_frag[frag - 1].tlist_dcnt |= TL_LAST_FRAG;
+ c->tl_ptr->tlist_frsize = total_len;
+ c->tl_ptr->tlist_cstat = TL_CSTAT_READY;
+ c->tl_ptr->tlist_fptr = 0;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+static void tl_start(ifp)
+ struct ifnet *ifp;
+{
+ struct tl_softc *sc;
+ struct mbuf *m_head = NULL;
+ u_int32_t cmd;
+ struct tl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+
+ sc = ifp->if_softc;
+ TL_LOCK(sc);
+
+ /*
+ * Check for an available queue slot. If there are none,
+ * punt.
+ */
+ if (sc->tl_cdata.tl_tx_free == NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ TL_UNLOCK(sc);
+ return;
+ }
+
+ start_tx = sc->tl_cdata.tl_tx_free;
+
+ while(sc->tl_cdata.tl_tx_free != NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /* Pick a chain member off the free list. */
+ cur_tx = sc->tl_cdata.tl_tx_free;
+ sc->tl_cdata.tl_tx_free = cur_tx->tl_next;
+
+ cur_tx->tl_next = NULL;
+
+ /* Pack the data into the list. */
+ tl_encap(sc, cur_tx, m_head);
+
+ /* Chain it together */
+ if (prev != NULL) {
+ prev->tl_next = cur_tx;
+ prev->tl_ptr->tlist_fptr = vtophys(cur_tx->tl_ptr);
+ }
+ prev = cur_tx;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->tl_mbuf);
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL) {
+ TL_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * That's all we can stands, we can't stands no more.
+ * If there are no other transfers pending, then issue the
+ * TX GO command to the adapter to start things moving.
+ * Otherwise, just leave the data in the queue and let
+ * the EOF/EOC interrupt handler send.
+ */
+ if (sc->tl_cdata.tl_tx_head == NULL) {
+ sc->tl_cdata.tl_tx_head = start_tx;
+ sc->tl_cdata.tl_tx_tail = cur_tx;
+
+ if (sc->tl_txeoc) {
+ sc->tl_txeoc = 0;
+ CSR_WRITE_4(sc, TL_CH_PARM, vtophys(start_tx->tl_ptr));
+ cmd = CSR_READ_4(sc, TL_HOSTCMD);
+ cmd &= ~TL_CMD_RT;
+ cmd |= TL_CMD_GO|TL_CMD_INTSON;
+ CMD_PUT(sc, cmd);
+ }
+ } else {
+ sc->tl_cdata.tl_tx_tail->tl_next = start_tx;
+ sc->tl_cdata.tl_tx_tail = cur_tx;
+ }
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+static void tl_init(xsc)
+ void *xsc;
+{
+ struct tl_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+
+ TL_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ /*
+ * Cancel pending I/O.
+ */
+ tl_stop(sc);
+
+ /* Initialize TX FIFO threshold */
+ tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH);
+ tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH_16LONG);
+
+ /* Set PCI burst size */
+ tl_dio_write8(sc, TL_BSIZEREG, TL_RXBURST_16LONG|TL_TXBURST_16LONG);
+
+ /*
+ * Set 'capture all frames' bit for promiscuous mode.
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF);
+ else
+ tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF);
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST)
+ tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_NOBRX);
+ else
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NOBRX);
+
+ tl_dio_write16(sc, TL_MAXRX, MCLBYTES);
+
+ /* Init our MAC address */
+ tl_setfilt(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0);
+
+ /* Init multicast filter, if needed. */
+ tl_setmulti(sc);
+
+ /* Init circular RX list. */
+ if (tl_list_rx_init(sc) == ENOBUFS) {
+ printf("tl%d: initialization failed: no "
+ "memory for rx buffers\n", sc->tl_unit);
+ tl_stop(sc);
+ TL_UNLOCK(sc);
+ return;
+ }
+
+ /* Init TX pointers. */
+ tl_list_tx_init(sc);
+
+ /* Enable PCI interrupts. */
+ CMD_SET(sc, TL_CMD_INTSON);
+
+ /* Load the address of the rx list */
+ CMD_SET(sc, TL_CMD_RT);
+ CSR_WRITE_4(sc, TL_CH_PARM, vtophys(&sc->tl_ldata->tl_rx_list[0]));
+
+ if (!sc->tl_bitrate) {
+ if (sc->tl_miibus != NULL) {
+ mii = device_get_softc(sc->tl_miibus);
+ mii_mediachg(mii);
+ }
+ }
+
+ /* Send the RX go command */
+ CMD_SET(sc, TL_CMD_GO|TL_CMD_NES|TL_CMD_RT);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* Start the stats update counter */
+ sc->tl_stat_ch = timeout(tl_stats_update, sc, hz);
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int tl_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct tl_softc *sc;
+ struct mii_data *mii = NULL;
+
+ sc = ifp->if_softc;
+
+ if (sc->tl_bitrate)
+ tl_setmode(sc, sc->ifmedia.ifm_media);
+ else {
+ mii = device_get_softc(sc->tl_miibus);
+ mii_mediachg(mii);
+ }
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void tl_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct tl_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ ifmr->ifm_active = IFM_ETHER;
+
+ if (sc->tl_bitrate) {
+ if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD1)
+ ifmr->ifm_active = IFM_ETHER|IFM_10_5;
+ else
+ ifmr->ifm_active = IFM_ETHER|IFM_10_T;
+ if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD3)
+ ifmr->ifm_active |= IFM_HDX;
+ else
+ ifmr->ifm_active |= IFM_FDX;
+ return;
+ } else {
+ mii = device_get_softc(sc->tl_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ }
+
+ return;
+}
+
+static int tl_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct tl_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->tl_if_flags & IFF_PROMISC)) {
+ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF);
+ tl_setmulti(sc);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->tl_if_flags & IFF_PROMISC) {
+ tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF);
+ tl_setmulti(sc);
+ } else
+ tl_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING) {
+ tl_stop(sc);
+ }
+ }
+ sc->tl_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ tl_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ if (sc->tl_bitrate)
+ error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ else {
+ struct mii_data *mii;
+ mii = device_get_softc(sc->tl_miibus);
+ error = ifmedia_ioctl(ifp, ifr,
+ &mii->mii_media, command);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void)splx(s);
+
+ return(error);
+}
+
+static void tl_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct tl_softc *sc;
+
+ sc = ifp->if_softc;
+
+ printf("tl%d: device timeout\n", sc->tl_unit);
+
+ ifp->if_oerrors++;
+
+ tl_softreset(sc, 1);
+ tl_init(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void tl_stop(sc)
+ struct tl_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ TL_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Stop the stats updater. */
+ untimeout(tl_stats_update, sc, sc->tl_stat_ch);
+
+ /* Stop the transmitter */
+ CMD_CLR(sc, TL_CMD_RT);
+ CMD_SET(sc, TL_CMD_STOP);
+ CSR_WRITE_4(sc, TL_CH_PARM, 0);
+
+ /* Stop the receiver */
+ CMD_SET(sc, TL_CMD_RT);
+ CMD_SET(sc, TL_CMD_STOP);
+ CSR_WRITE_4(sc, TL_CH_PARM, 0);
+
+ /*
+ * Disable host interrupts.
+ */
+ CMD_SET(sc, TL_CMD_INTSOFF);
+
+ /*
+ * Clear list pointer.
+ */
+ CSR_WRITE_4(sc, TL_CH_PARM, 0);
+
+ /*
+ * Free the RX lists.
+ */
+ for (i = 0; i < TL_RX_LIST_CNT; i++) {
+ if (sc->tl_cdata.tl_rx_chain[i].tl_mbuf != NULL) {
+ m_freem(sc->tl_cdata.tl_rx_chain[i].tl_mbuf);
+ sc->tl_cdata.tl_rx_chain[i].tl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->tl_ldata->tl_rx_list,
+ sizeof(sc->tl_ldata->tl_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < TL_TX_LIST_CNT; i++) {
+ if (sc->tl_cdata.tl_tx_chain[i].tl_mbuf != NULL) {
+ m_freem(sc->tl_cdata.tl_tx_chain[i].tl_mbuf);
+ sc->tl_cdata.tl_tx_chain[i].tl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->tl_ldata->tl_tx_list,
+ sizeof(sc->tl_ldata->tl_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ TL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void tl_shutdown(dev)
+ device_t dev;
+{
+ struct tl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ tl_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_tlreg.h b/sys/pci/if_tlreg.h
new file mode 100644
index 0000000..bd7ea5b
--- /dev/null
+++ b/sys/pci/if_tlreg.h
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+
+struct tl_type {
+ u_int16_t tl_vid;
+ u_int16_t tl_did;
+ char *tl_name;
+};
+
+/*
+ * ThunderLAN TX/RX list format. The TX and RX lists are pretty much
+ * identical: the list begins with a 32-bit forward pointer which points
+ * at the next list in the chain, followed by 16 bits for the total
+ * frame size, and a 16 bit status field. This is followed by a series
+ * of 10 32-bit data count/data address pairs that point to the fragments
+ * that make up the complete frame.
+ */
+
+#define TL_MAXFRAGS 10
+#define TL_RX_LIST_CNT 64
+#define TL_TX_LIST_CNT 128
+#define TL_MIN_FRAMELEN 64
+
+struct tl_frag {
+ u_int32_t tlist_dcnt;
+ u_int32_t tlist_dadr;
+};
+
+struct tl_list {
+ u_int32_t tlist_fptr; /* phys address of next list */
+ u_int16_t tlist_cstat; /* status word */
+ u_int16_t tlist_frsize; /* size of data in frame */
+ struct tl_frag tl_frag[TL_MAXFRAGS];
+};
+
+/*
+ * This is a special case of an RX list. By setting the One_Frag
+ * bit in the NETCONFIG register, the driver can force the ThunderLAN
+ * chip to use only one fragment when DMAing RX frames.
+ */
+
+struct tl_list_onefrag {
+ u_int32_t tlist_fptr;
+ u_int16_t tlist_cstat;
+ u_int16_t tlist_frsize;
+ struct tl_frag tl_frag;
+};
+
+struct tl_list_data {
+ struct tl_list_onefrag tl_rx_list[TL_RX_LIST_CNT];
+ struct tl_list tl_tx_list[TL_TX_LIST_CNT];
+ unsigned char tl_pad[TL_MIN_FRAMELEN];
+};
+
+struct tl_chain {
+ struct tl_list *tl_ptr;
+ struct mbuf *tl_mbuf;
+ struct tl_chain *tl_next;
+};
+
+struct tl_chain_onefrag {
+ struct tl_list_onefrag *tl_ptr;
+ struct mbuf *tl_mbuf;
+ struct tl_chain_onefrag *tl_next;
+};
+
+struct tl_chain_data {
+ struct tl_chain_onefrag tl_rx_chain[TL_RX_LIST_CNT];
+ struct tl_chain tl_tx_chain[TL_TX_LIST_CNT];
+
+ struct tl_chain_onefrag *tl_rx_head;
+ struct tl_chain_onefrag *tl_rx_tail;
+
+ struct tl_chain *tl_tx_head;
+ struct tl_chain *tl_tx_tail;
+ struct tl_chain *tl_tx_free;
+};
+
+struct tl_softc {
+ struct arpcom arpcom; /* interface info */
+ struct ifmedia ifmedia; /* media info */
+ bus_space_handle_t tl_bhandle;
+ bus_space_tag_t tl_btag;
+ void *tl_intrhand;
+ struct resource *tl_irq;
+ struct resource *tl_res;
+ device_t tl_miibus;
+ struct tl_type *tl_dinfo; /* ThunderLAN adapter info */
+ u_int8_t tl_unit; /* interface number */
+ u_int8_t tl_eeaddr;
+ struct tl_list_data *tl_ldata; /* TX/RX lists and mbufs */
+ struct tl_chain_data tl_cdata;
+ u_int8_t tl_txeoc;
+ u_int8_t tl_bitrate;
+ int tl_if_flags;
+ struct callout_handle tl_stat_ch;
+ struct mtx tl_mtx;
+};
+
+#define TL_LOCK(_sc) mtx_lock(&(_sc)->tl_mtx)
+#define TL_UNLOCK(_sc) mtx_unlock(&(_sc)->tl_mtx)
+
+/*
+ * Transmit interrupt threshold.
+ */
+#define TX_THR 0x00000004
+
+/*
+ * General constants that are fun to know.
+ *
+ * The ThunderLAN controller is made by Texas Instruments. The
+ * manual indicates that if the EEPROM checksum fails, the PCI
+ * vendor and device ID registers will be loaded with TI-specific
+ * values.
+ */
+#define TI_VENDORID 0x104C
+#define TI_DEVICEID_THUNDERLAN 0x0500
+
+/*
+ * These are the PCI vendor and device IDs for Compaq ethernet
+ * adapters based on the ThunderLAN controller.
+ */
+#define COMPAQ_VENDORID 0x0E11
+#define COMPAQ_DEVICEID_NETEL_10_100 0xAE32
+#define COMPAQ_DEVICEID_NETEL_UNKNOWN 0xAE33
+#define COMPAQ_DEVICEID_NETEL_10 0xAE34
+#define COMPAQ_DEVICEID_NETFLEX_3P_INTEGRATED 0xAE35
+#define COMPAQ_DEVICEID_NETEL_10_100_DUAL 0xAE40
+#define COMPAQ_DEVICEID_NETEL_10_100_PROLIANT 0xAE43
+#define COMPAQ_DEVICEID_NETEL_10_100_EMBEDDED 0xB011
+#define COMPAQ_DEVICEID_NETEL_10_T2_UTP_COAX 0xB012
+#define COMPAQ_DEVICEID_NETEL_10_100_TX_UTP 0xB030
+#define COMPAQ_DEVICEID_NETFLEX_3P 0xF130
+#define COMPAQ_DEVICEID_NETFLEX_3P_BNC 0xF150
+
+/*
+ * These are the PCI vendor and device IDs for Olicom
+ * adapters based on the ThunderLAN controller.
+ */
+#define OLICOM_VENDORID 0x108D
+#define OLICOM_DEVICEID_OC2183 0x0013
+#define OLICOM_DEVICEID_OC2325 0x0012
+#define OLICOM_DEVICEID_OC2326 0x0014
+
+/*
+ * PCI low memory base and low I/O base
+ */
+#define TL_PCI_LOIO 0x10
+#define TL_PCI_LOMEM 0x14
+
+/*
+ * PCI latency timer (it's actually 0x0D, but we want a value
+ * that's longword aligned).
+ */
+#define TL_PCI_LATENCY_TIMER 0x0C
+
+#define TL_DIO_ADDR_INC 0x8000 /* Increment addr on each read */
+#define TL_DIO_RAM_SEL 0x4000 /* RAM address select */
+#define TL_DIO_ADDR_MASK 0x3FFF /* address bits mask */
+
+/*
+ * Interrupt types
+ */
+#define TL_INTR_INVALID 0x0
+#define TL_INTR_TXEOF 0x1
+#define TL_INTR_STATOFLOW 0x2
+#define TL_INTR_RXEOF 0x3
+#define TL_INTR_DUMMY 0x4
+#define TL_INTR_TXEOC 0x5
+#define TL_INTR_ADCHK 0x6
+#define TL_INTR_RXEOC 0x7
+
+#define TL_INT_MASK 0x001C
+#define TL_VEC_MASK 0x1FE0
+/*
+ * Host command register bits
+ */
+#define TL_CMD_GO 0x80000000
+#define TL_CMD_STOP 0x40000000
+#define TL_CMD_ACK 0x20000000
+#define TL_CMD_CHSEL7 0x10000000
+#define TL_CMD_CHSEL6 0x08000000
+#define TL_CMD_CHSEL5 0x04000000
+#define TL_CMD_CHSEL4 0x02000000
+#define TL_CMD_CHSEL3 0x01000000
+#define TL_CMD_CHSEL2 0x00800000
+#define TL_CMD_CHSEL1 0x00400000
+#define TL_CMD_CHSEL0 0x00200000
+#define TL_CMD_EOC 0x00100000
+#define TL_CMD_RT 0x00080000
+#define TL_CMD_NES 0x00040000
+#define TL_CMD_ZERO0 0x00020000
+#define TL_CMD_ZERO1 0x00010000
+#define TL_CMD_ADRST 0x00008000
+#define TL_CMD_LDTMR 0x00004000
+#define TL_CMD_LDTHR 0x00002000
+#define TL_CMD_REQINT 0x00001000
+#define TL_CMD_INTSOFF 0x00000800
+#define TL_CMD_INTSON 0x00000400
+#define TL_CMD_RSVD0 0x00000200
+#define TL_CMD_RSVD1 0x00000100
+#define TL_CMD_ACK7 0x00000080
+#define TL_CMD_ACK6 0x00000040
+#define TL_CMD_ACK5 0x00000020
+#define TL_CMD_ACK4 0x00000010
+#define TL_CMD_ACK3 0x00000008
+#define TL_CMD_ACK2 0x00000004
+#define TL_CMD_ACK1 0x00000002
+#define TL_CMD_ACK0 0x00000001
+
+#define TL_CMD_CHSEL_MASK 0x01FE0000
+#define TL_CMD_ACK_MASK 0xFF
+
+/*
+ * EEPROM address where station address resides.
+ */
+#define TL_EEPROM_EADDR 0x83
+#define TL_EEPROM_EADDR2 0x99
+#define TL_EEPROM_EADDR3 0xAF
+#define TL_EEPROM_EADDR_OC 0xF8 /* Olicom cards use a different
+ address than Compaqs. */
+/*
+ * ThunderLAN host command register offsets.
+ * (Can be accessed either by IO ports or memory map.)
+ */
+#define TL_HOSTCMD 0x00
+#define TL_CH_PARM 0x04
+#define TL_DIO_ADDR 0x08
+#define TL_HOST_INT 0x0A
+#define TL_DIO_DATA 0x0C
+
+/*
+ * ThunderLAN internal registers
+ */
+#define TL_NETCMD 0x00
+#define TL_NETSIO 0x01
+#define TL_NETSTS 0x02
+#define TL_NETMASK 0x03
+
+#define TL_NETCONFIG 0x04
+#define TL_MANTEST 0x06
+
+#define TL_VENID_LSB 0x08
+#define TL_VENID_MSB 0x09
+#define TL_DEVID_LSB 0x0A
+#define TL_DEVID_MSB 0x0B
+
+#define TL_REVISION 0x0C
+#define TL_SUBCLASS 0x0D
+#define TL_MINLAT 0x0E
+#define TL_MAXLAT 0x0F
+
+#define TL_AREG0_B5 0x10
+#define TL_AREG0_B4 0x11
+#define TL_AREG0_B3 0x12
+#define TL_AREG0_B2 0x13
+
+#define TL_AREG0_B1 0x14
+#define TL_AREG0_B0 0x15
+#define TL_AREG1_B5 0x16
+#define TL_AREG1_B4 0x17
+
+#define TL_AREG1_B3 0x18
+#define TL_AREG1_B2 0x19
+#define TL_AREG1_B1 0x1A
+#define TL_AREG1_B0 0x1B
+
+#define TL_AREG2_B5 0x1C
+#define TL_AREG2_B4 0x1D
+#define TL_AREG2_B3 0x1E
+#define TL_AREG2_B2 0x1F
+
+#define TL_AREG2_B1 0x20
+#define TL_AREG2_B0 0x21
+#define TL_AREG3_B5 0x22
+#define TL_AREG3_B4 0x23
+
+#define TL_AREG3_B3 0x24
+#define TL_AREG3_B2 0x25
+#define TL_AREG3_B1 0x26
+#define TL_AREG3_B0 0x27
+
+#define TL_HASH1 0x28
+#define TL_HASH2 0x2C
+#define TL_TXGOODFRAMES 0x30
+#define TL_TXUNDERRUN 0x33
+#define TL_RXGOODFRAMES 0x34
+#define TL_RXOVERRUN 0x37
+#define TL_DEFEREDTX 0x38
+#define TL_CRCERROR 0x3A
+#define TL_CODEERROR 0x3B
+#define TL_MULTICOLTX 0x3C
+#define TL_SINGLECOLTX 0x3E
+#define TL_EXCESSIVECOL 0x40
+#define TL_LATECOL 0x41
+#define TL_CARRIERLOSS 0x42
+#define TL_ACOMMIT 0x43
+#define TL_LDREG 0x44
+#define TL_BSIZEREG 0x45
+#define TL_MAXRX 0x46
+
+/*
+ * ThunderLAN SIO register bits
+ */
+#define TL_SIO_MINTEN 0x80
+#define TL_SIO_ECLOK 0x40
+#define TL_SIO_ETXEN 0x20
+#define TL_SIO_EDATA 0x10
+#define TL_SIO_NMRST 0x08
+#define TL_SIO_MCLK 0x04
+#define TL_SIO_MTXEN 0x02
+#define TL_SIO_MDATA 0x01
+
+/*
+ * Thunderlan NETCONFIG bits
+ */
+#define TL_CFG_RCLKTEST 0x8000
+#define TL_CFG_TCLKTEST 0x4000
+#define TL_CFG_BITRATE 0x2000
+#define TL_CFG_RXCRC 0x1000
+#define TL_CFG_PEF 0x0800
+#define TL_CFG_ONEFRAG 0x0400
+#define TL_CFG_ONECHAN 0x0200
+#define TL_CFG_MTEST 0x0100
+#define TL_CFG_PHYEN 0x0080
+#define TL_CFG_MACSEL6 0x0040
+#define TL_CFG_MACSEL5 0x0020
+#define TL_CFG_MACSEL4 0x0010
+#define TL_CFG_MACSEL3 0x0008
+#define TL_CFG_MACSEL2 0x0004
+#define TL_CFG_MACSEL1 0x0002
+#define TL_CFG_MACSEL0 0x0001
+
+/*
+ * ThunderLAN NETSTS bits
+ */
+#define TL_STS_MIRQ 0x80
+#define TL_STS_HBEAT 0x40
+#define TL_STS_TXSTOP 0x20
+#define TL_STS_RXSTOP 0x10
+
+/*
+ * ThunderLAN NETCMD bits
+ */
+#define TL_CMD_NRESET 0x80
+#define TL_CMD_NWRAP 0x40
+#define TL_CMD_CSF 0x20
+#define TL_CMD_CAF 0x10
+#define TL_CMD_NOBRX 0x08
+#define TL_CMD_DUPLEX 0x04
+#define TL_CMD_TRFRAM 0x02
+#define TL_CMD_TXPACE 0x01
+
+/*
+ * ThunderLAN NETMASK bits
+ */
+#define TL_MASK_MASK7 0x80
+#define TL_MASK_MASK6 0x40
+#define TL_MASK_MASK5 0x20
+#define TL_MASK_MASK4 0x10
+
+/*
+ * MII frame format
+ */
+#ifdef ANSI_DOESNT_ALLOW_BITFIELDS
+struct tl_mii_frame {
+ u_int16_t mii_stdelim:2,
+ mii_opcode:2,
+ mii_phyaddr:5,
+ mii_regaddr:5,
+ mii_turnaround:2;
+ u_int16_t mii_data;
+};
+#else
+struct tl_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+#endif
+/*
+ * MII constants
+ */
+#define TL_MII_STARTDELIM 0x01
+#define TL_MII_READOP 0x02
+#define TL_MII_WRITEOP 0x01
+#define TL_MII_TURNAROUND 0x02
+
+#define TL_LAST_FRAG 0x80000000
+#define TL_CSTAT_UNUSED 0x8000
+#define TL_CSTAT_FRAMECMP 0x4000
+#define TL_CSTAT_READY 0x3000
+#define TL_CSTAT_UNUSED13 0x2000
+#define TL_CSTAT_UNUSED12 0x1000
+#define TL_CSTAT_EOC 0x0800
+#define TL_CSTAT_RXERROR 0x0400
+#define TL_CSTAT_PASSCRC 0x0200
+#define TL_CSTAT_DPRIO 0x0100
+
+#define TL_FRAME_MASK 0x00FFFFFF
+#define tl_tx_goodframes(x) (x.tl_txstat & TL_FRAME_MASK)
+#define tl_tx_underrun(x) ((x.tl_txstat & ~TL_FRAME_MASK) >> 24)
+#define tl_rx_goodframes(x) (x.tl_rxstat & TL_FRAME_MASK)
+#define tl_rx_overrun(x) ((x.tl_rxstat & ~TL_FRAME_MASK) >> 24)
+
+struct tl_stats {
+ u_int32_t tl_txstat;
+ u_int32_t tl_rxstat;
+ u_int16_t tl_deferred;
+ u_int8_t tl_crc_errors;
+ u_int8_t tl_code_errors;
+ u_int16_t tl_tx_multi_collision;
+ u_int16_t tl_tx_single_collision;
+ u_int8_t tl_excessive_collision;
+ u_int8_t tl_late_collision;
+ u_int8_t tl_carrier_loss;
+ u_int8_t acommit;
+};
+
+/*
+ * ACOMMIT register bits. These are used only when a bitrate
+ * PHY is selected ('bitrate' bit in netconfig register is set).
+ */
+#define TL_AC_MTXER 0x01 /* reserved */
+#define TL_AC_MTXD1 0x02 /* 0 == 10baseT 1 == AUI */
+#define TL_AC_MTXD2 0x04 /* loopback disable */
+#define TL_AC_MTXD3 0x08 /* full duplex disable */
+
+#define TL_AC_TXTHRESH 0xF0
+#define TL_AC_TXTHRESH_16LONG 0x00
+#define TL_AC_TXTHRESH_32LONG 0x10
+#define TL_AC_TXTHRESH_64LONG 0x20
+#define TL_AC_TXTHRESH_128LONG 0x30
+#define TL_AC_TXTHRESH_256LONG 0x40
+#define TL_AC_TXTHRESH_WHOLEPKT 0x50
+
+/*
+ * PCI burst size register (TL_BSIZEREG).
+ */
+#define TL_RXBURST 0x0F
+#define TL_TXBURST 0xF0
+
+#define TL_RXBURST_4LONG 0x00
+#define TL_RXBURST_8LONG 0x01
+#define TL_RXBURST_16LONG 0x02
+#define TL_RXBURST_32LONG 0x03
+#define TL_RXBURST_64LONG 0x04
+#define TL_RXBURST_128LONG 0x05
+
+#define TL_TXBURST_4LONG 0x00
+#define TL_TXBURST_8LONG 0x10
+#define TL_TXBURST_16LONG 0x20
+#define TL_TXBURST_32LONG 0x30
+#define TL_TXBURST_64LONG 0x40
+#define TL_TXBURST_128LONG 0x50
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->tl_btag, sc->tl_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->tl_btag, sc->tl_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->tl_btag, sc->tl_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->tl_btag, sc->tl_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->tl_btag, sc->tl_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->tl_btag, sc->tl_bhandle, reg)
+
+#define CMD_PUT(sc, x) CSR_WRITE_4(sc, TL_HOSTCMD, x)
+#define CMD_SET(sc, x) \
+ CSR_WRITE_4(sc, TL_HOSTCMD, CSR_READ_4(sc, TL_HOSTCMD) | (x))
+#define CMD_CLR(sc, x) \
+ CSR_WRITE_4(sc, TL_HOSTCMD, CSR_READ_4(sc, TL_HOSTCMD) & ~(x))
+
+/*
+ * ThunderLAN adapters typically have a serial EEPROM containing
+ * configuration information. The main reason we're interested in
+ * it is because it also contains the adapters's station address.
+ *
+ * Access to the EEPROM is a bit goofy since it is a serial device:
+ * you have to do reads and writes one bit at a time. The state of
+ * the DATA bit can only change while the CLOCK line is held low.
+ * Transactions work basically like this:
+ *
+ * 1) Send the EEPROM_START sequence to prepare the EEPROM for
+ * accepting commands. This pulls the clock high, sets
+ * the data bit to 0, enables transmission to the EEPROM,
+ * pulls the data bit up to 1, then pulls the clock low.
+ * The idea is to do a 0 to 1 transition of the data bit
+ * while the clock pin is held high.
+ *
+ * 2) To write a bit to the EEPROM, set the TXENABLE bit, then
+ * set the EDATA bit to send a 1 or clear it to send a 0.
+ * Finally, set and then clear ECLOK. Strobing the clock
+ * transmits the bit. After 8 bits have been written, the
+ * EEPROM should respond with an ACK, which should be read.
+ *
+ * 3) To read a bit from the EEPROM, clear the TXENABLE bit,
+ * then set ECLOK. The bit can then be read by reading EDATA.
+ * ECLOCK should then be cleared again. This can be repeated
+ * 8 times to read a whole byte, after which the
+ *
+ * 4) We need to send the address byte to the EEPROM. For this
+ * we have to send the write control byte to the EEPROM to
+ * tell it to accept data. The byte is 0xA0. The EEPROM should
+ * ack this. The address byte can be send after that.
+ *
+ * 5) Now we have to tell the EEPROM to send us data. For that we
+ * have to transmit the read control byte, which is 0xA1. This
+ * byte should also be acked. We can then read the data bits
+ * from the EEPROM.
+ *
+ * 6) When we're all finished, send the EEPROM_STOP sequence.
+ *
+ * Note that we use the ThunderLAN's NetSio register to access the
+ * EEPROM, however there is an alternate method. There is a PCI NVRAM
+ * register at PCI offset 0xB4 which can also be used with minor changes.
+ * The difference is that access to PCI registers via pci_conf_read()
+ * and pci_conf_write() is done using programmed I/O, which we want to
+ * avoid.
+ */
+
+/*
+ * Note that EEPROM_START leaves transmission enabled.
+ */
+#define EEPROM_START \
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK); /* Pull clock pin high */\
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_EDATA); /* Set DATA bit to 1 */ \
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ETXEN); /* Enable xmit to write bit */\
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_EDATA); /* Pull DATA bit to 0 again */\
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); /* Pull clock low again */
+
+/*
+ * EEPROM_STOP ends access to the EEPROM and clears the ETXEN bit so
+ * that no further data can be written to the EEPROM I/O pin.
+ */
+#define EEPROM_STOP \
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN); /* Disable xmit */ \
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_EDATA); /* Pull DATA to 0 */ \
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK); /* Pull clock high */ \
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ETXEN); /* Enable xmit */ \
+ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_EDATA); /* Toggle DATA to 1 */ \
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN); /* Disable xmit. */ \
+ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); /* Pull clock low again */
+
+
+/*
+ * Microchip Technology 24Cxx EEPROM control bytes
+ */
+#define EEPROM_CTL_READ 0xA1 /* 0101 0001 */
+#define EEPROM_CTL_WRITE 0xA0 /* 0101 0000 */
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_vr.c b/sys/pci/if_vr.c
new file mode 100644
index 0000000..1f4a07e
--- /dev/null
+++ b/sys/pci/if_vr.c
@@ -0,0 +1,1650 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * VIA Rhine fast ethernet PCI NIC driver
+ *
+ * Supports various network adapters based on the VIA Rhine
+ * and Rhine II PCI controllers, including the D-Link DFE530TX.
+ * Datasheets are available at http://www.via.com.tw.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The VIA Rhine controllers are similar in some respects to the
+ * the DEC tulip chips, except less complicated. The controller
+ * uses an MII bus and an external physical layer interface. The
+ * receiver has a one entry perfect filter and a 64-bit hash table
+ * multicast filter. Transmit and receive descriptors are similar
+ * to the tulip.
+ *
+ * The Rhine has a serious flaw in its transmit DMA mechanism:
+ * transmit buffers must be longword aligned. Unfortunately,
+ * FreeBSD doesn't guarantee that mbufs will be filled in starting
+ * at longword boundaries, so we have to do a buffer copy before
+ * transmission.
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define VR_USEIOSPACE
+
+#include <pci/if_vrreg.h>
+
+MODULE_DEPEND(vr, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct vr_type vr_devs[] = {
+ { VIA_VENDORID, VIA_DEVICEID_RHINE,
+ "VIA VT3043 Rhine I 10/100BaseTX" },
+ { VIA_VENDORID, VIA_DEVICEID_RHINE_II,
+ "VIA VT86C100A Rhine II 10/100BaseTX" },
+ { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
+ "VIA VT6102 Rhine II 10/100BaseTX" },
+ { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
+ "Delta Electronics Rhine II 10/100BaseTX" },
+ { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
+ "Addtron Technology Rhine II 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int vr_probe (device_t);
+static int vr_attach (device_t);
+static int vr_detach (device_t);
+
+static int vr_newbuf (struct vr_softc *,
+ struct vr_chain_onefrag *,
+ struct mbuf *);
+static int vr_encap (struct vr_softc *, struct vr_chain *,
+ struct mbuf * );
+
+static void vr_rxeof (struct vr_softc *);
+static void vr_rxeoc (struct vr_softc *);
+static void vr_txeof (struct vr_softc *);
+static void vr_txeoc (struct vr_softc *);
+static void vr_tick (void *);
+static void vr_intr (void *);
+static void vr_start (struct ifnet *);
+static int vr_ioctl (struct ifnet *, u_long, caddr_t);
+static void vr_init (void *);
+static void vr_stop (struct vr_softc *);
+static void vr_watchdog (struct ifnet *);
+static void vr_shutdown (device_t);
+static int vr_ifmedia_upd (struct ifnet *);
+static void vr_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void vr_mii_sync (struct vr_softc *);
+static void vr_mii_send (struct vr_softc *, u_int32_t, int);
+static int vr_mii_readreg (struct vr_softc *, struct vr_mii_frame *);
+static int vr_mii_writereg (struct vr_softc *, struct vr_mii_frame *);
+static int vr_miibus_readreg (device_t, int, int);
+static int vr_miibus_writereg (device_t, int, int, int);
+static void vr_miibus_statchg (device_t);
+
+static void vr_setcfg (struct vr_softc *, int);
+static u_int8_t vr_calchash (u_int8_t *);
+static void vr_setmulti (struct vr_softc *);
+static void vr_reset (struct vr_softc *);
+static int vr_list_rx_init (struct vr_softc *);
+static int vr_list_tx_init (struct vr_softc *);
+
+#ifdef VR_USEIOSPACE
+#define VR_RES SYS_RES_IOPORT
+#define VR_RID VR_PCI_LOIO
+#else
+#define VR_RES SYS_RES_MEMORY
+#define VR_RID VR_PCI_LOMEM
+#endif
+
+static device_method_t vr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, vr_probe),
+ DEVMETHOD(device_attach, vr_attach),
+ DEVMETHOD(device_detach, vr_detach),
+ DEVMETHOD(device_shutdown, vr_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, vr_miibus_readreg),
+ DEVMETHOD(miibus_writereg, vr_miibus_writereg),
+ DEVMETHOD(miibus_statchg, vr_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t vr_driver = {
+ "vr",
+ vr_methods,
+ sizeof(struct vr_softc)
+};
+
+static devclass_t vr_devclass;
+
+DRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0);
+DRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
+
+#define VR_SETBIT(sc, reg, x) \
+ CSR_WRITE_1(sc, reg, \
+ CSR_READ_1(sc, reg) | x)
+
+#define VR_CLRBIT(sc, reg, x) \
+ CSR_WRITE_1(sc, reg, \
+ CSR_READ_1(sc, reg) & ~x)
+
+#define VR_SETBIT16(sc, reg, x) \
+ CSR_WRITE_2(sc, reg, \
+ CSR_READ_2(sc, reg) | x)
+
+#define VR_CLRBIT16(sc, reg, x) \
+ CSR_WRITE_2(sc, reg, \
+ CSR_READ_2(sc, reg) & ~x)
+
+#define VR_SETBIT32(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define VR_CLRBIT32(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+#define SIO_SET(x) \
+ CSR_WRITE_1(sc, VR_MIICMD, \
+ CSR_READ_1(sc, VR_MIICMD) | x)
+
+#define SIO_CLR(x) \
+ CSR_WRITE_1(sc, VR_MIICMD, \
+ CSR_READ_1(sc, VR_MIICMD) & ~x)
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void vr_mii_sync(sc)
+ struct vr_softc *sc;
+{
+ register int i;
+
+ SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
+
+ for (i = 0; i < 32; i++) {
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void vr_mii_send(sc, bits, cnt)
+ struct vr_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ SIO_CLR(VR_MIICMD_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ SIO_SET(VR_MIICMD_DATAIN);
+ } else {
+ SIO_CLR(VR_MIICMD_DATAIN);
+ }
+ DELAY(1);
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_SET(VR_MIICMD_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int vr_mii_readreg(sc, frame)
+ struct vr_softc *sc;
+ struct vr_mii_frame *frame;
+
+{
+ int i, ack;
+
+ VR_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = VR_MII_STARTDELIM;
+ frame->mii_opcode = VR_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ CSR_WRITE_1(sc, VR_MIICMD, 0);
+ VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
+
+ /*
+ * Turn on data xmit.
+ */
+ SIO_SET(VR_MIICMD_DIR);
+
+ vr_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ vr_mii_send(sc, frame->mii_stdelim, 2);
+ vr_mii_send(sc, frame->mii_opcode, 2);
+ vr_mii_send(sc, frame->mii_phyaddr, 5);
+ vr_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
+ DELAY(1);
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ SIO_CLR(VR_MIICMD_DIR);
+
+ /* Check for ack */
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+ ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+
+ VR_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int vr_mii_writereg(sc, frame)
+ struct vr_softc *sc;
+ struct vr_mii_frame *frame;
+
+{
+ VR_LOCK(sc);
+
+ CSR_WRITE_1(sc, VR_MIICMD, 0);
+ VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = VR_MII_STARTDELIM;
+ frame->mii_opcode = VR_MII_WRITEOP;
+ frame->mii_turnaround = VR_MII_TURNAROUND;
+
+ /*
+ * Turn on data output.
+ */
+ SIO_SET(VR_MIICMD_DIR);
+
+ vr_mii_sync(sc);
+
+ vr_mii_send(sc, frame->mii_stdelim, 2);
+ vr_mii_send(sc, frame->mii_opcode, 2);
+ vr_mii_send(sc, frame->mii_phyaddr, 5);
+ vr_mii_send(sc, frame->mii_regaddr, 5);
+ vr_mii_send(sc, frame->mii_turnaround, 2);
+ vr_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ SIO_SET(VR_MIICMD_CLK);
+ DELAY(1);
+ SIO_CLR(VR_MIICMD_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ SIO_CLR(VR_MIICMD_DIR);
+
+ VR_UNLOCK(sc);
+
+ return(0);
+}
+
+static int vr_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct vr_softc *sc;
+ struct vr_mii_frame frame;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ vr_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int vr_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ u_int16_t phy, reg, data;
+{
+ struct vr_softc *sc;
+ struct vr_mii_frame frame;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ vr_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+static void vr_miibus_statchg(dev)
+ device_t dev;
+{
+ struct vr_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ VR_LOCK(sc);
+ mii = device_get_softc(sc->vr_miibus);
+ vr_setcfg(sc, mii->mii_media_active);
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Calculate CRC of a multicast group address, return the lower 6 bits.
+ */
+static u_int8_t vr_calchash(addr)
+ u_int8_t *addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return((crc >> 26) & 0x0000003F);
+}
+
+/*
+ * Program the 64-bit multicast hash filter.
+ */
+static void vr_setmulti(sc)
+ struct vr_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+ u_int8_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ rxfilt = CSR_READ_1(sc, VR_RXCFG);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= VR_RXCFG_RX_MULTI;
+ CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
+ CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
+ CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, VR_MAR0, 0);
+ CSR_WRITE_4(sc, VR_MAR1, 0);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ mcnt++;
+ }
+
+ if (mcnt)
+ rxfilt |= VR_RXCFG_RX_MULTI;
+ else
+ rxfilt &= ~VR_RXCFG_RX_MULTI;
+
+ CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
+ CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
+
+ return;
+}
+
+/*
+ * In order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void vr_setcfg(sc, media)
+ struct vr_softc *sc;
+ int media;
+{
+ int restart = 0;
+
+ if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
+ restart = 1;
+ VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX)
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
+ else
+ VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
+
+ if (restart)
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
+
+ return;
+}
+
+static void vr_reset(sc)
+ struct vr_softc *sc;
+{
+ register int i;
+
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
+
+ for (i = 0; i < VR_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
+ break;
+ }
+ if (i == VR_TIMEOUT)
+ printf("vr%d: reset never completed!\n", sc->vr_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ return;
+}
+
+/*
+ * Probe for a VIA Rhine chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int vr_probe(dev)
+ device_t dev;
+{
+ struct vr_type *t;
+
+ t = vr_devs;
+
+ while(t->vr_name != NULL) {
+ if ((pci_get_vendor(dev) == t->vr_vid) &&
+ (pci_get_device(dev) == t->vr_did)) {
+ device_set_desc(dev, t->vr_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int vr_attach(dev)
+ device_t dev;
+{
+ int i;
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct vr_softc *sc;
+ struct ifnet *ifp;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct vr_softc *));
+
+ mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ VR_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
+ membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("vr%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef VR_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("vr%d: failed to enable I/O ports!\n", unit);
+ free(sc, M_DEVBUF);
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("vr%d: failed to enable memory mapping!\n", unit);
+ goto fail;
+ }
+#endif
+
+ rid = VR_RID;
+ sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->vr_res == NULL) {
+ printf("vr%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->vr_btag = rman_get_bustag(sc->vr_res);
+ sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->vr_irq == NULL) {
+ printf("vr%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
+ vr_intr, sc, &sc->vr_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
+ bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
+ printf("vr%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /*
+ * Windows may put the chip in suspend mode when it
+ * shuts down. Be sure to kick it in the head to wake it
+ * up again.
+ */
+ VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
+
+ /* Reset the adapter. */
+ vr_reset(sc);
+
+ /*
+ * Get station address. The way the Rhine chips work,
+ * you're not allowed to directly access the EEPROM once
+ * they've been programmed a special way. Consequently,
+ * we need to read the node address from the PAR0 and PAR1
+ * registers.
+ */
+ VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
+ DELAY(200);
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
+
+ /*
+ * A Rhine chip was detected. Inform the world.
+ */
+ printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->vr_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->vr_ldata == NULL) {
+ printf("vr%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
+ bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->vr_ldata, sizeof(struct vr_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "vr";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = vr_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = vr_start;
+ ifp->if_watchdog = vr_watchdog;
+ ifp->if_init = vr_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ if (mii_phy_probe(dev, &sc->vr_miibus,
+ vr_ifmedia_upd, vr_ifmedia_sts)) {
+ printf("vr%d: MII without any phy!\n", sc->vr_unit);
+ bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
+ bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
+ contigfree(sc->vr_ldata,
+ sizeof(struct vr_list_data), M_DEVBUF);
+ error = ENXIO;
+ goto fail;
+ }
+
+ callout_handle_init(&sc->vr_stat_ch);
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ VR_UNLOCK(sc);
+ return(0);
+
+fail:
+ VR_UNLOCK(sc);
+ mtx_destroy(&sc->vr_mtx);
+
+ return(error);
+}
+
+static int vr_detach(dev)
+ device_t dev;
+{
+ struct vr_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ VR_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ vr_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->vr_miibus);
+
+ bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
+ bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
+
+ contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
+
+ VR_UNLOCK(sc);
+ mtx_destroy(&sc->vr_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int vr_list_tx_init(sc)
+ struct vr_softc *sc;
+{
+ struct vr_chain_data *cd;
+ struct vr_list_data *ld;
+ int i;
+
+ cd = &sc->vr_cdata;
+ ld = sc->vr_ldata;
+ for (i = 0; i < VR_TX_LIST_CNT; i++) {
+ cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
+ if (i == (VR_TX_LIST_CNT - 1))
+ cd->vr_tx_chain[i].vr_nextdesc =
+ &cd->vr_tx_chain[0];
+ else
+ cd->vr_tx_chain[i].vr_nextdesc =
+ &cd->vr_tx_chain[i + 1];
+ }
+
+ cd->vr_tx_free = &cd->vr_tx_chain[0];
+ cd->vr_tx_tail = cd->vr_tx_head = NULL;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int vr_list_rx_init(sc)
+ struct vr_softc *sc;
+{
+ struct vr_chain_data *cd;
+ struct vr_list_data *ld;
+ int i;
+
+ cd = &sc->vr_cdata;
+ ld = sc->vr_ldata;
+
+ for (i = 0; i < VR_RX_LIST_CNT; i++) {
+ cd->vr_rx_chain[i].vr_ptr =
+ (struct vr_desc *)&ld->vr_rx_list[i];
+ if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (VR_RX_LIST_CNT - 1)) {
+ cd->vr_rx_chain[i].vr_nextdesc =
+ &cd->vr_rx_chain[0];
+ ld->vr_rx_list[i].vr_next =
+ vtophys(&ld->vr_rx_list[0]);
+ } else {
+ cd->vr_rx_chain[i].vr_nextdesc =
+ &cd->vr_rx_chain[i + 1];
+ ld->vr_rx_list[i].vr_next =
+ vtophys(&ld->vr_rx_list[i + 1]);
+ }
+ }
+
+ cd->vr_rx_head = &cd->vr_rx_chain[0];
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ * Note: the length fields are only 11 bits wide, which means the
+ * largest size we can specify is 2047. This is important because
+ * MCLBYTES is 2048, so we have to subtract one otherwise we'll
+ * overflow the field and make a mess.
+ */
+static int vr_newbuf(sc, c, m)
+ struct vr_softc *sc;
+ struct vr_chain_onefrag *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ c->vr_mbuf = m_new;
+ c->vr_ptr->vr_status = VR_RXSTAT;
+ c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
+ c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
+
+ return(0);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void vr_rxeof(sc)
+ struct vr_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct vr_chain_onefrag *cur_rx;
+ int total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+ while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
+ VR_RXSTAT_OWN)) {
+ struct mbuf *m0 = NULL;
+
+ cur_rx = sc->vr_cdata.vr_rx_head;
+ sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
+ m = cur_rx->vr_mbuf;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & VR_RXSTAT_RXERR) {
+ ifp->if_ierrors++;
+ printf("vr%d: rx error: ", sc->vr_unit);
+ switch(rxstat & 0x000000FF) {
+ case VR_RXSTAT_CRCERR:
+ printf("crc error\n");
+ break;
+ case VR_RXSTAT_FRAMEALIGNERR:
+ printf("frame alignment error\n");
+ break;
+ case VR_RXSTAT_FIFOOFLOW:
+ printf("FIFO overflow\n");
+ break;
+ case VR_RXSTAT_GIANT:
+ printf("received giant packet\n");
+ break;
+ case VR_RXSTAT_RUNT:
+ printf("received runt packet\n");
+ break;
+ case VR_RXSTAT_BUSERR:
+ printf("system bus error\n");
+ break;
+ case VR_RXSTAT_BUFFERR:
+ printf("rx buffer error\n");
+ break;
+ default:
+ printf("unknown rx error\n");
+ break;
+ }
+ vr_newbuf(sc, cur_rx, m);
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+ total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
+
+ /*
+ * XXX The VIA Rhine chip includes the CRC with every
+ * received frame, and there's no way to turn this
+ * behavior off (at least, I can't find anything in
+ * the manual that explains how to do it) so we have
+ * to trim off the CRC manually.
+ */
+ total_len -= ETHER_CRC_LEN;
+
+ m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
+ NULL);
+ vr_newbuf(sc, cur_rx, m);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ return;
+}
+
+void vr_rxeoc(sc)
+ struct vr_softc *sc;
+{
+
+ vr_rxeof(sc);
+ VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
+ CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void vr_txeof(sc)
+ struct vr_softc *sc;
+{
+ struct vr_chain *cur_tx;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Reset the timeout timer; if_txeoc will clear it. */
+ ifp->if_timer = 5;
+
+ /* Sanity check. */
+ if (sc->vr_cdata.vr_tx_head == NULL)
+ return;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
+ u_int32_t txstat;
+
+ cur_tx = sc->vr_cdata.vr_tx_head;
+ txstat = cur_tx->vr_ptr->vr_status;
+
+ if (txstat & VR_TXSTAT_OWN)
+ break;
+
+ if (txstat & VR_TXSTAT_ERRSUM) {
+ ifp->if_oerrors++;
+ if (txstat & VR_TXSTAT_DEFER)
+ ifp->if_collisions++;
+ if (txstat & VR_TXSTAT_LATECOLL)
+ ifp->if_collisions++;
+ }
+
+ ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
+
+ ifp->if_opackets++;
+ if (cur_tx->vr_mbuf != NULL) {
+ m_freem(cur_tx->vr_mbuf);
+ cur_tx->vr_mbuf = NULL;
+ }
+
+ if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
+ sc->vr_cdata.vr_tx_head = NULL;
+ sc->vr_cdata.vr_tx_tail = NULL;
+ break;
+ }
+
+ sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
+ }
+
+ return;
+}
+
+/*
+ * TX 'end of channel' interrupt handler.
+ */
+static void vr_txeoc(sc)
+ struct vr_softc *sc;
+{
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (sc->vr_cdata.vr_tx_head == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->vr_cdata.vr_tx_tail = NULL;
+ ifp->if_timer = 0;
+ }
+
+ return;
+}
+
+static void vr_tick(xsc)
+ void *xsc;
+{
+ struct vr_softc *sc;
+ struct mii_data *mii;
+
+ sc = xsc;
+ VR_LOCK(sc);
+ mii = device_get_softc(sc->vr_miibus);
+ mii_tick(mii);
+
+ sc->vr_stat_ch = timeout(vr_tick, sc, hz);
+
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+static void vr_intr(arg)
+ void *arg;
+{
+ struct vr_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t status;
+
+ sc = arg;
+ VR_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ /* Supress unwanted interrupts. */
+ if (!(ifp->if_flags & IFF_UP)) {
+ vr_stop(sc);
+ VR_UNLOCK(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_2(sc, VR_IMR, 0x0000);
+
+ for (;;) {
+
+ status = CSR_READ_2(sc, VR_ISR);
+ if (status)
+ CSR_WRITE_2(sc, VR_ISR, status);
+
+ if ((status & VR_INTRS) == 0)
+ break;
+
+ if (status & VR_ISR_RX_OK)
+ vr_rxeof(sc);
+
+ if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
+ (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||
+ (status & VR_ISR_RX_DROPPED)) {
+ vr_rxeof(sc);
+ vr_rxeoc(sc);
+ }
+
+ if (status & VR_ISR_TX_OK) {
+ vr_txeof(sc);
+ vr_txeoc(sc);
+ }
+
+ if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){
+ ifp->if_oerrors++;
+ vr_txeof(sc);
+ if (sc->vr_cdata.vr_tx_head != NULL) {
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
+ }
+ }
+
+ if (status & VR_ISR_BUSERR) {
+ vr_reset(sc);
+ vr_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL) {
+ vr_start(ifp);
+ }
+
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int vr_encap(sc, c, m_head)
+ struct vr_softc *sc;
+ struct vr_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct vr_desc *f = NULL;
+ int total_len;
+ struct mbuf *m;
+
+ m = m_head;
+ total_len = 0;
+
+ /*
+ * The VIA Rhine wants packet buffers to be longword
+ * aligned, but very often our mbufs aren't. Rather than
+ * waste time trying to decide when to copy and when not
+ * to copy, just do it all the time.
+ */
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("vr%d: no memory for tx list\n", sc->vr_unit);
+ return(1);
+ }
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ printf("vr%d: no memory for tx list\n",
+ sc->vr_unit);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ /*
+ * The Rhine chip doesn't auto-pad, so we have to make
+ * sure to pad short frames out to the minimum frame length
+ * ourselves.
+ */
+ if (m_head->m_len < VR_MIN_FRAMELEN) {
+ m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
+ m_new->m_len = m_new->m_pkthdr.len;
+ }
+ f = c->vr_ptr;
+ f->vr_data = vtophys(mtod(m_new, caddr_t));
+ f->vr_ctl = total_len = m_new->m_len;
+ f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
+ f->vr_status = 0;
+ frag = 1;
+ }
+
+ c->vr_mbuf = m_head;
+ c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
+ c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void vr_start(ifp)
+ struct ifnet *ifp;
+{
+ struct vr_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct vr_chain *cur_tx = NULL, *start_tx;
+
+ sc = ifp->if_softc;
+
+ VR_LOCK(sc);
+ if (ifp->if_flags & IFF_OACTIVE) {
+ VR_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Check for an available queue slot. If there are none,
+ * punt.
+ */
+ if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ start_tx = sc->vr_cdata.vr_tx_free;
+
+ while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /* Pick a descriptor off the free list. */
+ cur_tx = sc->vr_cdata.vr_tx_free;
+ sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
+
+ /* Pack the data into the descriptor. */
+ if (vr_encap(sc, cur_tx, m_head)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ cur_tx = NULL;
+ break;
+ }
+
+ if (cur_tx != start_tx)
+ VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->vr_mbuf);
+
+ VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
+ VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
+ }
+
+ /*
+ * If there are no frames queued, bail.
+ */
+ if (cur_tx == NULL) {
+ VR_UNLOCK(sc);
+ return;
+ }
+
+ sc->vr_cdata.vr_tx_tail = cur_tx;
+
+ if (sc->vr_cdata.vr_tx_head == NULL)
+ sc->vr_cdata.vr_tx_head = start_tx;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+static void vr_init(xsc)
+ void *xsc;
+{
+ struct vr_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+ int i;
+
+ VR_LOCK(sc);
+
+ mii = device_get_softc(sc->vr_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ vr_stop(sc);
+ vr_reset(sc);
+
+ /*
+ * Set our station address.
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+
+ VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
+ VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD);
+
+ VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
+ VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
+
+ /* Init circular RX list. */
+ if (vr_list_rx_init(sc) == ENOBUFS) {
+ printf("vr%d: initialization failed: no "
+ "memory for rx buffers\n", sc->vr_unit);
+ vr_stop(sc);
+ VR_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ vr_list_tx_init(sc);
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
+ else
+ VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
+
+ /* Set capture broadcast bit to capture broadcast frames. */
+ if (ifp->if_flags & IFF_BROADCAST)
+ VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
+ else
+ VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
+
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ vr_setmulti(sc);
+
+ /*
+ * Load the address of the RX list.
+ */
+ CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
+
+ /* Enable receiver and transmitter. */
+ CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
+ VR_CMD_TX_ON|VR_CMD_RX_ON|
+ VR_CMD_RX_GO);
+
+ CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
+ CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
+
+ mii_mediachg(mii);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->vr_stat_ch = timeout(vr_tick, sc, hz);
+
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int vr_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct vr_softc *sc;
+
+ sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_UP)
+ vr_init(sc);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void vr_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct vr_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->vr_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int vr_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct vr_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ VR_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ vr_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ vr_stop(sc);
+ }
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ vr_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->vr_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ VR_UNLOCK(sc);
+
+ return(error);
+}
+
+static void vr_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct vr_softc *sc;
+
+ sc = ifp->if_softc;
+
+ VR_LOCK(sc);
+ ifp->if_oerrors++;
+ printf("vr%d: watchdog timeout\n", sc->vr_unit);
+
+ vr_stop(sc);
+ vr_reset(sc);
+ vr_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ vr_start(ifp);
+
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void vr_stop(sc)
+ struct vr_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ VR_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(vr_tick, sc, sc->vr_stat_ch);
+
+ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
+ VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
+ CSR_WRITE_2(sc, VR_IMR, 0x0000);
+ CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
+ CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < VR_RX_LIST_CNT; i++) {
+ if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
+ m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
+ sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->vr_ldata->vr_rx_list,
+ sizeof(sc->vr_ldata->vr_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < VR_TX_LIST_CNT; i++) {
+ if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
+ m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
+ sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
+ }
+ }
+
+ bzero((char *)&sc->vr_ldata->vr_tx_list,
+ sizeof(sc->vr_ldata->vr_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ VR_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void vr_shutdown(dev)
+ device_t dev;
+{
+ struct vr_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ vr_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_vrreg.h b/sys/pci/if_vrreg.h
new file mode 100644
index 0000000..c84f5c2
--- /dev/null
+++ b/sys/pci/if_vrreg.h
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Rhine register definitions.
+ */
+
+#define VR_PAR0 0x00 /* node address 0 to 4 */
+#define VR_PAR1 0x04 /* node address 2 to 6 */
+#define VR_RXCFG 0x06 /* receiver config register */
+#define VR_TXCFG 0x07 /* transmit config register */
+#define VR_COMMAND 0x08 /* command register */
+#define VR_ISR 0x0C /* interrupt/status register */
+#define VR_IMR 0x0E /* interrupt mask register */
+#define VR_MAR0 0x10 /* multicast hash 0 */
+#define VR_MAR1 0x14 /* multicast hash 1 */
+#define VR_RXADDR 0x18 /* rx descriptor list start addr */
+#define VR_TXADDR 0x1C /* tx descriptor list start addr */
+#define VR_CURRXDESC0 0x20
+#define VR_CURRXDESC1 0x24
+#define VR_CURRXDESC2 0x28
+#define VR_CURRXDESC3 0x2C
+#define VR_NEXTRXDESC0 0x30
+#define VR_NEXTRXDESC1 0x34
+#define VR_NEXTRXDESC2 0x38
+#define VR_NEXTRXDESC3 0x3C
+#define VR_CURTXDESC0 0x40
+#define VR_CURTXDESC1 0x44
+#define VR_CURTXDESC2 0x48
+#define VR_CURTXDESC3 0x4C
+#define VR_NEXTTXDESC0 0x50
+#define VR_NEXTTXDESC1 0x54
+#define VR_NEXTTXDESC2 0x58
+#define VR_NEXTTXDESC3 0x5C
+#define VR_CURRXDMA 0x60 /* current RX DMA address */
+#define VR_CURTXDMA 0x64 /* current TX DMA address */
+#define VR_TALLYCNT 0x68 /* tally counter test register */
+#define VR_PHYADDR 0x6C
+#define VR_MIISTAT 0x6D
+#define VR_BCR0 0x6E
+#define VR_BCR1 0x6F
+#define VR_MIICMD 0x70
+#define VR_MIIADDR 0x71
+#define VR_MIIDATA 0x72
+#define VR_EECSR 0x74
+#define VR_TEST 0x75
+#define VR_GPIO 0x76
+#define VR_CONFIG 0x78
+#define VR_MPA_CNT 0x7C
+#define VR_CRC_CNT 0x7E
+#define VR_STICKHW 0x83
+
+/*
+ * RX config bits.
+ */
+#define VR_RXCFG_RX_ERRPKTS 0x01
+#define VR_RXCFG_RX_RUNT 0x02
+#define VR_RXCFG_RX_MULTI 0x04
+#define VR_RXCFG_RX_BROAD 0x08
+#define VR_RXCFG_RX_PROMISC 0x10
+#define VR_RXCFG_RX_THRESH 0xE0
+
+#define VR_RXTHRESH_32BYTES 0x00
+#define VR_RXTHRESH_64BYTES 0x20
+#define VR_RXTHRESH_128BYTES 0x40
+#define VR_RXTHRESH_256BYTES 0x60
+#define VR_RXTHRESH_512BYTES 0x80
+#define VR_RXTHRESH_768BYTES 0xA0
+#define VR_RXTHRESH_1024BYTES 0xC0
+#define VR_RXTHRESH_STORENFWD 0xE0
+
+/*
+ * TX config bits.
+ */
+#define VR_TXCFG_RSVD0 0x01
+#define VR_TXCFG_LOOPBKMODE 0x06
+#define VR_TXCFG_BACKOFF 0x08
+#define VR_TXCFG_RSVD1 0x10
+#define VR_TXCFG_TX_THRESH 0xE0
+
+#define VR_TXTHRESH_32BYTES 0x00
+#define VR_TXTHRESH_64BYTES 0x20
+#define VR_TXTHRESH_128BYTES 0x40
+#define VR_TXTHRESH_256BYTES 0x60
+#define VR_TXTHRESH_512BYTES 0x80
+#define VR_TXTHRESH_768BYTES 0xA0
+#define VR_TXTHRESH_1024BYTES 0xC0
+#define VR_TXTHRESH_STORENFWD 0xE0
+
+/*
+ * Command register bits.
+ */
+#define VR_CMD_INIT 0x0001
+#define VR_CMD_START 0x0002
+#define VR_CMD_STOP 0x0004
+#define VR_CMD_RX_ON 0x0008
+#define VR_CMD_TX_ON 0x0010
+#define VR_CMD_TX_GO 0x0020
+#define VR_CMD_RX_GO 0x0040
+#define VR_CMD_RSVD 0x0080
+#define VR_CMD_RX_EARLY 0x0100
+#define VR_CMD_TX_EARLY 0x0200
+#define VR_CMD_FULLDUPLEX 0x0400
+#define VR_CMD_TX_NOPOLL 0x0800
+
+#define VR_CMD_RESET 0x8000
+
+/*
+ * Interrupt status bits.
+ */
+#define VR_ISR_RX_OK 0x0001 /* packet rx ok */
+#define VR_ISR_TX_OK 0x0002 /* packet tx ok */
+#define VR_ISR_RX_ERR 0x0004 /* packet rx with err */
+#define VR_ISR_TX_ABRT 0x0008 /* tx aborted due to excess colls */
+#define VR_ISR_TX_UNDERRUN 0x0010 /* tx buffer underflow */
+#define VR_ISR_RX_NOBUF 0x0020 /* no rx buffer available */
+#define VR_ISR_BUSERR 0x0040 /* PCI bus error */
+#define VR_ISR_STATSOFLOW 0x0080 /* stats counter oflow */
+#define VR_ISR_RX_EARLY 0x0100 /* rx early */
+#define VR_ISR_LINKSTAT 0x0200 /* MII status change */
+#define VR_ISR_RX_OFLOW 0x0400 /* rx FIFO overflow */
+#define VR_ISR_RX_DROPPED 0x0800
+#define VR_ISR_RX_NOBUF2 0x1000
+#define VR_ISR_TX_ABRT2 0x2000
+#define VR_ISR_LINKSTAT2 0x4000
+#define VR_ISR_MAGICPACKET 0x8000
+
+/*
+ * Interrupt mask bits.
+ */
+#define VR_IMR_RX_OK 0x0001 /* packet rx ok */
+#define VR_IMR_TX_OK 0x0002 /* packet tx ok */
+#define VR_IMR_RX_ERR 0x0004 /* packet rx with err */
+#define VR_IMR_TX_ABRT 0x0008 /* tx aborted due to excess colls */
+#define VR_IMR_TX_UNDERRUN 0x0010 /* tx buffer underflow */
+#define VR_IMR_RX_NOBUF 0x0020 /* no rx buffer available */
+#define VR_IMR_BUSERR 0x0040 /* PCI bus error */
+#define VR_IMR_STATSOFLOW 0x0080 /* stats counter oflow */
+#define VR_IMR_RX_EARLY 0x0100 /* rx early */
+#define VR_IMR_LINKSTAT 0x0200 /* MII status change */
+#define VR_IMR_RX_OFLOW 0x0400 /* rx FIFO overflow */
+#define VR_IMR_RX_DROPPED 0x0800
+#define VR_IMR_RX_NOBUF2 0x1000
+#define VR_IMR_TX_ABRT2 0x2000
+#define VR_IMR_LINKSTAT2 0x4000
+#define VR_IMR_MAGICPACKET 0x8000
+
+#define VR_INTRS \
+ (VR_IMR_RX_OK|VR_IMR_TX_OK|VR_IMR_RX_NOBUF| \
+ VR_IMR_TX_ABRT|VR_IMR_TX_UNDERRUN|VR_IMR_BUSERR| \
+ VR_IMR_RX_ERR|VR_ISR_RX_DROPPED)
+
+/*
+ * MII status register.
+ */
+
+#define VR_MIISTAT_SPEED 0x01
+#define VR_MIISTAT_LINKFAULT 0x02
+#define VR_MIISTAT_MGTREADERR 0x04
+#define VR_MIISTAT_MIIERR 0x08
+#define VR_MIISTAT_PHYOPT 0x10
+#define VR_MIISTAT_MDC_SPEED 0x20
+#define VR_MIISTAT_RSVD 0x40
+#define VR_MIISTAT_GPIO1POLL 0x80
+
+/*
+ * MII command register bits.
+ */
+#define VR_MIICMD_CLK 0x01
+#define VR_MIICMD_DATAOUT 0x02
+#define VR_MIICMD_DATAIN 0x04
+#define VR_MIICMD_DIR 0x08
+#define VR_MIICMD_DIRECTPGM 0x10
+#define VR_MIICMD_WRITE_ENB 0x20
+#define VR_MIICMD_READ_ENB 0x40
+#define VR_MIICMD_AUTOPOLL 0x80
+
+/*
+ * EEPROM control bits.
+ */
+#define VR_EECSR_DATAIN 0x01 /* data out */
+#define VR_EECSR_DATAOUT 0x02 /* data in */
+#define VR_EECSR_CLK 0x04 /* clock */
+#define VR_EECSR_CS 0x08 /* chip select */
+#define VR_EECSR_DPM 0x10
+#define VR_EECSR_LOAD 0x20
+#define VR_EECSR_EMBP 0x40
+#define VR_EECSR_EEPR 0x80
+
+#define VR_EECMD_WRITE 0x140
+#define VR_EECMD_READ 0x180
+#define VR_EECMD_ERASE 0x1c0
+
+/*
+ * Test register bits.
+ */
+#define VR_TEST_TEST0 0x01
+#define VR_TEST_TEST1 0x02
+#define VR_TEST_TEST2 0x04
+#define VR_TEST_TSTUD 0x08
+#define VR_TEST_TSTOV 0x10
+#define VR_TEST_BKOFF 0x20
+#define VR_TEST_FCOL 0x40
+#define VR_TEST_HBDES 0x80
+
+/*
+ * Config register bits.
+ */
+#define VR_CFG_GPIO2OUTENB 0x00000001
+#define VR_CFG_GPIO2OUT 0x00000002 /* gen. purp. pin */
+#define VR_CFG_GPIO2IN 0x00000004 /* gen. purp. pin */
+#define VR_CFG_AUTOOPT 0x00000008 /* enable rx/tx autopoll */
+#define VR_CFG_MIIOPT 0x00000010
+#define VR_CFG_MMIENB 0x00000020 /* memory mapped mode enb */
+#define VR_CFG_JUMPER 0x00000040 /* PHY and oper. mode select */
+#define VR_CFG_EELOAD 0x00000080 /* enable EEPROM programming */
+#define VR_CFG_LATMENB 0x00000100 /* larency timer effect enb. */
+#define VR_CFG_MRREADWAIT 0x00000200
+#define VR_CFG_MRWRITEWAIT 0x00000400
+#define VR_CFG_RX_ARB 0x00000800
+#define VR_CFG_TX_ARB 0x00001000
+#define VR_CFG_READMULTI 0x00002000
+#define VR_CFG_TX_PACE 0x00004000
+#define VR_CFG_TX_QDIS 0x00008000
+#define VR_CFG_ROMSEL0 0x00010000
+#define VR_CFG_ROMSEL1 0x00020000
+#define VR_CFG_ROMSEL2 0x00040000
+#define VR_CFG_ROMTIMESEL 0x00080000
+#define VR_CFG_RSVD0 0x00100000
+#define VR_CFG_ROMDLY 0x00200000
+#define VR_CFG_ROMOPT 0x00400000
+#define VR_CFG_RSVD1 0x00800000
+#define VR_CFG_BACKOFFOPT 0x01000000
+#define VR_CFG_BACKOFFMOD 0x02000000
+#define VR_CFG_CAPEFFECT 0x04000000
+#define VR_CFG_BACKOFFRAND 0x08000000
+#define VR_CFG_MAGICKPACKET 0x10000000
+#define VR_CFG_PCIREADLINE 0x20000000
+#define VR_CFG_DIAG 0x40000000
+#define VR_CFG_GPIOEN 0x80000000
+
+/* Sticky HW bits */
+#define VR_STICKHW_DS0 0x01
+#define VR_STICKHW_DS1 0x02
+#define VR_STICKHW_WOL_ENB 0x04
+#define VR_STICKHW_WOL_STS 0x08
+#define VR_STICKHW_LEGWOL_ENB 0x80
+
+/*
+ * Rhine TX/RX list structure.
+ */
+
+struct vr_desc {
+ u_int32_t vr_status;
+ u_int32_t vr_ctl;
+ u_int32_t vr_ptr1;
+ u_int32_t vr_ptr2;
+};
+
+#define vr_data vr_ptr1
+#define vr_next vr_ptr2
+
+
+#define VR_RXSTAT_RXERR 0x00000001
+#define VR_RXSTAT_CRCERR 0x00000002
+#define VR_RXSTAT_FRAMEALIGNERR 0x00000004
+#define VR_RXSTAT_FIFOOFLOW 0x00000008
+#define VR_RXSTAT_GIANT 0x00000010
+#define VR_RXSTAT_RUNT 0x00000020
+#define VR_RXSTAT_BUSERR 0x00000040
+#define VR_RXSTAT_BUFFERR 0x00000080
+#define VR_RXSTAT_LASTFRAG 0x00000100
+#define VR_RXSTAT_FIRSTFRAG 0x00000200
+#define VR_RXSTAT_RLINK 0x00000400
+#define VR_RXSTAT_RX_PHYS 0x00000800
+#define VR_RXSTAT_RX_BROAD 0x00001000
+#define VR_RXSTAT_RX_MULTI 0x00002000
+#define VR_RXSTAT_RX_OK 0x00004000
+#define VR_RXSTAT_RXLEN 0x07FF0000
+#define VR_RXSTAT_RXLEN_EXT 0x78000000
+#define VR_RXSTAT_OWN 0x80000000
+
+#define VR_RXBYTES(x) ((x & VR_RXSTAT_RXLEN) >> 16)
+#define VR_RXSTAT (VR_RXSTAT_FIRSTFRAG|VR_RXSTAT_LASTFRAG|VR_RXSTAT_OWN)
+
+#define VR_RXCTL_BUFLEN 0x000007FF
+#define VR_RXCTL_BUFLEN_EXT 0x00007800
+#define VR_RXCTL_CHAIN 0x00008000
+#define VR_RXCTL_RX_INTR 0x00800000
+
+#define VR_RXCTL (VR_RXCTL_CHAIN|VR_RXCTL_RX_INTR)
+
+#define VR_TXSTAT_DEFER 0x00000001
+#define VR_TXSTAT_UNDERRUN 0x00000002
+#define VR_TXSTAT_COLLCNT 0x00000078
+#define VR_TXSTAT_SQE 0x00000080
+#define VR_TXSTAT_ABRT 0x00000100
+#define VR_TXSTAT_LATECOLL 0x00000200
+#define VR_TXSTAT_CARRLOST 0x00000400
+#define VR_TXSTAT_BUSERR 0x00002000
+#define VR_TXSTAT_JABTIMEO 0x00004000
+#define VR_TXSTAT_ERRSUM 0x00008000
+#define VR_TXSTAT_OWN 0x80000000
+
+#define VR_TXCTL_BUFLEN 0x000007FF
+#define VR_TXCTL_BUFLEN_EXT 0x00007800
+#define VR_TXCTL_TLINK 0x00008000
+#define VR_TXCTL_FIRSTFRAG 0x00200000
+#define VR_TXCTL_LASTFRAG 0x00400000
+#define VR_TXCTL_FINT 0x00800000
+
+
+#define VR_MAXFRAGS 16
+#define VR_RX_LIST_CNT 64
+#define VR_TX_LIST_CNT 128
+#define VR_MIN_FRAMELEN 60
+#define VR_FRAMELEN 1536
+#define VR_RXLEN 1520
+
+#define VR_TXOWN(x) x->vr_ptr->vr_status
+
+struct vr_list_data {
+ struct vr_desc vr_rx_list[VR_RX_LIST_CNT];
+ struct vr_desc vr_tx_list[VR_TX_LIST_CNT];
+};
+
+struct vr_chain {
+ struct vr_desc *vr_ptr;
+ struct mbuf *vr_mbuf;
+ struct vr_chain *vr_nextdesc;
+};
+
+struct vr_chain_onefrag {
+ struct vr_desc *vr_ptr;
+ struct mbuf *vr_mbuf;
+ struct vr_chain_onefrag *vr_nextdesc;
+};
+
+struct vr_chain_data {
+ struct vr_chain_onefrag vr_rx_chain[VR_RX_LIST_CNT];
+ struct vr_chain vr_tx_chain[VR_TX_LIST_CNT];
+
+ struct vr_chain_onefrag *vr_rx_head;
+
+ struct vr_chain *vr_tx_head;
+ struct vr_chain *vr_tx_tail;
+ struct vr_chain *vr_tx_free;
+};
+
+struct vr_type {
+ u_int16_t vr_vid;
+ u_int16_t vr_did;
+ char *vr_name;
+};
+
+struct vr_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define VR_MII_STARTDELIM 0x01
+#define VR_MII_READOP 0x02
+#define VR_MII_WRITEOP 0x01
+#define VR_MII_TURNAROUND 0x02
+
+#define VR_FLAG_FORCEDELAY 1
+#define VR_FLAG_SCHEDDELAY 2
+#define VR_FLAG_DELAYTIMEO 3
+
+struct vr_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t vr_bhandle; /* bus space handle */
+ bus_space_tag_t vr_btag; /* bus space tag */
+ struct resource *vr_res;
+ struct resource *vr_irq;
+ void *vr_intrhand;
+ device_t vr_miibus;
+ struct vr_type *vr_info; /* Rhine adapter info */
+ u_int8_t vr_unit; /* interface number */
+ u_int8_t vr_type;
+ struct vr_list_data *vr_ldata;
+ struct vr_chain_data vr_cdata;
+ struct callout_handle vr_stat_ch;
+ struct mtx vr_mtx;
+};
+
+#define VR_LOCK(_sc) mtx_lock(&(_sc)->vr_mtx)
+#define VR_UNLOCK(_sc) mtx_unlock(&(_sc)->vr_mtx)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->vr_btag, sc->vr_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->vr_btag, sc->vr_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->vr_btag, sc->vr_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->vr_btag, sc->vr_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->vr_btag, sc->vr_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->vr_btag, sc->vr_bhandle, reg)
+
+#define VR_TIMEOUT 1000
+#define ETHER_ALIGN 2
+
+/*
+ * General constants that are fun to know.
+ *
+ * VIA vendor ID
+ */
+#define VIA_VENDORID 0x1106
+
+/*
+ * VIA Rhine device IDs.
+ */
+#define VIA_DEVICEID_RHINE 0x3043
+#define VIA_DEVICEID_RHINE_II 0x6100
+#define VIA_DEVICEID_RHINE_II_2 0x3065
+
+/*
+ * Delta Electronics device ID.
+ */
+#define DELTA_VENDORID 0x1500
+
+/*
+ * Delta device IDs.
+ */
+#define DELTA_DEVICEID_RHINE_II 0x1320
+
+/*
+ * Addtron vendor ID.
+ */
+#define ADDTRON_VENDORID 0x4033
+
+/*
+ * Addtron device IDs.
+ */
+#define ADDTRON_DEVICEID_RHINE_II 0x1320
+
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define VR_PCI_VENDOR_ID 0x00
+#define VR_PCI_DEVICE_ID 0x02
+#define VR_PCI_COMMAND 0x04
+#define VR_PCI_STATUS 0x06
+#define VR_PCI_CLASSCODE 0x09
+#define VR_PCI_LATENCY_TIMER 0x0D
+#define VR_PCI_HEADER_TYPE 0x0E
+#define VR_PCI_LOIO 0x10
+#define VR_PCI_LOMEM 0x14
+#define VR_PCI_BIOSROM 0x30
+#define VR_PCI_INTLINE 0x3C
+#define VR_PCI_INTPIN 0x3D
+#define VR_PCI_MINGNT 0x3E
+#define VR_PCI_MINLAT 0x0F
+#define VR_PCI_RESETOPT 0x48
+#define VR_PCI_EEPROM_DATA 0x4C
+
+/* power management registers */
+#define VR_PCI_CAPID 0xDC /* 8 bits */
+#define VR_PCI_NEXTPTR 0xDD /* 8 bits */
+#define VR_PCI_PWRMGMTCAP 0xDE /* 16 bits */
+#define VR_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
+
+#define VR_PSTATE_MASK 0x0003
+#define VR_PSTATE_D0 0x0000
+#define VR_PSTATE_D1 0x0002
+#define VR_PSTATE_D2 0x0002
+#define VR_PSTATE_D3 0x0003
+#define VR_PME_EN 0x0010
+#define VR_PME_STATUS 0x8000
+
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_wb.c b/sys/pci/if_wb.c
new file mode 100644
index 0000000..aa2f161
--- /dev/null
+++ b/sys/pci/if_wb.c
@@ -0,0 +1,1880 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Winbond fast ethernet PCI NIC driver
+ *
+ * Supports various cheap network adapters based on the Winbond W89C840F
+ * fast ethernet controller chip. This includes adapters manufactured by
+ * Winbond itself and some made by Linksys.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The Winbond W89C840F chip is a bus master; in some ways it resembles
+ * a DEC 'tulip' chip, only not as complicated. Unfortunately, it has
+ * one major difference which is that while the registers do many of
+ * the same things as a tulip adapter, the offsets are different: where
+ * tulip registers are typically spaced 8 bytes apart, the Winbond
+ * registers are spaced 4 bytes apart. The receiver filter is also
+ * programmed differently.
+ *
+ * Like the tulip, the Winbond chip uses small descriptors containing
+ * a status word, a control word and 32-bit areas that can either be used
+ * to point to two external data blocks, or to point to a single block
+ * and another descriptor in a linked list. Descriptors can be grouped
+ * together in blocks to form fixed length rings or can be chained
+ * together in linked lists. A single packet may be spread out over
+ * several descriptors if necessary.
+ *
+ * For the receive ring, this driver uses a linked list of descriptors,
+ * each pointing to a single mbuf cluster buffer, which us large enough
+ * to hold an entire packet. The link list is looped back to created a
+ * closed ring.
+ *
+ * For transmission, the driver creates a linked list of 'super descriptors'
+ * which each contain several individual descriptors linked toghether.
+ * Each 'super descriptor' contains WB_MAXFRAGS descriptors, which we
+ * abuse as fragment pointers. This allows us to use a buffer managment
+ * scheme very similar to that used in the ThunderLAN and Etherlink XL
+ * drivers.
+ *
+ * Autonegotiation is performed using the external PHY via the MII bus.
+ * The sample boards I have all use a Davicom PHY.
+ *
+ * Note: the author of the Linux driver for the Winbond chip alludes
+ * to some sort of flaw in the chip's design that seems to mandate some
+ * drastic workaround which signigicantly impairs transmit performance.
+ * I have no idea what he's on about: transmit performance with all
+ * three of my test boards seems fine.
+ */
+
+#include "opt_bdg.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/queue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_memio.h>
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#define WB_USEIOSPACE
+
+#include <pci/if_wbreg.h>
+
+MODULE_DEPEND(wb, miibus, 1, 1, 1);
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct wb_type wb_devs[] = {
+ { WB_VENDORID, WB_DEVICEID_840F,
+ "Winbond W89C840F 10/100BaseTX" },
+ { CP_VENDORID, CP_DEVICEID_RL100,
+ "Compex RL100-ATX 10/100baseTX" },
+ { 0, 0, NULL }
+};
+
+static int wb_probe (device_t);
+static int wb_attach (device_t);
+static int wb_detach (device_t);
+
+static void wb_bfree (void *addr, void *args);
+static int wb_newbuf (struct wb_softc *,
+ struct wb_chain_onefrag *,
+ struct mbuf *);
+static int wb_encap (struct wb_softc *, struct wb_chain *,
+ struct mbuf *);
+
+static void wb_rxeof (struct wb_softc *);
+static void wb_rxeoc (struct wb_softc *);
+static void wb_txeof (struct wb_softc *);
+static void wb_txeoc (struct wb_softc *);
+static void wb_intr (void *);
+static void wb_tick (void *);
+static void wb_start (struct ifnet *);
+static int wb_ioctl (struct ifnet *, u_long, caddr_t);
+static void wb_init (void *);
+static void wb_stop (struct wb_softc *);
+static void wb_watchdog (struct ifnet *);
+static void wb_shutdown (device_t);
+static int wb_ifmedia_upd (struct ifnet *);
+static void wb_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void wb_eeprom_putbyte (struct wb_softc *, int);
+static void wb_eeprom_getword (struct wb_softc *, int, u_int16_t *);
+static void wb_read_eeprom (struct wb_softc *, caddr_t, int, int, int);
+static void wb_mii_sync (struct wb_softc *);
+static void wb_mii_send (struct wb_softc *, u_int32_t, int);
+static int wb_mii_readreg (struct wb_softc *, struct wb_mii_frame *);
+static int wb_mii_writereg (struct wb_softc *, struct wb_mii_frame *);
+
+static void wb_setcfg (struct wb_softc *, u_int32_t);
+static u_int8_t wb_calchash (caddr_t);
+static void wb_setmulti (struct wb_softc *);
+static void wb_reset (struct wb_softc *);
+static void wb_fixmedia (struct wb_softc *);
+static int wb_list_rx_init (struct wb_softc *);
+static int wb_list_tx_init (struct wb_softc *);
+
+static int wb_miibus_readreg (device_t, int, int);
+static int wb_miibus_writereg (device_t, int, int, int);
+static void wb_miibus_statchg (device_t);
+
+#ifdef WB_USEIOSPACE
+#define WB_RES SYS_RES_IOPORT
+#define WB_RID WB_PCI_LOIO
+#else
+#define WB_RES SYS_RES_MEMORY
+#define WB_RID WB_PCI_LOMEM
+#endif
+
+static device_method_t wb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, wb_probe),
+ DEVMETHOD(device_attach, wb_attach),
+ DEVMETHOD(device_detach, wb_detach),
+ DEVMETHOD(device_shutdown, wb_shutdown),
+
+ /* bus interface, for miibus */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, wb_miibus_readreg),
+ DEVMETHOD(miibus_writereg, wb_miibus_writereg),
+ DEVMETHOD(miibus_statchg, wb_miibus_statchg),
+ { 0, 0 }
+};
+
+static driver_t wb_driver = {
+ "wb",
+ wb_methods,
+ sizeof(struct wb_softc)
+};
+
+static devclass_t wb_devclass;
+
+DRIVER_MODULE(if_wb, pci, wb_driver, wb_devclass, 0, 0);
+DRIVER_MODULE(miibus, wb, miibus_driver, miibus_devclass, 0, 0);
+
+#define WB_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define WB_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+#define SIO_SET(x) \
+ CSR_WRITE_4(sc, WB_SIO, \
+ CSR_READ_4(sc, WB_SIO) | x)
+
+#define SIO_CLR(x) \
+ CSR_WRITE_4(sc, WB_SIO, \
+ CSR_READ_4(sc, WB_SIO) & ~x)
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void wb_eeprom_putbyte(sc, addr)
+ struct wb_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ d = addr | WB_EECMD_READ;
+
+ /*
+ * Feed in each bit and stobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ SIO_SET(WB_SIO_EE_DATAIN);
+ } else {
+ SIO_CLR(WB_SIO_EE_DATAIN);
+ }
+ DELAY(100);
+ SIO_SET(WB_SIO_EE_CLK);
+ DELAY(150);
+ SIO_CLR(WB_SIO_EE_CLK);
+ DELAY(100);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void wb_eeprom_getword(sc, addr, dest)
+ struct wb_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS);
+
+ /*
+ * Send address of word we want to read.
+ */
+ wb_eeprom_putbyte(sc, addr);
+
+ CSR_WRITE_4(sc, WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_SET(WB_SIO_EE_CLK);
+ DELAY(100);
+ if (CSR_READ_4(sc, WB_SIO) & WB_SIO_EE_DATAOUT)
+ word |= i;
+ SIO_CLR(WB_SIO_EE_CLK);
+ DELAY(100);
+ }
+
+ /* Turn off EEPROM access mode. */
+ CSR_WRITE_4(sc, WB_SIO, 0);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void wb_read_eeprom(sc, dest, off, cnt, swap)
+ struct wb_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ wb_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void wb_mii_sync(sc)
+ struct wb_softc *sc;
+{
+ register int i;
+
+ SIO_SET(WB_SIO_MII_DIR|WB_SIO_MII_DATAIN);
+
+ for (i = 0; i < 32; i++) {
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void wb_mii_send(sc, bits, cnt)
+ struct wb_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ SIO_CLR(WB_SIO_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ SIO_SET(WB_SIO_MII_DATAIN);
+ } else {
+ SIO_CLR(WB_SIO_MII_DATAIN);
+ }
+ DELAY(1);
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int wb_mii_readreg(sc, frame)
+ struct wb_softc *sc;
+ struct wb_mii_frame *frame;
+
+{
+ int i, ack;
+
+ WB_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = WB_MII_STARTDELIM;
+ frame->mii_opcode = WB_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ CSR_WRITE_4(sc, WB_SIO, 0);
+
+ /*
+ * Turn on data xmit.
+ */
+ SIO_SET(WB_SIO_MII_DIR);
+
+ wb_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ wb_mii_send(sc, frame->mii_stdelim, 2);
+ wb_mii_send(sc, frame->mii_opcode, 2);
+ wb_mii_send(sc, frame->mii_phyaddr, 5);
+ wb_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ SIO_CLR((WB_SIO_MII_CLK|WB_SIO_MII_DATAIN));
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ SIO_CLR(WB_SIO_MII_DIR);
+ /* Check for ack */
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+ ack = CSR_READ_4(sc, WB_SIO) & WB_SIO_MII_DATAOUT;
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_4(sc, WB_SIO) & WB_SIO_MII_DATAOUT)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+
+ WB_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int wb_mii_writereg(sc, frame)
+ struct wb_softc *sc;
+ struct wb_mii_frame *frame;
+
+{
+ WB_LOCK(sc);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = WB_MII_STARTDELIM;
+ frame->mii_opcode = WB_MII_WRITEOP;
+ frame->mii_turnaround = WB_MII_TURNAROUND;
+
+ /*
+ * Turn on data output.
+ */
+ SIO_SET(WB_SIO_MII_DIR);
+
+ wb_mii_sync(sc);
+
+ wb_mii_send(sc, frame->mii_stdelim, 2);
+ wb_mii_send(sc, frame->mii_opcode, 2);
+ wb_mii_send(sc, frame->mii_phyaddr, 5);
+ wb_mii_send(sc, frame->mii_regaddr, 5);
+ wb_mii_send(sc, frame->mii_turnaround, 2);
+ wb_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ SIO_SET(WB_SIO_MII_CLK);
+ DELAY(1);
+ SIO_CLR(WB_SIO_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ SIO_CLR(WB_SIO_MII_DIR);
+
+ WB_UNLOCK(sc);
+
+ return(0);
+}
+
+static int wb_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct wb_softc *sc;
+ struct wb_mii_frame frame;
+
+ sc = device_get_softc(dev);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ wb_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int wb_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct wb_softc *sc;
+ struct wb_mii_frame frame;
+
+ sc = device_get_softc(dev);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ wb_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+static void wb_miibus_statchg(dev)
+ device_t dev;
+{
+ struct wb_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ WB_LOCK(sc);
+ mii = device_get_softc(sc->wb_miibus);
+ wb_setcfg(sc, mii->mii_media_active);
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+static u_int8_t wb_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /*
+ * return the filter bit position
+ * Note: I arrived at the following nonsense
+ * through experimentation. It's not the usual way to
+ * generate the bit position but it's the only thing
+ * I could come up with that works.
+ */
+ return(~(crc >> 26) & 0x0000003F);
+}
+
+/*
+ * Program the 64-bit multicast hash filter.
+ */
+static void wb_setmulti(sc)
+ struct wb_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+ u_int32_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ rxfilt = CSR_READ_4(sc, WB_NETCFG);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= WB_NETCFG_RX_MULTI;
+ CSR_WRITE_4(sc, WB_NETCFG, rxfilt);
+ CSR_WRITE_4(sc, WB_MAR0, 0xFFFFFFFF);
+ CSR_WRITE_4(sc, WB_MAR1, 0xFFFFFFFF);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, WB_MAR0, 0);
+ CSR_WRITE_4(sc, WB_MAR1, 0);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = wb_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ mcnt++;
+ }
+
+ if (mcnt)
+ rxfilt |= WB_NETCFG_RX_MULTI;
+ else
+ rxfilt &= ~WB_NETCFG_RX_MULTI;
+
+ CSR_WRITE_4(sc, WB_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, WB_MAR1, hashes[1]);
+ CSR_WRITE_4(sc, WB_NETCFG, rxfilt);
+
+ return;
+}
+
+/*
+ * The Winbond manual states that in order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void wb_setcfg(sc, media)
+ struct wb_softc *sc;
+ u_int32_t media;
+{
+ int i, restart = 0;
+
+ if (CSR_READ_4(sc, WB_NETCFG) & (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)) {
+ restart = 1;
+ WB_CLRBIT(sc, WB_NETCFG, (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON));
+
+ for (i = 0; i < WB_TIMEOUT; i++) {
+ DELAY(10);
+ if ((CSR_READ_4(sc, WB_ISR) & WB_ISR_TX_IDLE) &&
+ (CSR_READ_4(sc, WB_ISR) & WB_ISR_RX_IDLE))
+ break;
+ }
+
+ if (i == WB_TIMEOUT)
+ printf("wb%d: failed to force tx and "
+ "rx to idle state\n", sc->wb_unit);
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_T)
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_100MBPS);
+ else
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_100MBPS);
+
+ if ((media & IFM_GMASK) == IFM_FDX)
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_FULLDUPLEX);
+ else
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_FULLDUPLEX);
+
+ if (restart)
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON|WB_NETCFG_RX_ON);
+
+ return;
+}
+
+static void wb_reset(sc)
+ struct wb_softc *sc;
+{
+ register int i;
+ struct mii_data *mii;
+
+ CSR_WRITE_4(sc, WB_NETCFG, 0);
+ CSR_WRITE_4(sc, WB_BUSCTL, 0);
+ CSR_WRITE_4(sc, WB_TXADDR, 0);
+ CSR_WRITE_4(sc, WB_RXADDR, 0);
+
+ WB_SETBIT(sc, WB_BUSCTL, WB_BUSCTL_RESET);
+ WB_SETBIT(sc, WB_BUSCTL, WB_BUSCTL_RESET);
+
+ for (i = 0; i < WB_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, WB_BUSCTL) & WB_BUSCTL_RESET))
+ break;
+ }
+ if (i == WB_TIMEOUT)
+ printf("wb%d: reset never completed!\n", sc->wb_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ if (sc->wb_miibus == NULL)
+ return;
+
+ mii = device_get_softc(sc->wb_miibus);
+ if (mii == NULL)
+ return;
+
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+
+ return;
+}
+
+static void wb_fixmedia(sc)
+ struct wb_softc *sc;
+{
+ struct mii_data *mii = NULL;
+ struct ifnet *ifp;
+ u_int32_t media;
+
+ if (sc->wb_miibus == NULL)
+ return;
+
+ mii = device_get_softc(sc->wb_miibus);
+ ifp = &sc->arpcom.ac_if;
+
+ mii_pollstat(mii);
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
+ media = mii->mii_media_active & ~IFM_10_T;
+ media |= IFM_100_TX;
+ } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
+ media = mii->mii_media_active & ~IFM_100_TX;
+ media |= IFM_10_T;
+ } else
+ return;
+
+ ifmedia_set(&mii->mii_media, media);
+
+ return;
+}
+
+/*
+ * Probe for a Winbond chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int wb_probe(dev)
+ device_t dev;
+{
+ struct wb_type *t;
+
+ t = wb_devs;
+
+ while(t->wb_name != NULL) {
+ if ((pci_get_vendor(dev) == t->wb_vid) &&
+ (pci_get_device(dev) == t->wb_did)) {
+ device_set_desc(dev, t->wb_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int wb_attach(dev)
+ device_t dev;
+{
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct wb_softc *sc;
+ struct ifnet *ifp;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+
+ mtx_init(&sc->wb_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ WB_LOCK(sc);
+
+ /*
+ * Handle power management nonsense.
+ */
+
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, WB_PCI_LOIO, 4);
+ membase = pci_read_config(dev, WB_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, WB_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("wb%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, WB_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, WB_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, WB_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef WB_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("wb%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("wb%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = WB_RID;
+ sc->wb_res = bus_alloc_resource(dev, WB_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->wb_res == NULL) {
+ printf("wb%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->wb_btag = rman_get_bustag(sc->wb_res);
+ sc->wb_bhandle = rman_get_bushandle(sc->wb_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->wb_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->wb_irq == NULL) {
+ printf("wb%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, WB_RES, WB_RID, sc->wb_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->wb_irq, INTR_TYPE_NET,
+ wb_intr, sc, &sc->wb_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->wb_irq);
+ bus_release_resource(dev, WB_RES, WB_RID, sc->wb_res);
+ printf("wb%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Save the cache line size. */
+ sc->wb_cachesize = pci_read_config(dev, WB_PCI_CACHELEN, 4) & 0xFF;
+
+ /* Reset the adapter. */
+ wb_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ wb_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 0);
+
+ /*
+ * A Winbond chip was detected. Inform the world.
+ */
+ printf("wb%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->wb_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->wb_ldata = contigmalloc(sizeof(struct wb_list_data) + 8, M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->wb_ldata == NULL) {
+ printf("wb%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->wb_irq, sc->wb_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->wb_irq);
+ bus_release_resource(dev, WB_RES, WB_RID, sc->wb_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->wb_ldata, sizeof(struct wb_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "wb";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = wb_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = wb_start;
+ ifp->if_watchdog = wb_watchdog;
+ ifp->if_init = wb_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = WB_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ if (mii_phy_probe(dev, &sc->wb_miibus,
+ wb_ifmedia_upd, wb_ifmedia_sts)) {
+ bus_teardown_intr(dev, sc->wb_irq, sc->wb_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->wb_irq);
+ bus_release_resource(dev, WB_RES, WB_RID, sc->wb_res);
+ free(sc->wb_ldata_ptr, M_DEVBUF);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ WB_UNLOCK(sc);
+ return(0);
+
+fail:
+ if (error)
+ device_delete_child(dev, sc->wb_miibus);
+ WB_UNLOCK(sc);
+ mtx_destroy(&sc->wb_mtx);
+
+ return(error);
+}
+
+static int wb_detach(dev)
+ device_t dev;
+{
+ struct wb_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ WB_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ wb_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ /* Delete any miibus and phy devices attached to this interface */
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->wb_miibus);
+
+ bus_teardown_intr(dev, sc->wb_irq, sc->wb_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->wb_irq);
+ bus_release_resource(dev, WB_RES, WB_RID, sc->wb_res);
+
+ free(sc->wb_ldata_ptr, M_DEVBUF);
+
+ WB_UNLOCK(sc);
+ mtx_destroy(&sc->wb_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int wb_list_tx_init(sc)
+ struct wb_softc *sc;
+{
+ struct wb_chain_data *cd;
+ struct wb_list_data *ld;
+ int i;
+
+ cd = &sc->wb_cdata;
+ ld = sc->wb_ldata;
+
+ for (i = 0; i < WB_TX_LIST_CNT; i++) {
+ cd->wb_tx_chain[i].wb_ptr = &ld->wb_tx_list[i];
+ if (i == (WB_TX_LIST_CNT - 1)) {
+ cd->wb_tx_chain[i].wb_nextdesc =
+ &cd->wb_tx_chain[0];
+ } else {
+ cd->wb_tx_chain[i].wb_nextdesc =
+ &cd->wb_tx_chain[i + 1];
+ }
+ }
+
+ cd->wb_tx_free = &cd->wb_tx_chain[0];
+ cd->wb_tx_tail = cd->wb_tx_head = NULL;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int wb_list_rx_init(sc)
+ struct wb_softc *sc;
+{
+ struct wb_chain_data *cd;
+ struct wb_list_data *ld;
+ int i;
+
+ cd = &sc->wb_cdata;
+ ld = sc->wb_ldata;
+
+ for (i = 0; i < WB_RX_LIST_CNT; i++) {
+ cd->wb_rx_chain[i].wb_ptr =
+ (struct wb_desc *)&ld->wb_rx_list[i];
+ cd->wb_rx_chain[i].wb_buf = (void *)&ld->wb_rxbufs[i];
+ if (wb_newbuf(sc, &cd->wb_rx_chain[i], NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (WB_RX_LIST_CNT - 1)) {
+ cd->wb_rx_chain[i].wb_nextdesc = &cd->wb_rx_chain[0];
+ ld->wb_rx_list[i].wb_next =
+ vtophys(&ld->wb_rx_list[0]);
+ } else {
+ cd->wb_rx_chain[i].wb_nextdesc =
+ &cd->wb_rx_chain[i + 1];
+ ld->wb_rx_list[i].wb_next =
+ vtophys(&ld->wb_rx_list[i + 1]);
+ }
+ }
+
+ cd->wb_rx_head = &cd->wb_rx_chain[0];
+
+ return(0);
+}
+
+static void wb_bfree(buf, args)
+ void *buf;
+ void *args;
+{
+ return;
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int wb_newbuf(sc, c, m)
+ struct wb_softc *sc;
+ struct wb_chain_onefrag *c;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+ m_new->m_data = c->wb_buf;
+ m_new->m_pkthdr.len = m_new->m_len = WB_BUFBYTES;
+ MEXTADD(m_new, c->wb_buf, WB_BUFBYTES, wb_bfree, NULL, 0,
+ EXT_NET_DRV);
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = WB_BUFBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ c->wb_mbuf = m_new;
+ c->wb_ptr->wb_data = vtophys(mtod(m_new, caddr_t));
+ c->wb_ptr->wb_ctl = WB_RXCTL_RLINK | 1536;
+ c->wb_ptr->wb_status = WB_RXSTAT;
+
+ return(0);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void wb_rxeof(sc)
+ struct wb_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m = NULL;
+ struct ifnet *ifp;
+ struct wb_chain_onefrag *cur_rx;
+ int total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+ while(!((rxstat = sc->wb_cdata.wb_rx_head->wb_ptr->wb_status) &
+ WB_RXSTAT_OWN)) {
+ struct mbuf *m0 = NULL;
+
+ cur_rx = sc->wb_cdata.wb_rx_head;
+ sc->wb_cdata.wb_rx_head = cur_rx->wb_nextdesc;
+
+ m = cur_rx->wb_mbuf;
+
+ if ((rxstat & WB_RXSTAT_MIIERR) ||
+ (WB_RXBYTES(cur_rx->wb_ptr->wb_status) < WB_MIN_FRAMELEN) ||
+ (WB_RXBYTES(cur_rx->wb_ptr->wb_status) > 1536) ||
+ !(rxstat & WB_RXSTAT_LASTFRAG) ||
+ !(rxstat & WB_RXSTAT_RXCMP)) {
+ ifp->if_ierrors++;
+ wb_newbuf(sc, cur_rx, m);
+ printf("wb%x: receiver babbling: possible chip "
+ "bug, forcing reset\n", sc->wb_unit);
+ wb_fixmedia(sc);
+ wb_reset(sc);
+ wb_init(sc);
+ return;
+ }
+
+ if (rxstat & WB_RXSTAT_RXERR) {
+ ifp->if_ierrors++;
+ wb_newbuf(sc, cur_rx, m);
+ break;
+ }
+
+ /* No errors; receive the packet. */
+ total_len = WB_RXBYTES(cur_rx->wb_ptr->wb_status);
+
+ /*
+ * XXX The Winbond chip includes the CRC with every
+ * received frame, and there's no way to turn this
+ * behavior off (at least, I can't find anything in
+ * the manual that explains how to do it) so we have
+ * to trim off the CRC manually.
+ */
+ total_len -= ETHER_CRC_LEN;
+
+ m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
+ NULL);
+ wb_newbuf(sc, cur_rx, m);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ break;
+ }
+ m = m0;
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+}
+
+void wb_rxeoc(sc)
+ struct wb_softc *sc;
+{
+ wb_rxeof(sc);
+
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, WB_RXADDR, vtophys(&sc->wb_ldata->wb_rx_list[0]));
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON);
+ if (CSR_READ_4(sc, WB_ISR) & WB_RXSTATE_SUSPEND)
+ CSR_WRITE_4(sc, WB_RXSTART, 0xFFFFFFFF);
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+static void wb_txeof(sc)
+ struct wb_softc *sc;
+{
+ struct wb_chain *cur_tx;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ if (sc->wb_cdata.wb_tx_head == NULL)
+ return;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ while(sc->wb_cdata.wb_tx_head->wb_mbuf != NULL) {
+ u_int32_t txstat;
+
+ cur_tx = sc->wb_cdata.wb_tx_head;
+ txstat = WB_TXSTATUS(cur_tx);
+
+ if ((txstat & WB_TXSTAT_OWN) || txstat == WB_UNSENT)
+ break;
+
+ if (txstat & WB_TXSTAT_TXERR) {
+ ifp->if_oerrors++;
+ if (txstat & WB_TXSTAT_ABORT)
+ ifp->if_collisions++;
+ if (txstat & WB_TXSTAT_LATECOLL)
+ ifp->if_collisions++;
+ }
+
+ ifp->if_collisions += (txstat & WB_TXSTAT_COLLCNT) >> 3;
+
+ ifp->if_opackets++;
+ m_freem(cur_tx->wb_mbuf);
+ cur_tx->wb_mbuf = NULL;
+
+ if (sc->wb_cdata.wb_tx_head == sc->wb_cdata.wb_tx_tail) {
+ sc->wb_cdata.wb_tx_head = NULL;
+ sc->wb_cdata.wb_tx_tail = NULL;
+ break;
+ }
+
+ sc->wb_cdata.wb_tx_head = cur_tx->wb_nextdesc;
+ }
+
+ return;
+}
+
+/*
+ * TX 'end of channel' interrupt handler.
+ */
+static void wb_txeoc(sc)
+ struct wb_softc *sc;
+{
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ ifp->if_timer = 0;
+
+ if (sc->wb_cdata.wb_tx_head == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->wb_cdata.wb_tx_tail = NULL;
+ } else {
+ if (WB_TXOWN(sc->wb_cdata.wb_tx_head) == WB_UNSENT) {
+ WB_TXOWN(sc->wb_cdata.wb_tx_head) = WB_TXSTAT_OWN;
+ ifp->if_timer = 5;
+ CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF);
+ }
+ }
+
+ return;
+}
+
+static void wb_intr(arg)
+ void *arg;
+{
+ struct wb_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ WB_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ if (!(ifp->if_flags & IFF_UP)) {
+ WB_UNLOCK(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, WB_IMR, 0x00000000);
+
+ for (;;) {
+
+ status = CSR_READ_4(sc, WB_ISR);
+ if (status)
+ CSR_WRITE_4(sc, WB_ISR, status);
+
+ if ((status & WB_INTRS) == 0)
+ break;
+
+ if ((status & WB_ISR_RX_NOBUF) || (status & WB_ISR_RX_ERR)) {
+ ifp->if_ierrors++;
+ wb_reset(sc);
+ if (status & WB_ISR_RX_ERR)
+ wb_fixmedia(sc);
+ wb_init(sc);
+ continue;
+ }
+
+ if (status & WB_ISR_RX_OK)
+ wb_rxeof(sc);
+
+ if (status & WB_ISR_RX_IDLE)
+ wb_rxeoc(sc);
+
+ if (status & WB_ISR_TX_OK)
+ wb_txeof(sc);
+
+ if (status & WB_ISR_TX_NOBUF)
+ wb_txeoc(sc);
+
+ if (status & WB_ISR_TX_IDLE) {
+ wb_txeof(sc);
+ if (sc->wb_cdata.wb_tx_head != NULL) {
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON);
+ CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF);
+ }
+ }
+
+ if (status & WB_ISR_TX_UNDERRUN) {
+ ifp->if_oerrors++;
+ wb_txeof(sc);
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON);
+ /* Jack up TX threshold */
+ sc->wb_txthresh += WB_TXTHRESH_CHUNK;
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_THRESH);
+ WB_SETBIT(sc, WB_NETCFG, WB_TXTHRESH(sc->wb_txthresh));
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON);
+ }
+
+ if (status & WB_ISR_BUS_ERR) {
+ wb_reset(sc);
+ wb_init(sc);
+ }
+
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, WB_IMR, WB_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL) {
+ wb_start(ifp);
+ }
+
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+static void wb_tick(xsc)
+ void *xsc;
+{
+ struct wb_softc *sc;
+ struct mii_data *mii;
+
+ sc = xsc;
+ WB_LOCK(sc);
+ mii = device_get_softc(sc->wb_miibus);
+
+ mii_tick(mii);
+
+ sc->wb_stat_ch = timeout(wb_tick, sc, hz);
+
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int wb_encap(sc, c, m_head)
+ struct wb_softc *sc;
+ struct wb_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct wb_desc *f = NULL;
+ int total_len;
+ struct mbuf *m;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ total_len = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == WB_MAXFRAGS)
+ break;
+ total_len += m->m_len;
+ f = &c->wb_ptr->wb_frag[frag];
+ f->wb_ctl = WB_TXCTL_TLINK | m->m_len;
+ if (frag == 0) {
+ f->wb_ctl |= WB_TXCTL_FIRSTFRAG;
+ f->wb_status = 0;
+ } else
+ f->wb_status = WB_TXSTAT_OWN;
+ f->wb_next = vtophys(&c->wb_ptr->wb_frag[frag + 1]);
+ f->wb_data = vtophys(mtod(m, vm_offset_t));
+ frag++;
+ }
+ }
+
+ /*
+ * Handle special case: we used up all 16 fragments,
+ * but we have more mbufs left in the chain. Copy the
+ * data into an mbuf cluster. Note that we don't
+ * bother clearing the values in the other fragment
+ * pointers/counters; it wouldn't gain us anything,
+ * and would waste cycles.
+ */
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(1);
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ f = &c->wb_ptr->wb_frag[0];
+ f->wb_status = 0;
+ f->wb_data = vtophys(mtod(m_new, caddr_t));
+ f->wb_ctl = total_len = m_new->m_len;
+ f->wb_ctl |= WB_TXCTL_TLINK|WB_TXCTL_FIRSTFRAG;
+ frag = 1;
+ }
+
+ if (total_len < WB_MIN_FRAMELEN) {
+ f = &c->wb_ptr->wb_frag[frag];
+ f->wb_ctl = WB_MIN_FRAMELEN - total_len;
+ f->wb_data = vtophys(&sc->wb_cdata.wb_pad);
+ f->wb_ctl |= WB_TXCTL_TLINK;
+ f->wb_status = WB_TXSTAT_OWN;
+ frag++;
+ }
+
+ c->wb_mbuf = m_head;
+ c->wb_lastdesc = frag - 1;
+ WB_TXCTL(c) |= WB_TXCTL_LASTFRAG;
+ WB_TXNEXT(c) = vtophys(&c->wb_nextdesc->wb_ptr->wb_frag[0]);
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void wb_start(ifp)
+ struct ifnet *ifp;
+{
+ struct wb_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct wb_chain *cur_tx = NULL, *start_tx;
+
+ sc = ifp->if_softc;
+ WB_LOCK(sc);
+
+ /*
+ * Check for an available queue slot. If there are none,
+ * punt.
+ */
+ if (sc->wb_cdata.wb_tx_free->wb_mbuf != NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ WB_UNLOCK(sc);
+ return;
+ }
+
+ start_tx = sc->wb_cdata.wb_tx_free;
+
+ while(sc->wb_cdata.wb_tx_free->wb_mbuf == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /* Pick a descriptor off the free list. */
+ cur_tx = sc->wb_cdata.wb_tx_free;
+ sc->wb_cdata.wb_tx_free = cur_tx->wb_nextdesc;
+
+ /* Pack the data into the descriptor. */
+ wb_encap(sc, cur_tx, m_head);
+
+ if (cur_tx != start_tx)
+ WB_TXOWN(cur_tx) = WB_TXSTAT_OWN;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->wb_mbuf);
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL) {
+ WB_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ WB_TXCTL(cur_tx) |= WB_TXCTL_FINT;
+ cur_tx->wb_ptr->wb_frag[0].wb_ctl |= WB_TXCTL_FINT;
+ sc->wb_cdata.wb_tx_tail = cur_tx;
+
+ if (sc->wb_cdata.wb_tx_head == NULL) {
+ sc->wb_cdata.wb_tx_head = start_tx;
+ WB_TXOWN(start_tx) = WB_TXSTAT_OWN;
+ CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF);
+ } else {
+ /*
+ * We need to distinguish between the case where
+ * the own bit is clear because the chip cleared it
+ * and where the own bit is clear because we haven't
+ * set it yet. The magic value WB_UNSET is just some
+ * ramdomly chosen number which doesn't have the own
+ * bit set. When we actually transmit the frame, the
+ * status word will have _only_ the own bit set, so
+ * the txeoc handler will be able to tell if it needs
+ * to initiate another transmission to flush out pending
+ * frames.
+ */
+ WB_TXOWN(start_tx) = WB_UNSENT;
+ }
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+static void wb_init(xsc)
+ void *xsc;
+{
+ struct wb_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i;
+ struct mii_data *mii;
+
+ WB_LOCK(sc);
+ mii = device_get_softc(sc->wb_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ wb_stop(sc);
+ wb_reset(sc);
+
+ sc->wb_txthresh = WB_TXTHRESH_INIT;
+
+ /*
+ * Set cache alignment and burst length.
+ */
+#ifdef foo
+ CSR_WRITE_4(sc, WB_BUSCTL, WB_BUSCTL_CONFIG);
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_THRESH);
+ WB_SETBIT(sc, WB_NETCFG, WB_TXTHRESH(sc->wb_txthresh));
+#endif
+
+ CSR_WRITE_4(sc, WB_BUSCTL, WB_BUSCTL_MUSTBEONE|WB_BUSCTL_ARBITRATION);
+ WB_SETBIT(sc, WB_BUSCTL, WB_BURSTLEN_16LONG);
+ switch(sc->wb_cachesize) {
+ case 32:
+ WB_SETBIT(sc, WB_BUSCTL, WB_CACHEALIGN_32LONG);
+ break;
+ case 16:
+ WB_SETBIT(sc, WB_BUSCTL, WB_CACHEALIGN_16LONG);
+ break;
+ case 8:
+ WB_SETBIT(sc, WB_BUSCTL, WB_CACHEALIGN_8LONG);
+ break;
+ case 0:
+ default:
+ WB_SETBIT(sc, WB_BUSCTL, WB_CACHEALIGN_NONE);
+ break;
+ }
+
+ /* This doesn't tend to work too well at 100Mbps. */
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_EARLY_ON);
+
+ /* Init our MAC address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ CSR_WRITE_1(sc, WB_NODE0 + i, sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Init circular RX list. */
+ if (wb_list_rx_init(sc) == ENOBUFS) {
+ printf("wb%d: initialization failed: no "
+ "memory for rx buffers\n", sc->wb_unit);
+ wb_stop(sc);
+ WB_UNLOCK(sc);
+ return;
+ }
+
+ /* Init TX descriptors. */
+ wb_list_tx_init(sc);
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ALLPHYS);
+ } else {
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ALLPHYS);
+ }
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_BROAD);
+ } else {
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_BROAD);
+ }
+
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ wb_setmulti(sc);
+
+ /*
+ * Load the address of the RX list.
+ */
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, WB_RXADDR, vtophys(&sc->wb_ldata->wb_rx_list[0]));
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_4(sc, WB_IMR, WB_INTRS);
+ CSR_WRITE_4(sc, WB_ISR, 0xFFFFFFFF);
+
+ /* Enable receiver and transmitter. */
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, WB_RXSTART, 0xFFFFFFFF);
+
+ WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON);
+ CSR_WRITE_4(sc, WB_TXADDR, vtophys(&sc->wb_ldata->wb_tx_list[0]));
+ WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON);
+
+ mii_mediachg(mii);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->wb_stat_ch = timeout(wb_tick, sc, hz);
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int wb_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct wb_softc *sc;
+
+ sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_UP)
+ wb_init(sc);
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void wb_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct wb_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ mii = device_get_softc(sc->wb_miibus);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int wb_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct wb_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0;
+
+ WB_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ wb_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ wb_stop(sc);
+ }
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ wb_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->wb_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ WB_UNLOCK(sc);
+
+ return(error);
+}
+
+static void wb_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct wb_softc *sc;
+
+ sc = ifp->if_softc;
+
+ WB_LOCK(sc);
+ ifp->if_oerrors++;
+ printf("wb%d: watchdog timeout\n", sc->wb_unit);
+#ifdef foo
+ if (!(wb_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
+ printf("wb%d: no carrier - transceiver cable problem?\n",
+ sc->wb_unit);
+#endif
+ wb_stop(sc);
+ wb_reset(sc);
+ wb_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ wb_start(ifp);
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void wb_stop(sc)
+ struct wb_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ WB_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(wb_tick, sc, sc->wb_stat_ch);
+
+ WB_CLRBIT(sc, WB_NETCFG, (WB_NETCFG_RX_ON|WB_NETCFG_TX_ON));
+ CSR_WRITE_4(sc, WB_IMR, 0x00000000);
+ CSR_WRITE_4(sc, WB_TXADDR, 0x00000000);
+ CSR_WRITE_4(sc, WB_RXADDR, 0x00000000);
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < WB_RX_LIST_CNT; i++) {
+ if (sc->wb_cdata.wb_rx_chain[i].wb_mbuf != NULL) {
+ m_freem(sc->wb_cdata.wb_rx_chain[i].wb_mbuf);
+ sc->wb_cdata.wb_rx_chain[i].wb_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->wb_ldata->wb_rx_list,
+ sizeof(sc->wb_ldata->wb_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < WB_TX_LIST_CNT; i++) {
+ if (sc->wb_cdata.wb_tx_chain[i].wb_mbuf != NULL) {
+ m_freem(sc->wb_cdata.wb_tx_chain[i].wb_mbuf);
+ sc->wb_cdata.wb_tx_chain[i].wb_mbuf = NULL;
+ }
+ }
+
+ bzero((char *)&sc->wb_ldata->wb_tx_list,
+ sizeof(sc->wb_ldata->wb_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ WB_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void wb_shutdown(dev)
+ device_t dev;
+{
+ struct wb_softc *sc;
+
+ sc = device_get_softc(dev);
+ wb_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_wbreg.h b/sys/pci/if_wbreg.h
new file mode 100644
index 0000000..983886b
--- /dev/null
+++ b/sys/pci/if_wbreg.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Winbond register definitions.
+ */
+
+#define WB_BUSCTL 0x00 /* bus control */
+#define WB_TXSTART 0x04 /* tx start demand */
+#define WB_RXSTART 0x08 /* rx start demand */
+#define WB_RXADDR 0x0C /* rx descriptor list start addr */
+#define WB_TXADDR 0x10 /* tx descriptor list start addr */
+#define WB_ISR 0x14 /* interrupt status register */
+#define WB_NETCFG 0x18 /* network config register */
+#define WB_IMR 0x1C /* interrupt mask */
+#define WB_FRAMESDISCARDED 0x20 /* # of discarded frames */
+#define WB_SIO 0x24 /* MII and ROM/EEPROM access */
+#define WB_BOOTROMADDR 0x28
+#define WB_TIMER 0x2C /* general timer */
+#define WB_CURRXCTL 0x30 /* current RX descriptor */
+#define WB_CURRXBUF 0x34 /* current RX buffer */
+#define WB_MAR0 0x38 /* multicast filter 0 */
+#define WB_MAR1 0x3C /* multicast filter 1 */
+#define WB_NODE0 0x40 /* station address 0 */
+#define WB_NODE1 0x44 /* station address 1 */
+#define WB_BOOTROMSIZE 0x48 /* boot ROM size */
+#define WB_CURTXCTL 0x4C /* current TX descriptor */
+#define WB_CURTXBUF 0x50 /* current TX buffer */
+
+/*
+ * Bus control bits.
+ */
+#define WB_BUSCTL_RESET 0x00000001
+#define WB_BUSCTL_ARBITRATION 0x00000002
+#define WB_BUSCTL_SKIPLEN 0x0000007C
+#define WB_BUSCTL_BUF_BIGENDIAN 0x00000080
+#define WB_BUSCTL_BURSTLEN 0x00003F00
+#define WB_BUSCTL_CACHEALIGN 0x0000C000
+#define WB_BUSCTL_DES_BIGENDIAN 0x00100000
+#define WB_BUSCTL_WAIT 0x00200000
+#define WB_BUSCTL_MUSTBEONE 0x00400000
+
+#define WB_SKIPLEN_1LONG 0x00000004
+#define WB_SKIPLEN_2LONG 0x00000008
+#define WB_SKIPLEN_3LONG 0x00000010
+#define WB_SKIPLEN_4LONG 0x00000020
+#define WB_SKIPLEN_5LONG 0x00000040
+
+#define WB_CACHEALIGN_NONE 0x00000000
+#define WB_CACHEALIGN_8LONG 0x00004000
+#define WB_CACHEALIGN_16LONG 0x00008000
+#define WB_CACHEALIGN_32LONG 0x0000C000
+
+#define WB_BURSTLEN_USECA 0x00000000
+#define WB_BURSTLEN_1LONG 0x00000100
+#define WB_BURSTLEN_2LONG 0x00000200
+#define WB_BURSTLEN_4LONG 0x00000400
+#define WB_BURSTLEN_8LONG 0x00000800
+#define WB_BURSTLEN_16LONG 0x00001000
+#define WB_BURSTLEN_32LONG 0x00002000
+
+#define WB_BUSCTL_CONFIG (WB_CACHEALIGN_8LONG|WB_SKIPLEN_3LONG| \
+ WB_BURSTLEN_8LONG)
+
+/*
+ * Interrupt status bits.
+ */
+#define WB_ISR_TX_OK 0x00000001
+#define WB_ISR_TX_IDLE 0x00000002
+#define WB_ISR_TX_NOBUF 0x00000004
+#define WB_ISR_RX_EARLY 0x00000008
+#define WB_ISR_RX_ERR 0x00000010
+#define WB_ISR_TX_UNDERRUN 0x00000020
+#define WB_ISR_RX_OK 0x00000040
+#define WB_ISR_RX_NOBUF 0x00000080
+#define WB_ISR_RX_IDLE 0x00000100
+#define WB_ISR_TX_EARLY 0x00000400
+#define WB_ISR_TIMER_EXPIRED 0x00000800
+#define WB_ISR_BUS_ERR 0x00002000
+#define WB_ISR_ABNORMAL 0x00008000
+#define WB_ISR_NORMAL 0x00010000
+#define WB_ISR_RX_STATE 0x000E0000
+#define WB_ISR_TX_STATE 0x00700000
+#define WB_ISR_BUSERRTYPE 0x03800000
+
+/*
+ * The RX_STATE and TX_STATE fields are not described anywhere in the
+ * Winbond datasheet, however it appears that the Winbond chip is an
+ * attempt at a DEC 'tulip' clone, hence the ISR register is identical
+ * to that of the tulip chip and we can steal the bit definitions from
+ * the tulip documentation.
+ */
+#define WB_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
+#define WB_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
+#define WB_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
+#define WB_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
+#define WB_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
+#define WB_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
+#define WB_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
+#define WB_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
+
+#define WB_TXSTATE_RESET 0x00000000 /* 000 - reset */
+#define WB_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
+#define WB_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
+#define WB_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
+#define WB_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
+#define WB_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
+#define WB_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
+#define WB_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
+
+/*
+ * Network config bits.
+ */
+#define WB_NETCFG_RX_ON 0x00000002
+#define WB_NETCFG_RX_ALLPHYS 0x00000008
+#define WB_NETCFG_RX_MULTI 0x00000010
+#define WB_NETCFG_RX_BROAD 0x00000020
+#define WB_NETCFG_RX_RUNT 0x00000040
+#define WB_NETCFG_RX_ERR 0x00000080
+#define WB_NETCFG_FULLDUPLEX 0x00000200
+#define WB_NETCFG_LOOPBACK 0x00000C00
+#define WB_NETCFG_TX_ON 0x00002000
+#define WB_NETCFG_TX_THRESH 0x001FC000
+#define WB_NETCFG_RX_EARLYTHRSH 0x1FE00000
+#define WB_NETCFG_100MBPS 0x20000000
+#define WB_NETCFG_TX_EARLY_ON 0x40000000
+#define WB_NETCFG_RX_EARLY_ON 0x80000000
+
+/*
+ * The tx threshold can be adjusted in increments of 32 bytes.
+ */
+#define WB_TXTHRESH(x) ((x >> 5) << 14)
+#define WB_TXTHRESH_CHUNK 32
+#define WB_TXTHRESH_INIT 0 /*72*/
+
+/*
+ * Interrupt mask bits.
+ */
+#define WB_IMR_TX_OK 0x00000001
+#define WB_IMR_TX_IDLE 0x00000002
+#define WB_IMR_TX_NOBUF 0x00000004
+#define WB_IMR_RX_EARLY 0x00000008
+#define WB_IMR_RX_ERR 0x00000010
+#define WB_IMR_TX_UNDERRUN 0x00000020
+#define WB_IMR_RX_OK 0x00000040
+#define WB_IMR_RX_NOBUF 0x00000080
+#define WB_IMR_RX_IDLE 0x00000100
+#define WB_IMR_TX_EARLY 0x00000400
+#define WB_IMR_TIMER_EXPIRED 0x00000800
+#define WB_IMR_BUS_ERR 0x00002000
+#define WB_IMR_ABNORMAL 0x00008000
+#define WB_IMR_NORMAL 0x00010000
+
+#define WB_INTRS \
+ (WB_IMR_RX_OK|WB_IMR_TX_OK|WB_IMR_RX_NOBUF|WB_IMR_RX_ERR| \
+ WB_IMR_TX_NOBUF|WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \
+ WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY)
+/*
+ * Serial I/O (EEPROM/ROM) bits.
+ */
+#define WB_SIO_EE_CS 0x00000001 /* EEPROM chip select */
+#define WB_SIO_EE_CLK 0x00000002 /* EEPROM clock */
+#define WB_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
+#define WB_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
+#define WB_SIO_ROMDATA4 0x00000010
+#define WB_SIO_ROMDATA5 0x00000020
+#define WB_SIO_ROMDATA6 0x00000040
+#define WB_SIO_ROMDATA7 0x00000080
+#define WB_SIO_ROMCTL_WRITE 0x00000200
+#define WB_SIO_ROMCTL_READ 0x00000400
+#define WB_SIO_EESEL 0x00000800
+#define WB_SIO_MII_CLK 0x00010000 /* MDIO clock */
+#define WB_SIO_MII_DATAIN 0x00020000 /* MDIO data out */
+#define WB_SIO_MII_DIR 0x00040000 /* MDIO dir */
+#define WB_SIO_MII_DATAOUT 0x00080000 /* MDIO data in */
+
+#define WB_EECMD_WRITE 0x140
+#define WB_EECMD_READ 0x180
+#define WB_EECMD_ERASE 0x1c0
+
+/*
+ * Winbond TX/RX descriptor structure.
+ */
+
+struct wb_desc {
+ u_int32_t wb_status;
+ u_int32_t wb_ctl;
+ u_int32_t wb_ptr1;
+ u_int32_t wb_ptr2;
+};
+
+#define wb_data wb_ptr1
+#define wb_next wb_ptr2
+
+#define WB_RXSTAT_CRCERR 0x00000002
+#define WB_RXSTAT_DRIBBLE 0x00000004
+#define WB_RXSTAT_MIIERR 0x00000008
+#define WB_RXSTAT_LATEEVENT 0x00000040
+#define WB_RXSTAT_GIANT 0x00000080
+#define WB_RXSTAT_LASTFRAG 0x00000100
+#define WB_RXSTAT_FIRSTFRAG 0x00000200
+#define WB_RXSTAT_MULTICAST 0x00000400
+#define WB_RXSTAT_RUNT 0x00000800
+#define WB_RXSTAT_RXTYPE 0x00003000
+#define WB_RXSTAT_RXERR 0x00008000
+#define WB_RXSTAT_RXLEN 0x3FFF0000
+#define WB_RXSTAT_RXCMP 0x40000000
+#define WB_RXSTAT_OWN 0x80000000
+
+#define WB_RXBYTES(x) ((x & WB_RXSTAT_RXLEN) >> 16)
+#define WB_RXSTAT (WB_RXSTAT_FIRSTFRAG|WB_RXSTAT_LASTFRAG|WB_RXSTAT_OWN)
+
+#define WB_RXCTL_BUFLEN1 0x00000FFF
+#define WB_RXCTL_BUFLEN2 0x00FFF000
+#define WB_RXCTL_RLINK 0x01000000
+#define WB_RXCTL_RLAST 0x02000000
+
+#define WB_TXSTAT_DEFER 0x00000001
+#define WB_TXSTAT_UNDERRUN 0x00000002
+#define WB_TXSTAT_COLLCNT 0x00000078
+#define WB_TXSTAT_SQE 0x00000080
+#define WB_TXSTAT_ABORT 0x00000100
+#define WB_TXSTAT_LATECOLL 0x00000200
+#define WB_TXSTAT_NOCARRIER 0x00000400
+#define WB_TXSTAT_CARRLOST 0x00000800
+#define WB_TXSTAT_TXERR 0x00001000
+#define WB_TXSTAT_OWN 0x80000000
+
+#define WB_TXCTL_BUFLEN1 0x000007FF
+#define WB_TXCTL_BUFLEN2 0x003FF800
+#define WB_TXCTL_PAD 0x00800000
+#define WB_TXCTL_TLINK 0x01000000
+#define WB_TXCTL_TLAST 0x02000000
+#define WB_TXCTL_NOCRC 0x08000000
+#define WB_TXCTL_FIRSTFRAG 0x20000000
+#define WB_TXCTL_LASTFRAG 0x40000000
+#define WB_TXCTL_FINT 0x80000000
+
+#define WB_MAXFRAGS 16
+#define WB_RX_LIST_CNT 64
+#define WB_TX_LIST_CNT 128
+#define WB_MIN_FRAMELEN 60
+#define ETHER_ALIGN 2
+
+/*
+ * A transmit 'super descriptor' is actually WB_MAXFRAGS regular
+ * descriptors clumped together. The idea here is to emulate the
+ * multi-fragment descriptor layout found in devices such as the
+ * Texas Instruments ThunderLAN and 3Com boomerang and cylone chips.
+ * The advantage to using this scheme is that it avoids buffer copies.
+ * The disadvantage is that there's a certain amount of overhead due
+ * to the fact that each 'fragment' is 16 bytes long. In my tests,
+ * this limits top speed to about 10.5MB/sec. It should be more like
+ * 11.5MB/sec. However, the upshot is that you can achieve better
+ * results on slower machines: a Pentium 200 can pump out packets at
+ * same speed as a PII 400.
+ */
+struct wb_txdesc {
+ struct wb_desc wb_frag[WB_MAXFRAGS];
+};
+
+#define WB_TXNEXT(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_next
+#define WB_TXSTATUS(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_status
+#define WB_TXCTL(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_ctl
+#define WB_TXDATA(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_data
+
+#define WB_TXOWN(x) x->wb_ptr->wb_frag[0].wb_status
+
+#define WB_UNSENT 0x1234
+
+#define WB_BUFBYTES (1024 * sizeof(u_int32_t))
+
+struct wb_buf {
+ u_int32_t wb_data[1024];
+};
+
+struct wb_list_data {
+ struct wb_buf wb_rxbufs[WB_RX_LIST_CNT];
+ struct wb_desc wb_rx_list[WB_RX_LIST_CNT];
+ struct wb_txdesc wb_tx_list[WB_TX_LIST_CNT];
+};
+
+struct wb_chain {
+ struct wb_txdesc *wb_ptr;
+ struct mbuf *wb_mbuf;
+ struct wb_chain *wb_nextdesc;
+ u_int8_t wb_lastdesc;
+};
+
+struct wb_chain_onefrag {
+ struct wb_desc *wb_ptr;
+ struct mbuf *wb_mbuf;
+ void *wb_buf;
+ struct wb_chain_onefrag *wb_nextdesc;
+ u_int8_t wb_rlast;
+};
+
+struct wb_chain_data {
+ u_int8_t wb_pad[WB_MIN_FRAMELEN];
+ struct wb_chain_onefrag wb_rx_chain[WB_RX_LIST_CNT];
+ struct wb_chain wb_tx_chain[WB_TX_LIST_CNT];
+
+ struct wb_chain_onefrag *wb_rx_head;
+
+ struct wb_chain *wb_tx_head;
+ struct wb_chain *wb_tx_tail;
+ struct wb_chain *wb_tx_free;
+};
+
+struct wb_type {
+ u_int16_t wb_vid;
+ u_int16_t wb_did;
+ char *wb_name;
+};
+
+struct wb_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define WB_MII_STARTDELIM 0x01
+#define WB_MII_READOP 0x02
+#define WB_MII_WRITEOP 0x01
+#define WB_MII_TURNAROUND 0x02
+
+struct wb_softc {
+ struct arpcom arpcom; /* interface info */
+ device_t wb_miibus;
+ bus_space_handle_t wb_bhandle;
+ bus_space_tag_t wb_btag;
+ struct resource *wb_res;
+ struct resource *wb_irq;
+ void *wb_intrhand;
+ struct wb_type *wb_info; /* Winbond adapter info */
+ u_int8_t wb_unit; /* interface number */
+ u_int8_t wb_type;
+ u_int16_t wb_txthresh;
+ int wb_cachesize;
+ caddr_t wb_ldata_ptr;
+ struct wb_list_data *wb_ldata;
+ struct wb_chain_data wb_cdata;
+ struct callout_handle wb_stat_ch;
+ struct mtx wb_mtx;
+};
+
+#define WB_LOCK(_sc) mtx_lock(&(_sc)->wb_mtx)
+#define WB_UNLOCK(_sc) mtx_unlock(&(_sc)->wb_mtx)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->wb_btag, sc->wb_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->wb_btag, sc->wb_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->wb_btag, sc->wb_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->wb_btag, sc->wb_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->wb_btag, sc->wb_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->wb_btag, sc->wb_bhandle, reg)
+
+#define WB_TIMEOUT 1000
+
+/*
+ * General constants that are fun to know.
+ *
+ * Winbond PCI vendor ID
+ */
+#define WB_VENDORID 0x1050
+
+/*
+ * Winbond device IDs.
+ */
+#define WB_DEVICEID_840F 0x0840
+
+/*
+ * Compex vendor ID.
+ */
+#define CP_VENDORID 0x11F6
+
+/*
+ * Compex device IDs.
+ */
+#define CP_DEVICEID_RL100 0x2011
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define WB_PCI_VENDOR_ID 0x00
+#define WB_PCI_DEVICE_ID 0x02
+#define WB_PCI_COMMAND 0x04
+#define WB_PCI_STATUS 0x06
+#define WB_PCI_CLASSCODE 0x09
+#define WB_PCI_CACHELEN 0x0C
+#define WB_PCI_LATENCY_TIMER 0x0D
+#define WB_PCI_HEADER_TYPE 0x0E
+#define WB_PCI_LOIO 0x10
+#define WB_PCI_LOMEM 0x14
+#define WB_PCI_BIOSROM 0x30
+#define WB_PCI_INTLINE 0x3C
+#define WB_PCI_INTPIN 0x3D
+#define WB_PCI_MINGNT 0x3E
+#define WB_PCI_MINLAT 0x0F
+#define WB_PCI_RESETOPT 0x48
+#define WB_PCI_EEPROM_DATA 0x4C
+
+/* power management registers */
+#define WB_PCI_CAPID 0xDC /* 8 bits */
+#define WB_PCI_NEXTPTR 0xDD /* 8 bits */
+#define WB_PCI_PWRMGMTCAP 0xDE /* 16 bits */
+#define WB_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
+
+#define WB_PSTATE_MASK 0x0003
+#define WB_PSTATE_D0 0x0000
+#define WB_PSTATE_D1 0x0002
+#define WB_PSTATE_D2 0x0002
+#define WB_PSTATE_D3 0x0003
+#define WB_PME_EN 0x0010
+#define WB_PME_STATUS 0x8000
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
new file mode 100644
index 0000000..782361c
--- /dev/null
+++ b/sys/pci/if_xl.c
@@ -0,0 +1,3082 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * 3Com 3c90x Etherlink XL PCI NIC driver
+ *
+ * Supports the 3Com "boomerang", "cyclone" and "hurricane" PCI
+ * bus-master chips (3c90x cards and embedded controllers) including
+ * the following:
+ *
+ * 3Com 3c900-TPO 10Mbps/RJ-45
+ * 3Com 3c900-COMBO 10Mbps/RJ-45,AUI,BNC
+ * 3Com 3c905-TX 10/100Mbps/RJ-45
+ * 3Com 3c905-T4 10/100Mbps/RJ-45
+ * 3Com 3c900B-TPO 10Mbps/RJ-45
+ * 3Com 3c900B-COMBO 10Mbps/RJ-45,AUI,BNC
+ * 3Com 3c900B-TPC 10Mbps/RJ-45,BNC
+ * 3Com 3c900B-FL 10Mbps/Fiber-optic
+ * 3Com 3c905B-COMBO 10/100Mbps/RJ-45,AUI,BNC
+ * 3Com 3c905B-TX 10/100Mbps/RJ-45
+ * 3Com 3c905B-FL/FX 10/100Mbps/Fiber-optic
+ * 3Com 3c905C-TX 10/100Mbps/RJ-45 (Tornado ASIC)
+ * 3Com 3c980-TX 10/100Mbps server adapter (Hurricane ASIC)
+ * 3Com 3c980C-TX 10/100Mbps server adapter (Tornado ASIC)
+ * 3Com 3cSOHO100-TX 10/100Mbps/RJ-45 (Hurricane ASIC)
+ * 3Com 3c450-TX 10/100Mbps/RJ-45 (Tornado ASIC)
+ * 3Com 3c556 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC)
+ * 3Com 3c556B 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC)
+ * 3Com 3c575TX 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC)
+ * 3Com 3c575B 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC)
+ * 3Com 3c575C 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC)
+ * 3Com 3cxfem656 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC)
+ * 3Com 3cxfem656b 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC)
+ * 3Com 3cxfem656c 10/100Mbps/RJ-45 (Cardbus, Tornado ASIC)
+ * Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45
+ * Dell on-board 3c920 10/100Mbps/RJ-45
+ * Dell Precision on-board 3c905B 10/100Mbps/RJ-45
+ * Dell Latitude laptop docking station embedded 3c905-TX
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The 3c90x series chips use a bus-master DMA interface for transfering
+ * packets to and from the controller chip. Some of the "vortex" cards
+ * (3c59x) also supported a bus master mode, however for those chips
+ * you could only DMA packets to/from a contiguous memory buffer. For
+ * transmission this would mean copying the contents of the queued mbuf
+ * chain into a an mbuf cluster and then DMAing the cluster. This extra
+ * copy would sort of defeat the purpose of the bus master support for
+ * any packet that doesn't fit into a single mbuf.
+ *
+ * By contrast, the 3c90x cards support a fragment-based bus master
+ * mode where mbuf chains can be encapsulated using TX descriptors.
+ * This is similar to other PCI chips such as the Texas Instruments
+ * ThunderLAN and the Intel 82557/82558.
+ *
+ * The "vortex" driver (if_vx.c) happens to work for the "boomerang"
+ * bus master chips because they maintain the old PIO interface for
+ * backwards compatibility, but starting with the 3c905B and the
+ * "cyclone" chips, the compatibility interface has been dropped.
+ * Since using bus master DMA is a big win, we use this driver to
+ * support the PCI "boomerang" chips even though they work with the
+ * "vortex" driver in order to obtain better performance.
+ *
+ * This driver is in the /sys/pci directory because it only supports
+ * PCI-based NICs.
+ */
+
+#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 <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/bus_memio.h>
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+MODULE_DEPEND(xl, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+/*
+ * The following #define causes the code to use PIO to access the
+ * chip's registers instead of memory mapped mode. The reason PIO mode
+ * is on by default is that the Etherlink XL manual seems to indicate
+ * that only the newer revision chips (3c905B) support both PIO and
+ * memory mapped access. Since we want to be compatible with the older
+ * bus master chips, we use PIO here. If you comment this out, the
+ * driver will use memory mapped I/O, which may be faster but which
+ * might not work on some devices.
+ */
+#define XL_USEIOSPACE
+
+#include <pci/if_xlreg.h>
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#define XL905B_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP)
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct xl_type xl_devs[] = {
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT,
+ "3Com 3c900-TPO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT_COMBO,
+ "3Com 3c900-COMBO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10_100BT,
+ "3Com 3c905-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_100BT4,
+ "3Com 3c905-T4 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT,
+ "3Com 3c900B-TPO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_COMBO,
+ "3Com 3c900B-COMBO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_TPC,
+ "3Com 3c900B-TPC Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10FL,
+ "3Com 3c900B-FL Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT,
+ "3Com 3c905B-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100BT4,
+ "3Com 3c905B-T4 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100FX,
+ "3Com 3c905B-FX/SC Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100_COMBO,
+ "3Com 3c905B-COMBO Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT,
+ "3Com 3c905C-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT_SERV,
+ "3Com 3c980 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT_SERV,
+ "3Com 3c980C Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_SOHO100TX,
+ "3Com 3cSOHO100-TX OfficeConnect" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_HOMECONNECT,
+ "3Com 3c450-TX HomeConnect" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556,
+ "3Com 3c556 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556B,
+ "3Com 3c556B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575A,
+ "3Com 3c575TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575B,
+ "3Com 3c575B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575C,
+ "3Com 3c575C Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_656,
+ "3Com 3c656 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_656B,
+ "3Com 3c656B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_656C,
+ "3Com 3c656C Fast Etherlink XL" },
+ { 0, 0, NULL }
+};
+
+static int xl_probe (device_t);
+static int xl_attach (device_t);
+static int xl_detach (device_t);
+
+static int xl_newbuf (struct xl_softc *, struct xl_chain_onefrag *);
+static void xl_stats_update (void *);
+static int xl_encap (struct xl_softc *, struct xl_chain *,
+ struct mbuf *);
+static int xl_encap_90xB (struct xl_softc *, struct xl_chain *,
+ struct mbuf *);
+
+static void xl_rxeof (struct xl_softc *);
+static int xl_rx_resync (struct xl_softc *);
+static void xl_txeof (struct xl_softc *);
+static void xl_txeof_90xB (struct xl_softc *);
+static void xl_txeoc (struct xl_softc *);
+static void xl_intr (void *);
+static void xl_start (struct ifnet *);
+static void xl_start_90xB (struct ifnet *);
+static int xl_ioctl (struct ifnet *, u_long, caddr_t);
+static void xl_init (void *);
+static void xl_stop (struct xl_softc *);
+static void xl_watchdog (struct ifnet *);
+static void xl_shutdown (device_t);
+static int xl_suspend (device_t);
+static int xl_resume (device_t);
+
+static int xl_ifmedia_upd (struct ifnet *);
+static void xl_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static int xl_eeprom_wait (struct xl_softc *);
+static int xl_read_eeprom (struct xl_softc *, caddr_t, int, int, int);
+static void xl_mii_sync (struct xl_softc *);
+static void xl_mii_send (struct xl_softc *, u_int32_t, int);
+static int xl_mii_readreg (struct xl_softc *, struct xl_mii_frame *);
+static int xl_mii_writereg (struct xl_softc *, struct xl_mii_frame *);
+
+static void xl_setcfg (struct xl_softc *);
+static void xl_setmode (struct xl_softc *, int);
+static u_int8_t xl_calchash (caddr_t);
+static void xl_setmulti (struct xl_softc *);
+static void xl_setmulti_hash (struct xl_softc *);
+static void xl_reset (struct xl_softc *);
+static int xl_list_rx_init (struct xl_softc *);
+static int xl_list_tx_init (struct xl_softc *);
+static int xl_list_tx_init_90xB (struct xl_softc *);
+static void xl_wait (struct xl_softc *);
+static void xl_mediacheck (struct xl_softc *);
+static void xl_choose_xcvr (struct xl_softc *, int);
+#ifdef notdef
+static void xl_testpacket (struct xl_softc *);
+#endif
+
+static int xl_miibus_readreg (device_t, int, int);
+static int xl_miibus_writereg (device_t, int, int, int);
+static void xl_miibus_statchg (device_t);
+static void xl_miibus_mediainit (device_t);
+
+#ifdef XL_USEIOSPACE
+#define XL_RES SYS_RES_IOPORT
+#define XL_RID XL_PCI_LOIO
+#else
+#define XL_RES SYS_RES_MEMORY
+#define XL_RID XL_PCI_LOMEM
+#endif
+
+static device_method_t xl_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, xl_probe),
+ DEVMETHOD(device_attach, xl_attach),
+ DEVMETHOD(device_detach, xl_detach),
+ DEVMETHOD(device_shutdown, xl_shutdown),
+ DEVMETHOD(device_suspend, xl_suspend),
+ DEVMETHOD(device_resume, xl_resume),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, xl_miibus_readreg),
+ DEVMETHOD(miibus_writereg, xl_miibus_writereg),
+ DEVMETHOD(miibus_statchg, xl_miibus_statchg),
+ DEVMETHOD(miibus_mediainit, xl_miibus_mediainit),
+
+ { 0, 0 }
+};
+
+static driver_t xl_driver = {
+ "xl",
+ xl_methods,
+ sizeof(struct xl_softc)
+};
+
+static devclass_t xl_devclass;
+
+DRIVER_MODULE(if_xl, cardbus, xl_driver, xl_devclass, 0, 0);
+DRIVER_MODULE(if_xl, pci, xl_driver, xl_devclass, 0, 0);
+DRIVER_MODULE(miibus, xl, miibus_driver, miibus_devclass, 0, 0);
+
+/*
+ * Murphy's law says that it's possible the chip can wedge and
+ * the 'command in progress' bit may never clear. Hence, we wait
+ * only a finite amount of time to avoid getting caught in an
+ * infinite loop. Normally this delay routine would be a macro,
+ * but it isn't called during normal operation so we can afford
+ * to make it a function.
+ */
+static void xl_wait(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+ if (i == XL_TIMEOUT)
+ printf("xl%d: command never completed!\n", sc->xl_unit);
+
+ return;
+}
+
+/*
+ * MII access routines are provided for adapters with external
+ * PHYs (3c905-TX, 3c905-T4, 3c905B-T4) and those with built-in
+ * autoneg logic that's faked up to look like a PHY (3c905B-TX).
+ * Note: if you don't perform the MDIO operations just right,
+ * it's possible to end up with code that works correctly with
+ * some chips/CPUs/processor speeds/bus speeds/etc but not
+ * with others.
+ */
+#define MII_SET(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) | x)
+
+#define MII_CLR(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~x)
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void xl_mii_sync(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(4);
+ MII_SET(XL_MII_DIR|XL_MII_DATA);
+
+ for (i = 0; i < 32; i++) {
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void xl_mii_send(sc, bits, cnt)
+ struct xl_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ XL_SEL_WIN(4);
+ MII_CLR(XL_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ MII_SET(XL_MII_DATA);
+ } else {
+ MII_CLR(XL_MII_DATA);
+ }
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int xl_mii_readreg(sc, frame)
+ struct xl_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ int i, ack;
+
+ XL_LOCK(sc);
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Select register window 4.
+ */
+
+ XL_SEL_WIN(4);
+
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0);
+ /*
+ * Turn on data xmit.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ MII_CLR((XL_MII_CLK|XL_MII_DATA));
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ MII_CLR(XL_MII_DIR);
+
+ /* Check for ack */
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA;
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+
+ XL_UNLOCK(sc);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int xl_mii_writereg(sc, frame)
+ struct xl_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ XL_LOCK(sc);
+
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_WRITEOP;
+ frame->mii_turnaround = XL_MII_TURNAROUND;
+
+ /*
+ * Select the window 4.
+ */
+ XL_SEL_WIN(4);
+
+ /*
+ * Turn on data output.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+ xl_mii_send(sc, frame->mii_turnaround, 2);
+ xl_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ MII_CLR(XL_MII_DIR);
+
+ XL_UNLOCK(sc);
+
+ return(0);
+}
+
+static int xl_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct xl_softc *sc;
+ struct xl_mii_frame frame;
+
+ sc = device_get_softc(dev);
+
+ /*
+ * Pretend that PHYs are only available at MII address 24.
+ * This is to guard against problems with certain 3Com ASIC
+ * revisions that incorrectly map the internal transceiver
+ * control registers at all MII addresses. This can cause
+ * the miibus code to attach the same PHY several times over.
+ */
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
+ return(0);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ xl_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int xl_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct xl_softc *sc;
+ struct xl_mii_frame frame;
+
+ sc = device_get_softc(dev);
+
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
+ return(0);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ xl_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+static void xl_miibus_statchg(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+ struct mii_data *mii;
+
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->xl_miibus);
+
+ XL_LOCK(sc);
+
+ xl_setcfg(sc);
+
+ /* Set ASIC's duplex mode to match the PHY. */
+ XL_SEL_WIN(3);
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+ else
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
+ (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Special support for the 3c905B-COMBO. This card has 10/100 support
+ * plus BNC and AUI ports. This means we will have both an miibus attached
+ * plus some non-MII media settings. In order to allow this, we have to
+ * add the extra media to the miibus's ifmedia struct, but we can't do
+ * that during xl_attach() because the miibus hasn't been attached yet.
+ * So instead, we wait until the miibus probe/attach is done, at which
+ * point we will get a callback telling is that it's safe to add our
+ * extra media.
+ */
+static void xl_miibus_mediainit(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+ struct mii_data *mii;
+ struct ifmedia *ifm;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->xl_miibus);
+ ifm = &mii->mii_media;
+
+ XL_LOCK(sc);
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ /*
+ * Check for a 10baseFL board in disguise.
+ */
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ if (bootverbose)
+ printf("xl%d: found 10baseFL\n", sc->xl_unit);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_FL, 0, NULL);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_FL|IFM_HDX, 0, NULL);
+ if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
+ ifmedia_add(ifm,
+ IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
+ } else {
+ if (bootverbose)
+ printf("xl%d: found AUI\n", sc->xl_unit);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_5, 0, NULL);
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ if (bootverbose)
+ printf("xl%d: found BNC\n", sc->xl_unit);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_2, 0, NULL);
+ }
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * The EEPROM is slow: give it time to come ready after issuing
+ * it a command.
+ */
+static int xl_eeprom_wait(sc)
+ struct xl_softc *sc;
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ if (CSR_READ_2(sc, XL_W0_EE_CMD) & XL_EE_BUSY)
+ DELAY(162);
+ else
+ break;
+ }
+
+ if (i == 100) {
+ printf("xl%d: eeprom failed to come ready\n", sc->xl_unit);
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * Read a sequence of words from the EEPROM. Note that ethernet address
+ * data is stored in the EEPROM in network byte order.
+ */
+static int xl_read_eeprom(sc, dest, off, cnt, swap)
+ struct xl_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int err = 0, i;
+ u_int16_t word = 0, *ptr;
+#define EEPROM_5BIT_OFFSET(A) ((((A) << 2) & 0x7F00) | ((A) & 0x003F))
+#define EEPROM_8BIT_OFFSET(A) ((A) & 0x003F)
+ /* WARNING! DANGER!
+ * It's easy to accidentally overwrite the rom content!
+ * Note: the 3c575 uses 8bit EEPROM offsets.
+ */
+ XL_SEL_WIN(0);
+
+ if (xl_eeprom_wait(sc))
+ return(1);
+
+ if (sc->xl_flags & XL_FLAG_EEPROM_OFFSET_30)
+ off += 0x30;
+
+ for (i = 0; i < cnt; i++) {
+ if (sc->xl_flags & XL_FLAG_8BITROM)
+ CSR_WRITE_2(sc, XL_W0_EE_CMD,
+ XL_EE_8BIT_READ | EEPROM_8BIT_OFFSET(off + i));
+ else
+ CSR_WRITE_2(sc, XL_W0_EE_CMD,
+ XL_EE_READ | EEPROM_5BIT_OFFSET(off + i));
+ err = xl_eeprom_wait(sc);
+ if (err)
+ break;
+ word = CSR_READ_2(sc, XL_W0_EE_DATA);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return(err ? 1 : 0);
+}
+
+/*
+ * This routine is taken from the 3Com Etherlink XL manual,
+ * page 10-7. It calculates a CRC of the supplied multicast
+ * group address and returns the lower 8 bits, which are used
+ * as the multicast filter position.
+ * Note: the 3c905B currently only supports a 64-bit hash table,
+ * which means we really only need 6 bits, but the manual indicates
+ * that future chip revisions will have a 256-bit hash table,
+ * hence the routine is set up to calculate 8 bits of position
+ * info in case we need it some day.
+ * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a
+ * 256 bit hash table. This means we have to use all 8 bits regardless.
+ * On older cards, the upper 2 bits will be ignored. Grrrr....
+ */
+static u_int8_t xl_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return(crc & 0x000000FF);
+}
+
+/*
+ * NICs older than the 3c905B have only one multicast option, which
+ * is to enable reception of all multicast frames.
+ */
+static void xl_setmulti(sc)
+ struct xl_softc *sc;
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ u_int8_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ if (ifp->if_flags & IFF_ALLMULTI) {
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ return;
+ }
+
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
+ mcnt++;
+
+ if (mcnt)
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ else
+ rxfilt &= ~XL_RXFILTER_ALLMULTI;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+
+ return;
+}
+
+/*
+ * 3c905B adapters have a hash filter that we can program.
+ */
+static void xl_setmulti_hash(sc)
+ struct xl_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0, i;
+ struct ifmultiaddr *ifma;
+ u_int8_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ if (ifp->if_flags & IFF_ALLMULTI) {
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ return;
+ } else
+ rxfilt &= ~XL_RXFILTER_ALLMULTI;
+
+
+ /* first, zot all the existing hash bits */
+ for (i = 0; i < XL_HASHFILT_SIZE; i++)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);
+
+ /* now program new ones */
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = xl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|XL_HASH_SET|h);
+ mcnt++;
+ }
+
+ if (mcnt)
+ rxfilt |= XL_RXFILTER_MULTIHASH;
+ else
+ rxfilt &= ~XL_RXFILTER_MULTIHASH;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+
+ return;
+}
+
+#ifdef notdef
+static void xl_testpacket(sc)
+ struct xl_softc *sc;
+{
+ struct mbuf *m;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ if (m == NULL)
+ return;
+
+ bcopy(&sc->arpcom.ac_enaddr,
+ mtod(m, struct ether_header *)->ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&sc->arpcom.ac_enaddr,
+ mtod(m, struct ether_header *)->ether_shost, ETHER_ADDR_LEN);
+ mtod(m, struct ether_header *)->ether_type = htons(3);
+ mtod(m, unsigned char *)[14] = 0;
+ mtod(m, unsigned char *)[15] = 0;
+ mtod(m, unsigned char *)[16] = 0xE3;
+ m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
+ IF_ENQUEUE(&ifp->if_snd, m);
+ xl_start(ifp);
+
+ return;
+}
+#endif
+
+static void xl_setcfg(sc)
+ struct xl_softc *sc;
+{
+ u_int32_t icfg;
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ if (sc->xl_media & XL_MEDIAOPT_MII ||
+ sc->xl_media & XL_MEDIAOPT_BT4)
+ icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS);
+ if (sc->xl_media & XL_MEDIAOPT_BTX)
+ icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS);
+
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+
+ return;
+}
+
+static void xl_setmode(sc, media)
+ struct xl_softc *sc;
+ int media;
+{
+ u_int32_t icfg;
+ u_int16_t mediastat;
+
+ printf("xl%d: selecting ", sc->xl_unit);
+
+ XL_SEL_WIN(4);
+ mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+
+ if (sc->xl_media & XL_MEDIAOPT_BT) {
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ printf("10baseT transceiver, ");
+ sc->xl_xcvr = XL_XCVR_10BT;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BFX) {
+ if (IFM_SUBTYPE(media) == IFM_100_FX) {
+ printf("100baseFX port, ");
+ sc->xl_xcvr = XL_XCVR_100BFX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ if (IFM_SUBTYPE(media) == IFM_10_5) {
+ printf("AUI port, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ if (IFM_SUBTYPE(media) == IFM_10_FL) {
+ printf("10baseFL transceiver, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ if (IFM_SUBTYPE(media) == IFM_10_2) {
+ printf("BNC port, ");
+ sc->xl_xcvr = XL_XCVR_COAX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD|
+ XL_MEDIASTAT_SQEENB);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX ||
+ IFM_SUBTYPE(media) == IFM_100_FX) {
+ printf("full duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+ } else {
+ printf("half duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
+ (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_2)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat);
+ DELAY(800);
+ XL_SEL_WIN(7);
+
+ return;
+}
+
+static void xl_reset(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(0);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET |
+ ((sc->xl_flags & XL_FLAG_WEIRDRESET) ?
+ XL_RESETOPT_DISADVFD:0));
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+ if (i == XL_TIMEOUT)
+ printf("xl%d: reset didn't complete\n", sc->xl_unit);
+
+ /* Reset TX and RX. */
+ /* Note: the RX reset takes an absurd amount of time
+ * on newer versions of the Tornado chips such as those
+ * on the 3c905CX and newer 3c908C cards. We wait an
+ * extra amount of time so that xl_wait() doesn't complain
+ * and annoy the users.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ DELAY(100000);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+
+ if (sc->xl_flags & XL_FLAG_INVERT_LED_PWR ||
+ sc->xl_flags & XL_FLAG_INVERT_MII_PWR) {
+ XL_SEL_WIN(2);
+ CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, CSR_READ_2(sc,
+ XL_W2_RESET_OPTIONS)
+ | ((sc->xl_flags & XL_FLAG_INVERT_LED_PWR)?XL_RESETOPT_INVERT_LED:0)
+ | ((sc->xl_flags & XL_FLAG_INVERT_MII_PWR)?XL_RESETOPT_INVERT_MII:0)
+ );
+ }
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(100000);
+ return;
+}
+
+/*
+ * Probe for a 3Com Etherlink XL chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int xl_probe(dev)
+ device_t dev;
+{
+ struct xl_type *t;
+
+ t = xl_devs;
+
+ while(t->xl_name != NULL) {
+ if ((pci_get_vendor(dev) == t->xl_vid) &&
+ (pci_get_device(dev) == t->xl_did)) {
+ device_set_desc(dev, t->xl_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+/*
+ * This routine is a kludge to work around possible hardware faults
+ * or manufacturing defects that can cause the media options register
+ * (or reset options register, as it's called for the first generation
+ * 3c90x adapters) to return an incorrect result. I have encountered
+ * one Dell Latitude laptop docking station with an integrated 3c905-TX
+ * which doesn't have any of the 'mediaopt' bits set. This screws up
+ * the attach routine pretty badly because it doesn't know what media
+ * to look for. If we find ourselves in this predicament, this routine
+ * will try to guess the media options values and warn the user of a
+ * possible manufacturing defect with his adapter/system/whatever.
+ */
+static void xl_mediacheck(sc)
+ struct xl_softc *sc;
+{
+
+ /*
+ * If some of the media options bits are set, assume they are
+ * correct. If not, try to figure it out down below.
+ * XXX I should check for 10baseFL, but I don't have an adapter
+ * to test with.
+ */
+ if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) {
+ /*
+ * Check the XCVR value. If it's not in the normal range
+ * of values, we need to fake it up here.
+ */
+ if (sc->xl_xcvr <= XL_XCVR_AUTO)
+ return;
+ else {
+ printf("xl%d: bogus xcvr value "
+ "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr);
+ printf("xl%d: choosing new default based "
+ "on card type\n", sc->xl_unit);
+ }
+ } else {
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media & XL_MEDIAOPT_10FL)
+ return;
+ printf("xl%d: WARNING: no media options bits set in "
+ "the media options register!!\n", sc->xl_unit);
+ printf("xl%d: this could be a manufacturing defect in "
+ "your adapter or system\n", sc->xl_unit);
+ printf("xl%d: attempting to guess media type; you "
+ "should probably consult your vendor\n", sc->xl_unit);
+ }
+
+ xl_choose_xcvr(sc, 1);
+
+ return;
+}
+
+static void xl_choose_xcvr(sc, verbose)
+ struct xl_softc *sc;
+ int verbose;
+{
+ u_int16_t devid;
+
+ /*
+ * Read the device ID from the EEPROM.
+ * This is what's loaded into the PCI device ID register, so it has
+ * to be correct otherwise we wouldn't have gotten this far.
+ */
+ xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0);
+
+ switch(devid) {
+ case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */
+ case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */
+ sc->xl_media = XL_MEDIAOPT_BT;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing 10BaseT "
+ "transceiver\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */
+ case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing COMBO "
+ "(AUI/BNC/TP)\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing TPC (BNC/TP)\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */
+ sc->xl_media = XL_MEDIAOPT_10FL;
+ sc->xl_xcvr = XL_XCVR_AUI;
+ if (verbose)
+ printf("xl%d: guessing 10baseFL\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */
+ case TC_DEVICEID_HURRICANE_556: /* 3c556 */
+ case TC_DEVICEID_HURRICANE_556B: /* 3c556B */
+ case TC_DEVICEID_HURRICANE_575A: /* 3c575TX */
+ case TC_DEVICEID_HURRICANE_575B: /* 3c575B */
+ case TC_DEVICEID_HURRICANE_575C: /* 3c575C */
+ case TC_DEVICEID_HURRICANE_656: /* 3c656 */
+ case TC_DEVICEID_HURRICANE_656B: /* 3c656B */
+ case TC_DEVICEID_TORNADO_656C: /* 3c656C */
+ sc->xl_media = XL_MEDIAOPT_MII;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printf("xl%d: guessing MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */
+ case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */
+ sc->xl_media = XL_MEDIAOPT_BT4;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printf("xl%d: guessing 100BaseT4/MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */
+ case TC_DEVICEID_HURRICANE_10_100BT_SERV:/*3c980-TX */
+ case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */
+ case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */
+ case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */
+ case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */
+ sc->xl_media = XL_MEDIAOPT_BTX;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (verbose)
+ printf("xl%d: guessing 10/100 internal\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (verbose)
+ printf("xl%d: guessing 10/100 "
+ "plus BNC/AUI\n", sc->xl_unit);
+ break;
+ default:
+ printf("xl%d: unknown device ID: %x -- "
+ "defaulting to 10baseT\n", sc->xl_unit, devid);
+ sc->xl_media = XL_MEDIAOPT_BT;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int xl_attach(dev)
+ device_t dev;
+{
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+ int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+
+ mtx_init(&sc->xl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ XL_LOCK(sc);
+
+ sc->xl_flags = 0;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_556 ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_556B)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK |
+ XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_WEIRDRESET |
+ XL_FLAG_INVERT_LED_PWR | XL_FLAG_INVERT_MII_PWR;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_556)
+ sc->xl_flags |= XL_FLAG_8BITROM;
+
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_575A ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_575B ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_575C ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_656B ||
+ pci_get_device(dev) == TC_DEVICEID_TORNADO_656C)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK |
+ XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_8BITROM;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_656)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_575B)
+ sc->xl_flags |= XL_FLAG_INVERT_LED_PWR;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_575C)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR;
+ if (pci_get_device(dev) == TC_DEVICEID_TORNADO_656C)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_656 ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_656B)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR |
+ XL_FLAG_INVERT_LED_PWR;
+
+ /*
+ * If this is a 3c905B, we have to check one extra thing.
+ * The 905B supports power management and may be placed in
+ * a low-power mode (D3 mode), typically by certain operating
+ * systems which shall not be named. The PCI BIOS is supposed
+ * to reset the NIC and bring it out of low-power mode, but
+ * some do not. Consequently, we have to see if this chip
+ * supports power management, and if so, make sure it's not
+ * in low-power mode. If power management is available, the
+ * capid byte will be 0x01.
+ *
+ * I _think_ that what actually happens is that the chip
+ * loses its PCI configuration during the transition from
+ * D3 back to D0; this means that it should be possible for
+ * us to save the PCI iobase, membase and IRQ, put the chip
+ * back in the D0 state, then restore the PCI config ourselves.
+ */
+
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, XL_PCI_LOIO, 4);
+ membase = pci_read_config(dev, XL_PCI_LOMEM, 4);
+ irq = pci_read_config(dev, XL_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("xl%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit,
+ pci_get_powerstate(dev));
+
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, XL_PCI_LOIO, iobase, 4);
+ pci_write_config(dev, XL_PCI_LOMEM, membase, 4);
+ pci_write_config(dev, XL_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+ pci_enable_io(dev, SYS_RES_IOPORT);
+ pci_enable_io(dev, SYS_RES_MEMORY);
+ command = pci_read_config(dev, PCIR_COMMAND, 4);
+
+#ifdef XL_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("xl%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("xl%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = XL_RID;
+ sc->xl_res = bus_alloc_resource(dev, XL_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->xl_res == NULL) {
+ printf ("xl%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->xl_btag = rman_get_bustag(sc->xl_res);
+ sc->xl_bhandle = rman_get_bushandle(sc->xl_res);
+
+ if (sc->xl_flags & XL_FLAG_FUNCREG) {
+ rid = XL_PCI_FUNCMEM;
+ sc->xl_fres = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->xl_fres == NULL) {
+ printf ("xl%d: couldn't map ports/memory\n", unit);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->xl_ftag = rman_get_bustag(sc->xl_fres);
+ sc->xl_fhandle = rman_get_bushandle(sc->xl_fres);
+ }
+
+ rid = 0;
+ sc->xl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->xl_irq == NULL) {
+ printf("xl%d: couldn't map interrupt\n", unit);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->xl_irq, INTR_TYPE_NET,
+ xl_intr, sc, &sc->xl_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ printf("xl%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Reset the adapter. */
+ xl_reset(sc);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ if (xl_read_eeprom(sc, (caddr_t)&eaddr, XL_EE_OEM_ADR0, 3, 1)) {
+ printf("xl%d: failed to read station address\n", sc->xl_unit);
+ bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * A 3Com chip was detected. Inform the world.
+ */
+ printf("xl%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->xl_unit = unit;
+ callout_handle_init(&sc->xl_stat_ch);
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->xl_ldata = contigmalloc(sizeof(struct xl_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->xl_ldata == NULL) {
+ printf("xl%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->xl_ldata, sizeof(struct xl_list_data));
+
+ /*
+ * Figure out the card type. 3c905B adapters have the
+ * 'supportsNoTxLength' bit set in the capabilities
+ * word in the EEPROM.
+ */
+ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
+ if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
+ sc->xl_type = XL_TYPE_905B;
+ else
+ sc->xl_type = XL_TYPE_90X;
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "xl";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = xl_ioctl;
+ ifp->if_output = ether_output;
+ if (sc->xl_type == XL_TYPE_905B) {
+ ifp->if_start = xl_start_90xB;
+ ifp->if_hwassist = XL905B_CSUM_FEATURES;
+ ifp->if_capabilities = IFCAP_HWCSUM;
+ } else
+ ifp->if_start = xl_start;
+ ifp->if_watchdog = xl_watchdog;
+ ifp->if_init = xl_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = XL_TX_LIST_CNT - 1;
+ ifp->if_capenable = ifp->if_capabilities;
+
+ /*
+ * Now we have to see what sort of media we have.
+ * This includes probing for an MII interace and a
+ * possible PHY.
+ */
+ XL_SEL_WIN(3);
+ sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT);
+ if (bootverbose)
+ printf("xl%d: media options word: %x\n", sc->xl_unit,
+ sc->xl_media);
+
+ xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0);
+ sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK;
+ sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS;
+
+ xl_mediacheck(sc);
+
+ if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX
+ || sc->xl_media & XL_MEDIAOPT_BT4) {
+ if (bootverbose)
+ printf("xl%d: found MII/AUTO\n", sc->xl_unit);
+ xl_setcfg(sc);
+ if (mii_phy_probe(dev, &sc->xl_miibus,
+ xl_ifmedia_upd, xl_ifmedia_sts)) {
+ printf("xl%d: no PHY found!\n", sc->xl_unit);
+ bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ contigfree(sc->xl_ldata,
+ sizeof(struct xl_list_data), M_DEVBUF);
+ error = ENXIO;
+ goto fail;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Sanity check. If the user has selected "auto" and this isn't
+ * a 10/100 card of some kind, we need to force the transceiver
+ * type to something sane.
+ */
+ if (sc->xl_xcvr == XL_XCVR_AUTO)
+ xl_choose_xcvr(sc, bootverbose);
+
+ /*
+ * Do ifmedia setup.
+ */
+
+ ifmedia_init(&sc->ifmedia, 0, xl_ifmedia_upd, xl_ifmedia_sts);
+
+ if (sc->xl_media & XL_MEDIAOPT_BT) {
+ if (bootverbose)
+ printf("xl%d: found 10baseT\n", sc->xl_unit);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
+ if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ }
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ /*
+ * Check for a 10baseFL board in disguise.
+ */
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ if (bootverbose)
+ printf("xl%d: found 10baseFL\n", sc->xl_unit);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL|IFM_HDX,
+ 0, NULL);
+ if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
+ } else {
+ if (bootverbose)
+ printf("xl%d: found AUI\n", sc->xl_unit);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ if (bootverbose)
+ printf("xl%d: found BNC\n", sc->xl_unit);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BFX) {
+ if (bootverbose)
+ printf("xl%d: found 100baseFX\n", sc->xl_unit);
+ ifp->if_baudrate = 100000000;
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_FX, 0, NULL);
+ }
+
+ /* Choose a default media. */
+ switch(sc->xl_xcvr) {
+ case XL_XCVR_10BT:
+ media = IFM_ETHER|IFM_10_T;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUI:
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ media = IFM_ETHER|IFM_10_FL;
+ xl_setmode(sc, media);
+ } else {
+ media = IFM_ETHER|IFM_10_5;
+ xl_setmode(sc, media);
+ }
+ break;
+ case XL_XCVR_COAX:
+ media = IFM_ETHER|IFM_10_2;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUTO:
+ case XL_XCVR_100BTX:
+ case XL_XCVR_MII:
+ /* Chosen by miibus */
+ break;
+ case XL_XCVR_100BFX:
+ media = IFM_ETHER|IFM_100_FX;
+ break;
+ default:
+ printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit,
+ sc->xl_xcvr);
+ /*
+ * This will probably be wrong, but it prevents
+ * the ifmedia code from panicking.
+ */
+ media = IFM_ETHER|IFM_10_T;
+ break;
+ }
+
+ if (sc->xl_miibus == NULL)
+ ifmedia_set(&sc->ifmedia, media);
+
+done:
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+ XL_UNLOCK(sc);
+ return(0);
+
+fail:
+ XL_UNLOCK(sc);
+ mtx_destroy(&sc->xl_mtx);
+
+ return(error);
+}
+
+static int xl_detach(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ XL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ xl_reset(sc);
+ xl_stop(sc);
+ ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
+
+ /* Delete any miibus and phy devices attached to this interface */
+ if (sc->xl_miibus != NULL) {
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->xl_miibus);
+ }
+
+ bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+
+ ifmedia_removeall(&sc->ifmedia);
+ contigfree(sc->xl_ldata, sizeof(struct xl_list_data), M_DEVBUF);
+
+ XL_UNLOCK(sc);
+ mtx_destroy(&sc->xl_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int xl_list_tx_init(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
+ if (i == (XL_TX_LIST_CNT - 1))
+ cd->xl_tx_chain[i].xl_next = NULL;
+ else
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
+ }
+
+ cd->xl_tx_free = &cd->xl_tx_chain[0];
+ cd->xl_tx_tail = cd->xl_tx_head = NULL;
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int xl_list_tx_init_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
+ cd->xl_tx_chain[i].xl_phys = vtophys(&ld->xl_tx_list[i]);
+ if (i == (XL_TX_LIST_CNT - 1))
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0];
+ else
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
+ if (i == 0)
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[XL_TX_LIST_CNT - 1];
+ else
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[i - 1];
+ }
+
+ bzero((char *)ld->xl_tx_list,
+ sizeof(struct xl_list) * XL_TX_LIST_CNT);
+ ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY;
+
+ cd->xl_tx_prod = 1;
+ cd->xl_tx_cons = 1;
+ cd->xl_tx_cnt = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int xl_list_rx_init(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ cd->xl_rx_chain[i].xl_ptr =
+ (struct xl_list_onefrag *)&ld->xl_rx_list[i];
+ if (xl_newbuf(sc, &cd->xl_rx_chain[i]) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (XL_RX_LIST_CNT - 1)) {
+ cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0];
+ ld->xl_rx_list[i].xl_next =
+ vtophys(&ld->xl_rx_list[0]);
+ } else {
+ cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1];
+ ld->xl_rx_list[i].xl_next =
+ vtophys(&ld->xl_rx_list[i + 1]);
+ }
+ }
+
+ cd->xl_rx_head = &cd->xl_rx_chain[0];
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int xl_newbuf(sc, c)
+ struct xl_softc *sc;
+ struct xl_chain_onefrag *c;
+{
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+
+ /* Force longword alignment for packet payload. */
+ m_adj(m_new, ETHER_ALIGN);
+
+ c->xl_mbuf = m_new;
+ c->xl_ptr->xl_frag.xl_addr = vtophys(mtod(m_new, caddr_t));
+ c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG;
+ c->xl_ptr->xl_status = 0;
+
+ return(0);
+}
+
+static int xl_rx_resync(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_onefrag *pos;
+ int i;
+
+ pos = sc->xl_cdata.xl_rx_head;
+
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ if (pos->xl_ptr->xl_status)
+ break;
+ pos = pos->xl_next;
+ }
+
+ if (i == XL_RX_LIST_CNT)
+ return(0);
+
+ sc->xl_cdata.xl_rx_head = pos;
+
+ return(EAGAIN);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void xl_rxeof(sc)
+ struct xl_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct xl_chain_onefrag *cur_rx;
+ int total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+again:
+
+ while((rxstat = sc->xl_cdata.xl_rx_head->xl_ptr->xl_status)) {
+ cur_rx = sc->xl_cdata.xl_rx_head;
+ sc->xl_cdata.xl_rx_head = cur_rx->xl_next;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & XL_RXSTAT_UP_ERROR) {
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ /*
+ * If there error bit was not set, the upload complete
+ * bit should be set which means we have a valid packet.
+ * If not, something truly strange has happened.
+ */
+ if (!(rxstat & XL_RXSTAT_UP_CMPLT)) {
+ printf("xl%d: bad receive status -- "
+ "packet dropped", sc->xl_unit);
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+ m = cur_rx->xl_mbuf;
+ total_len = cur_rx->xl_ptr->xl_status & XL_RXSTAT_LENMASK;
+
+ /*
+ * Try to conjure up a new mbuf cluster. If that
+ * fails, it means we have an out of memory condition and
+ * should leave the buffer in place and continue. This will
+ * result in a lost packet, but there's little else we
+ * can do in this situation.
+ */
+ if (xl_newbuf(sc, cur_rx) == ENOBUFS) {
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+
+ if (sc->xl_type == XL_TYPE_905B) {
+ /* Do IP checksum checking. */
+ if (rxstat & XL_RXSTAT_IPCKOK)
+ m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+ if (!(rxstat & XL_RXSTAT_IPCKERR))
+ m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+ if ((rxstat & XL_RXSTAT_TCPCOK &&
+ !(rxstat & XL_RXSTAT_TCPCKERR)) ||
+ (rxstat & XL_RXSTAT_UDPCKOK &&
+ !(rxstat & XL_RXSTAT_UDPCKERR))) {
+ m->m_pkthdr.csum_flags |=
+ CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+ }
+ ether_input(ifp, eh, m);
+ }
+
+ /*
+ * Handle the 'end of channel' condition. When the upload
+ * engine hits the end of the RX ring, it will stall. This
+ * is our cue to flush the RX ring, reload the uplist pointer
+ * register and unstall the engine.
+ * XXX This is actually a little goofy. With the ThunderLAN
+ * chip, you get an interrupt when the receiver hits the end
+ * of the receive ring, which tells you exactly when you
+ * you need to reload the ring pointer. Here we have to
+ * fake it. I'm mad at myself for not being clever enough
+ * to avoid the use of a goto here.
+ */
+ if (CSR_READ_4(sc, XL_UPLIST_PTR) == 0 ||
+ CSR_READ_4(sc, XL_UPLIST_STATUS) & XL_PKTSTAT_UP_STALLED) {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR,
+ vtophys(&sc->xl_ldata->xl_rx_list[0]));
+ sc->xl_cdata.xl_rx_head = &sc->xl_cdata.xl_rx_chain[0];
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ goto again;
+ }
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+static void xl_txeof(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain *cur_tx;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been uploaded. Note: the 3c905B
+ * sets a special bit in the status word to let us
+ * know that a frame has been downloaded, but the
+ * original 3c900/3c905 adapters don't do that.
+ * Consequently, we have to use a different test if
+ * xl_type != XL_TYPE_905B.
+ */
+ while(sc->xl_cdata.xl_tx_head != NULL) {
+ cur_tx = sc->xl_cdata.xl_tx_head;
+
+ if (CSR_READ_4(sc, XL_DOWNLIST_PTR))
+ break;
+
+ sc->xl_cdata.xl_tx_head = cur_tx->xl_next;
+ m_freem(cur_tx->xl_mbuf);
+ cur_tx->xl_mbuf = NULL;
+ ifp->if_opackets++;
+
+ cur_tx->xl_next = sc->xl_cdata.xl_tx_free;
+ sc->xl_cdata.xl_tx_free = cur_tx;
+ }
+
+ if (sc->xl_cdata.xl_tx_head == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->xl_cdata.xl_tx_tail = NULL;
+ } else {
+ if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED ||
+ !CSR_READ_4(sc, XL_DOWNLIST_PTR)) {
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ }
+ }
+
+ return;
+}
+
+static void xl_txeof_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ idx = sc->xl_cdata.xl_tx_cons;
+ while(idx != sc->xl_cdata.xl_tx_prod) {
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE))
+ break;
+
+ if (cur_tx->xl_mbuf != NULL) {
+ m_freem(cur_tx->xl_mbuf);
+ cur_tx->xl_mbuf = NULL;
+ }
+
+ ifp->if_opackets++;
+
+ sc->xl_cdata.xl_tx_cnt--;
+ XL_INC(idx, XL_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->xl_cdata.xl_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+/*
+ * TX 'end of channel' interrupt handler. Actually, we should
+ * only get a 'TX complete' interrupt if there's a transmit error,
+ * so this is really TX error handler.
+ */
+static void xl_txeoc(sc)
+ struct xl_softc *sc;
+{
+ u_int8_t txstat;
+
+ while((txstat = CSR_READ_1(sc, XL_TX_STATUS))) {
+ if (txstat & XL_TXSTATUS_UNDERRUN ||
+ txstat & XL_TXSTATUS_JABBER ||
+ txstat & XL_TXSTATUS_RECLAIM) {
+ printf("xl%d: transmission error: %x\n",
+ sc->xl_unit, txstat);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+ if (sc->xl_type == XL_TYPE_905B) {
+ if (sc->xl_cdata.xl_tx_cnt) {
+ int i;
+ struct xl_chain *c;
+ i = sc->xl_cdata.xl_tx_cons;
+ c = &sc->xl_cdata.xl_tx_chain[i];
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ c->xl_phys);
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ }
+ } else {
+ if (sc->xl_cdata.xl_tx_head != NULL)
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
+ }
+ /*
+ * Remember to set this for the
+ * first generation 3c90X chips.
+ */
+ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
+ if (txstat & XL_TXSTATUS_UNDERRUN &&
+ sc->xl_tx_thresh < XL_PACKET_SIZE) {
+ sc->xl_tx_thresh += XL_MIN_FRAMELEN;
+ printf("xl%d: tx underrun, increasing tx start"
+ " threshold to %d bytes\n", sc->xl_unit,
+ sc->xl_tx_thresh);
+ }
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_TX_SET_START|sc->xl_tx_thresh);
+ if (sc->xl_type == XL_TYPE_905B) {
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ }
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ } else {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ }
+ /*
+ * Write an arbitrary byte to the TX_STATUS register
+ * to clear this interrupt/error and advance to the next.
+ */
+ CSR_WRITE_1(sc, XL_TX_STATUS, 0x01);
+ }
+
+ return;
+}
+
+static void xl_intr(arg)
+ void *arg;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t status;
+
+ sc = arg;
+ XL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ while((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS && status != 0xFFFF) {
+
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_INTR_ACK|(status & XL_INTRS));
+
+ if (status & XL_STAT_UP_COMPLETE) {
+ int curpkts;
+
+ curpkts = ifp->if_ipackets;
+ xl_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while (xl_rx_resync(sc))
+ xl_rxeof(sc);
+ }
+ }
+
+ if (status & XL_STAT_DOWN_COMPLETE) {
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_txeof_90xB(sc);
+ else
+ xl_txeof(sc);
+ }
+
+ if (status & XL_STAT_TX_COMPLETE) {
+ ifp->if_oerrors++;
+ xl_txeoc(sc);
+ }
+
+ if (status & XL_STAT_ADFAIL) {
+ xl_reset(sc);
+ xl_init(sc);
+ }
+
+ if (status & XL_STAT_STATSOFLOW) {
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc);
+ sc->xl_stats_no_timeout = 0;
+ }
+ }
+
+ if (ifp->if_snd.ifq_head != NULL)
+ (*ifp->if_start)(ifp);
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+static void xl_stats_update(xsc)
+ void *xsc;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+ struct xl_stats xl_stats;
+ u_int8_t *p;
+ int i;
+ struct mii_data *mii = NULL;
+
+ bzero((char *)&xl_stats, sizeof(struct xl_stats));
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+ if (sc->xl_miibus != NULL)
+ mii = device_get_softc(sc->xl_miibus);
+
+ p = (u_int8_t *)&xl_stats;
+
+ /* Read all the stats registers. */
+ XL_SEL_WIN(6);
+
+ for (i = 0; i < 16; i++)
+ *p++ = CSR_READ_1(sc, XL_W6_CARRIER_LOST + i);
+
+ ifp->if_ierrors += xl_stats.xl_rx_overrun;
+
+ ifp->if_collisions += xl_stats.xl_tx_multi_collision +
+ xl_stats.xl_tx_single_collision +
+ xl_stats.xl_tx_late_collision;
+
+ /*
+ * Boomerang and cyclone chips have an extra stats counter
+ * in window 4 (BadSSD). We have to read this too in order
+ * to clear out all the stats registers and avoid a statsoflow
+ * interrupt.
+ */
+ XL_SEL_WIN(4);
+ CSR_READ_1(sc, XL_W4_BADSSD);
+
+ if ((mii != NULL) && (!sc->xl_stats_no_timeout))
+ mii_tick(mii);
+
+ XL_SEL_WIN(7);
+
+ if (!sc->xl_stats_no_timeout)
+ sc->xl_stat_ch = timeout(xl_stats_update, sc, hz);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int xl_encap(sc, c, m_head)
+ struct xl_softc *sc;
+ struct xl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct xl_frag *f = NULL;
+ int total_len;
+ struct mbuf *m;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ total_len = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == XL_MAXFRAGS)
+ break;
+ total_len+= m->m_len;
+ c->xl_ptr->xl_frag[frag].xl_addr =
+ vtophys(mtod(m, vm_offset_t));
+ c->xl_ptr->xl_frag[frag].xl_len = m->m_len;
+ frag++;
+ }
+ }
+
+ /*
+ * Handle special case: we used up all 63 fragments,
+ * but we have more mbufs left in the chain. Copy the
+ * data into an mbuf cluster. Note that we don't
+ * bother clearing the values in the other fragment
+ * pointers/counters; it wouldn't gain us anything,
+ * and would waste cycles.
+ */
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("xl%d: no memory for tx list", sc->xl_unit);
+ return(1);
+ }
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ printf("xl%d: no memory for tx list",
+ sc->xl_unit);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ f = &c->xl_ptr->xl_frag[0];
+ f->xl_addr = vtophys(mtod(m_new, caddr_t));
+ f->xl_len = total_len = m_new->m_len;
+ frag = 1;
+ }
+
+ c->xl_mbuf = m_head;
+ c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
+ c->xl_ptr->xl_status = total_len;
+ c->xl_ptr->xl_next = 0;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+static void xl_start(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+
+ sc = ifp->if_softc;
+ XL_LOCK(sc);
+ /*
+ * Check for an available queue slot. If there are none,
+ * punt.
+ */
+ if (sc->xl_cdata.xl_tx_free == NULL) {
+ xl_txeoc(sc);
+ xl_txeof(sc);
+ if (sc->xl_cdata.xl_tx_free == NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ XL_UNLOCK(sc);
+ return;
+ }
+ }
+
+ start_tx = sc->xl_cdata.xl_tx_free;
+
+ while(sc->xl_cdata.xl_tx_free != NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /* Pick a descriptor off the free list. */
+ cur_tx = sc->xl_cdata.xl_tx_free;
+ sc->xl_cdata.xl_tx_free = cur_tx->xl_next;
+
+ cur_tx->xl_next = NULL;
+
+ /* Pack the data into the descriptor. */
+ xl_encap(sc, cur_tx, m_head);
+
+ /* Chain it together. */
+ if (prev != NULL) {
+ prev->xl_next = cur_tx;
+ prev->xl_ptr->xl_next = vtophys(cur_tx->xl_ptr);
+ }
+ prev = cur_tx;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->xl_mbuf);
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL) {
+ XL_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
+
+ /*
+ * Queue the packets. If the TX channel is clear, update
+ * the downlist pointer register.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+
+ if (sc->xl_cdata.xl_tx_head != NULL) {
+ sc->xl_cdata.xl_tx_tail->xl_next = start_tx;
+ sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next =
+ vtophys(start_tx->xl_ptr);
+ sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &=
+ ~XL_TXSTAT_DL_INTR;
+ sc->xl_cdata.xl_tx_tail = cur_tx;
+ } else {
+ sc->xl_cdata.xl_tx_head = start_tx;
+ sc->xl_cdata.xl_tx_tail = cur_tx;
+ }
+ if (!CSR_READ_4(sc, XL_DOWNLIST_PTR))
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR, vtophys(start_tx->xl_ptr));
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+
+ XL_SEL_WIN(7);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ /*
+ * XXX Under certain conditions, usually on slower machines
+ * where interrupts may be dropped, it's possible for the
+ * adapter to chew up all the buffers in the receive ring
+ * and stall, without us being able to do anything about it.
+ * To guard against this, we need to make a pass over the
+ * RX queue to make sure there aren't any packets pending.
+ * Doing it here means we can flush the receive ring at the
+ * same time the chip is DMAing the transmit descriptors we
+ * just gave it.
+ *
+ * 3Com goes to some lengths to emphasize the Parallel Tasking (tm)
+ * nature of their chips in all their marketing literature;
+ * we may as well take advantage of it. :)
+ */
+ xl_rxeof(sc);
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+static int xl_encap_90xB(sc, c, m_head)
+ struct xl_softc *sc;
+ struct xl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct xl_frag *f = NULL;
+ struct mbuf *m;
+ struct xl_list *d;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ d = c->xl_ptr;
+ d->xl_status = 0;
+ d->xl_next = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == XL_MAXFRAGS)
+ break;
+ f = &d->xl_frag[frag];
+ f->xl_addr = vtophys(mtod(m, vm_offset_t));
+ f->xl_len = m->m_len;
+ frag++;
+ }
+ }
+
+ c->xl_mbuf = m_head;
+ c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
+ c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT;
+
+ if (m_head->m_pkthdr.csum_flags) {
+ if (m_head->m_pkthdr.csum_flags & CSUM_IP)
+ c->xl_ptr->xl_status |= XL_TXSTAT_IPCKSUM;
+ if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
+ c->xl_ptr->xl_status |= XL_TXSTAT_TCPCKSUM;
+ if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
+ c->xl_ptr->xl_status |= XL_TXSTAT_UDPCKSUM;
+ }
+ return(0);
+}
+
+static void xl_start_90xB(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+ int idx;
+
+ sc = ifp->if_softc;
+ XL_LOCK(sc);
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ XL_UNLOCK(sc);
+ return;
+ }
+
+ idx = sc->xl_cdata.xl_tx_prod;
+ start_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ while (sc->xl_cdata.xl_tx_chain[idx].xl_mbuf == NULL) {
+
+ if ((XL_TX_LIST_CNT - sc->xl_cdata.xl_tx_cnt) < 3) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ /* Pack the data into the descriptor. */
+ xl_encap_90xB(sc, cur_tx, m_head);
+
+ /* Chain it together. */
+ if (prev != NULL)
+ prev->xl_ptr->xl_next = cur_tx->xl_phys;
+ prev = cur_tx;
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->xl_mbuf);
+
+ XL_INC(idx, XL_TX_LIST_CNT);
+ sc->xl_cdata.xl_tx_cnt++;
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL) {
+ XL_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
+
+ /* Start transmission */
+ sc->xl_cdata.xl_tx_prod = idx;
+ start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+static void xl_init(xsc)
+ void *xsc;
+{
+ struct xl_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i;
+ u_int16_t rxfilt = 0;
+ struct mii_data *mii = NULL;
+
+ XL_LOCK(sc);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ xl_stop(sc);
+
+ if (sc->xl_miibus == NULL) {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ }
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+ DELAY(10000);
+
+ if (sc->xl_miibus != NULL)
+ mii = device_get_softc(sc->xl_miibus);
+
+ /* Init our MAC address */
+ XL_SEL_WIN(2);
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ CSR_WRITE_1(sc, XL_W2_STATION_ADDR_LO + i,
+ sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Clear the station mask. */
+ for (i = 0; i < 3; i++)
+ CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0);
+#ifdef notdef
+ /* Reset TX and RX. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+#endif
+ /* Init circular RX list. */
+ if (xl_list_rx_init(sc) == ENOBUFS) {
+ printf("xl%d: initialization failed: no "
+ "memory for rx buffers\n", sc->xl_unit);
+ xl_stop(sc);
+ XL_UNLOCK(sc);
+ return;
+ }
+
+ /* Init TX descriptors. */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_list_tx_init_90xB(sc);
+ else
+ xl_list_tx_init(sc);
+
+ /*
+ * Set the TX freethresh value.
+ * Note that this has no effect on 3c905B "cyclone"
+ * cards but is required for 3c900/3c905 "boomerang"
+ * cards in order to enable the download engine.
+ */
+ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
+
+ /* Set the TX start threshold for best performance. */
+ sc->xl_tx_thresh = XL_MIN_FRAMELEN;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_SET_START|sc->xl_tx_thresh);
+
+ /*
+ * If this is a 3c905B, also set the tx reclaim threshold.
+ * This helps cut down on the number of tx reclaim errors
+ * that could happen on a busy network. The chip multiplies
+ * the register value by 16 to obtain the actual threshold
+ * in bytes, so we divide by 16 when setting the value here.
+ * The existing threshold value can be examined by reading
+ * the register at offset 9 in window 5.
+ */
+ if (sc->xl_type == XL_TYPE_905B) {
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ }
+
+ /* Set RX filter bits. */
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ /* Set the individual bit to receive frames for this host only. */
+ rxfilt |= XL_RXFILTER_INDIVIDUAL;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ rxfilt |= XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_setmulti_hash(sc);
+ else
+ xl_setmulti(sc);
+
+ /*
+ * Load the address of the RX list. We have to
+ * stall the upload engine before we can manipulate
+ * the uplist pointer register, then unstall it when
+ * we're finished. We also have to wait for the
+ * stall command to complete before proceeding.
+ * Note that we have to do this after any RX resets
+ * have completed since the uplist register is cleared
+ * by a reset.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0]));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ xl_wait(sc);
+
+
+ if (sc->xl_type == XL_TYPE_905B) {
+ /* Set polling interval */
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ /* Load the address of the TX list */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(&sc->xl_ldata->xl_tx_list[0]));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ xl_wait(sc);
+ }
+
+ /*
+ * If the coax transceiver is on, make sure to enable
+ * the DC-DC converter.
+ */
+ XL_SEL_WIN(3);
+ if (sc->xl_xcvr == XL_XCVR_COAX)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+
+ /* increase packet size to allow reception of 802.1q or ISL packets */
+ if (sc->xl_type == XL_TYPE_905B)
+ CSR_WRITE_2(sc, XL_W3_MAXPKTSIZE, XL_PACKET_SIZE);
+ /* Clear out the stats counters. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc);
+ sc->xl_stats_no_timeout = 0;
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_NET_DIAG, XL_NETDIAG_UPPER_BYTES_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_ENABLE);
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
+ if (sc->xl_flags & XL_FLAG_FUNCREG)
+ bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, 4, 0x8000);
+
+ /* Set the RX early threshold */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2));
+ CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY);
+
+ /* Enable receiver and transmitter. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
+ xl_wait(sc);
+
+ if (mii != NULL)
+ mii_mediachg(mii);
+
+ /* Select window 7 for normal operations. */
+ XL_SEL_WIN(7);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->xl_stat_ch = timeout(xl_stats_update, sc, hz);
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int xl_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct ifmedia *ifm = NULL;
+ struct mii_data *mii = NULL;
+
+ sc = ifp->if_softc;
+ if (sc->xl_miibus != NULL)
+ mii = device_get_softc(sc->xl_miibus);
+ if (mii == NULL)
+ ifm = &sc->ifmedia;
+ else
+ ifm = &mii->mii_media;
+
+ switch(IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_100_FX:
+ case IFM_10_FL:
+ case IFM_10_2:
+ case IFM_10_5:
+ xl_setmode(sc, ifm->ifm_media);
+ return(0);
+ break;
+ default:
+ break;
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX
+ || sc->xl_media & XL_MEDIAOPT_BT4) {
+ xl_init(sc);
+ } else {
+ xl_setmode(sc, ifm->ifm_media);
+ }
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void xl_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct xl_softc *sc;
+ u_int32_t icfg;
+ struct mii_data *mii = NULL;
+
+ sc = ifp->if_softc;
+ if (sc->xl_miibus != NULL)
+ mii = device_get_softc(sc->xl_miibus);
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG) & XL_ICFG_CONNECTOR_MASK;
+ icfg >>= XL_ICFG_CONNECTOR_BITS;
+
+ ifmr->ifm_active = IFM_ETHER;
+
+ switch(icfg) {
+ case XL_XCVR_10BT:
+ ifmr->ifm_active = IFM_ETHER|IFM_10_T;
+ if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ break;
+ case XL_XCVR_AUI:
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ ifmr->ifm_active = IFM_ETHER|IFM_10_FL;
+ if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ } else
+ ifmr->ifm_active = IFM_ETHER|IFM_10_5;
+ break;
+ case XL_XCVR_COAX:
+ ifmr->ifm_active = IFM_ETHER|IFM_10_2;
+ break;
+ /*
+ * XXX MII and BTX/AUTO should be separate cases.
+ */
+
+ case XL_XCVR_100BTX:
+ case XL_XCVR_AUTO:
+ case XL_XCVR_MII:
+ if (mii != NULL) {
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ }
+ break;
+ case XL_XCVR_100BFX:
+ ifmr->ifm_active = IFM_ETHER|IFM_100_FX;
+ break;
+ default:
+ printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit, icfg);
+ break;
+ }
+
+ return;
+}
+
+static int xl_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct xl_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0;
+ struct mii_data *mii = NULL;
+ u_int8_t rxfilt;
+
+ XL_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->xl_if_flags & IFF_PROMISC)) {
+ rxfilt |= XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_RX_SET_FILT|rxfilt);
+ XL_SEL_WIN(7);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->xl_if_flags & IFF_PROMISC) {
+ rxfilt &= ~XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_RX_SET_FILT|rxfilt);
+ XL_SEL_WIN(7);
+ } else
+ xl_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ xl_stop(sc);
+ }
+ sc->xl_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_setmulti_hash(sc);
+ else
+ xl_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ if (sc->xl_miibus != NULL)
+ mii = device_get_softc(sc->xl_miibus);
+ if (mii == NULL)
+ error = ifmedia_ioctl(ifp, ifr,
+ &sc->ifmedia, command);
+ else
+ error = ifmedia_ioctl(ifp, ifr,
+ &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ XL_UNLOCK(sc);
+
+ return(error);
+}
+
+static void xl_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ u_int16_t status = 0;
+
+ sc = ifp->if_softc;
+
+ XL_LOCK(sc);
+
+ ifp->if_oerrors++;
+ XL_SEL_WIN(4);
+ status = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
+ printf("xl%d: watchdog timeout\n", sc->xl_unit);
+
+ if (status & XL_MEDIASTAT_CARRIER)
+ printf("xl%d: no carrier - transceiver cable problem?\n",
+ sc->xl_unit);
+ xl_txeoc(sc);
+ xl_txeof(sc);
+ xl_rxeof(sc);
+ xl_reset(sc);
+ xl_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ (*ifp->if_start)(ifp);
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void xl_stop(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ XL_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ DELAY(800);
+
+#ifdef foo
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+#endif
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
+ if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4 (sc->xl_ftag, sc->xl_fhandle, 4, 0x8000);
+
+ /* Stop the stats updater. */
+ untimeout(xl_stats_update, sc, sc->xl_stat_ch);
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ if (sc->xl_cdata.xl_rx_chain[i].xl_mbuf != NULL) {
+ m_freem(sc->xl_cdata.xl_rx_chain[i].xl_mbuf);
+ sc->xl_cdata.xl_rx_chain[i].xl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->xl_ldata->xl_rx_list,
+ sizeof(sc->xl_ldata->xl_rx_list));
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ if (sc->xl_cdata.xl_tx_chain[i].xl_mbuf != NULL) {
+ m_freem(sc->xl_cdata.xl_tx_chain[i].xl_mbuf);
+ sc->xl_cdata.xl_tx_chain[i].xl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->xl_ldata->xl_tx_list,
+ sizeof(sc->xl_ldata->xl_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void xl_shutdown(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ XL_LOCK(sc);
+ xl_reset(sc);
+ xl_stop(sc);
+ XL_UNLOCK(sc);
+
+ return;
+}
+
+static int xl_suspend(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ XL_LOCK(sc);
+ xl_stop(sc);
+ XL_UNLOCK(sc);
+
+ return(0);
+}
+
+static int xl_resume(dev)
+ device_t dev;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ XL_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ xl_reset(sc);
+ if (ifp->if_flags & IFF_UP)
+ xl_init(sc);
+
+ XL_UNLOCK(sc);
+ return(0);
+}
diff --git a/sys/pci/if_xlreg.h b/sys/pci/if_xlreg.h
new file mode 100644
index 0000000..5e1b920
--- /dev/null
+++ b/sys/pci/if_xlreg.h
@@ -0,0 +1,720 @@
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#define XL_EE_READ 0x0080 /* read, 5 bit address */
+#define XL_EE_WRITE 0x0040 /* write, 5 bit address */
+#define XL_EE_ERASE 0x00c0 /* erase, 5 bit address */
+#define XL_EE_EWEN 0x0030 /* erase, no data needed */
+#define XL_EE_8BIT_READ 0x0200 /* read, 8 bit address */
+#define XL_EE_BUSY 0x8000
+
+#define XL_EE_EADDR0 0x00 /* station address, first word */
+#define XL_EE_EADDR1 0x01 /* station address, next word, */
+#define XL_EE_EADDR2 0x02 /* station address, last word */
+#define XL_EE_PRODID 0x03 /* product ID code */
+#define XL_EE_MDATA_DATE 0x04 /* manufacturing data, date */
+#define XL_EE_MDATA_DIV 0x05 /* manufacturing data, division */
+#define XL_EE_MDATA_PCODE 0x06 /* manufacturing data, product code */
+#define XL_EE_MFG_ID 0x07
+#define XL_EE_PCI_PARM 0x08
+#define XL_EE_ROM_ONFO 0x09
+#define XL_EE_OEM_ADR0 0x0A
+#define XL_EE_OEM_ADR1 0x0B
+#define XL_EE_OEM_ADR2 0x0C
+#define XL_EE_SOFTINFO1 0x0D
+#define XL_EE_COMPAT 0x0E
+#define XL_EE_SOFTINFO2 0x0F
+#define XL_EE_CAPS 0x10 /* capabilities word */
+#define XL_EE_RSVD0 0x11
+#define XL_EE_ICFG_0 0x12
+#define XL_EE_ICFG_1 0x13
+#define XL_EE_RSVD1 0x14
+#define XL_EE_SOFTINFO3 0x15
+#define XL_EE_RSVD_2 0x16
+
+/*
+ * Bits in the capabilities word
+ */
+#define XL_CAPS_PNP 0x0001
+#define XL_CAPS_FULL_DUPLEX 0x0002
+#define XL_CAPS_LARGE_PKTS 0x0004
+#define XL_CAPS_SLAVE_DMA 0x0008
+#define XL_CAPS_SECOND_DMA 0x0010
+#define XL_CAPS_FULL_BM 0x0020
+#define XL_CAPS_FRAG_BM 0x0040
+#define XL_CAPS_CRC_PASSTHRU 0x0080
+#define XL_CAPS_TXDONE 0x0100
+#define XL_CAPS_NO_TXLENGTH 0x0200
+#define XL_CAPS_RX_REPEAT 0x0400
+#define XL_CAPS_SNOOPING 0x0800
+#define XL_CAPS_100MBPS 0x1000
+#define XL_CAPS_PWRMGMT 0x2000
+
+#define XL_PACKET_SIZE 1540
+
+/*
+ * Register layouts.
+ */
+#define XL_COMMAND 0x0E
+#define XL_STATUS 0x0E
+
+#define XL_TX_STATUS 0x1B
+#define XL_TX_FREE 0x1C
+#define XL_DMACTL 0x20
+#define XL_DOWNLIST_PTR 0x24
+#define XL_DOWN_POLL 0x2D /* 3c90xB only */
+#define XL_TX_FREETHRESH 0x2F
+#define XL_UPLIST_PTR 0x38
+#define XL_UPLIST_STATUS 0x30
+#define XL_UP_POLL 0x3D /* 3c90xB only */
+
+#define XL_PKTSTAT_UP_STALLED 0x00002000
+#define XL_PKTSTAT_UP_ERROR 0x00004000
+#define XL_PKTSTAT_UP_CMPLT 0x00008000
+
+#define XL_DMACTL_DN_CMPLT_REQ 0x00000002
+#define XL_DMACTL_DOWN_STALLED 0x00000004
+#define XL_DMACTL_UP_CMPLT 0x00000008
+#define XL_DMACTL_DOWN_CMPLT 0x00000010
+#define XL_DMACTL_UP_RX_EARLY 0x00000020
+#define XL_DMACTL_ARM_COUNTDOWN 0x00000040
+#define XL_DMACTL_DOWN_INPROG 0x00000080
+#define XL_DMACTL_COUNTER_SPEED 0x00000100
+#define XL_DMACTL_DOWNDOWN_MODE 0x00000200
+#define XL_DMACTL_TARGET_ABORT 0x40000000
+#define XL_DMACTL_MASTER_ABORT 0x80000000
+
+/*
+ * Command codes. Some command codes require that we wait for
+ * the CMD_BUSY flag to clear. Those codes are marked as 'mustwait.'
+ */
+#define XL_CMD_RESET 0x0000 /* mustwait */
+#define XL_CMD_WINSEL 0x0800
+#define XL_CMD_COAX_START 0x1000
+#define XL_CMD_RX_DISABLE 0x1800
+#define XL_CMD_RX_ENABLE 0x2000
+#define XL_CMD_RX_RESET 0x2800 /* mustwait */
+#define XL_CMD_UP_STALL 0x3000 /* mustwait */
+#define XL_CMD_UP_UNSTALL 0x3001
+#define XL_CMD_DOWN_STALL 0x3002 /* mustwait */
+#define XL_CMD_DOWN_UNSTALL 0x3003
+#define XL_CMD_RX_DISCARD 0x4000
+#define XL_CMD_TX_ENABLE 0x4800
+#define XL_CMD_TX_DISABLE 0x5000
+#define XL_CMD_TX_RESET 0x5800 /* mustwait */
+#define XL_CMD_INTR_FAKE 0x6000
+#define XL_CMD_INTR_ACK 0x6800
+#define XL_CMD_INTR_ENB 0x7000
+#define XL_CMD_STAT_ENB 0x7800
+#define XL_CMD_RX_SET_FILT 0x8000
+#define XL_CMD_RX_SET_THRESH 0x8800
+#define XL_CMD_TX_SET_THRESH 0x9000
+#define XL_CMD_TX_SET_START 0x9800
+#define XL_CMD_DMA_UP 0xA000
+#define XL_CMD_DMA_STOP 0xA001
+#define XL_CMD_STATS_ENABLE 0xA800
+#define XL_CMD_STATS_DISABLE 0xB000
+#define XL_CMD_COAX_STOP 0xB800
+
+#define XL_CMD_SET_TX_RECLAIM 0xC000 /* 3c905B only */
+#define XL_CMD_RX_SET_HASH 0xC800 /* 3c905B only */
+
+#define XL_HASH_SET 0x0400
+#define XL_HASHFILT_SIZE 256
+
+/*
+ * status codes
+ * Note that bits 15 to 13 indicate the currently visible register window
+ * which may be anything from 0 to 7.
+ */
+#define XL_STAT_INTLATCH 0x0001 /* 0 */
+#define XL_STAT_ADFAIL 0x0002 /* 1 */
+#define XL_STAT_TX_COMPLETE 0x0004 /* 2 */
+#define XL_STAT_TX_AVAIL 0x0008 /* 3 first generation */
+#define XL_STAT_RX_COMPLETE 0x0010 /* 4 */
+#define XL_STAT_RX_EARLY 0x0020 /* 5 */
+#define XL_STAT_INTREQ 0x0040 /* 6 */
+#define XL_STAT_STATSOFLOW 0x0080 /* 7 */
+#define XL_STAT_DMADONE 0x0100 /* 8 first generation */
+#define XL_STAT_LINKSTAT 0x0100 /* 8 3c509B */
+#define XL_STAT_DOWN_COMPLETE 0x0200 /* 9 */
+#define XL_STAT_UP_COMPLETE 0x0400 /* 10 */
+#define XL_STAT_DMABUSY 0x0800 /* 11 first generation */
+#define XL_STAT_CMDBUSY 0x1000 /* 12 */
+
+/*
+ * Interrupts we normally want enabled.
+ */
+#define XL_INTRS \
+ (XL_STAT_UP_COMPLETE|XL_STAT_STATSOFLOW|XL_STAT_ADFAIL| \
+ XL_STAT_DOWN_COMPLETE|XL_STAT_TX_COMPLETE|XL_STAT_INTLATCH)
+
+/*
+ * Window 0 registers
+ */
+#define XL_W0_EE_DATA 0x0C
+#define XL_W0_EE_CMD 0x0A
+#define XL_W0_RSRC_CFG 0x08
+#define XL_W0_ADDR_CFG 0x06
+#define XL_W0_CFG_CTRL 0x04
+
+#define XL_W0_PROD_ID 0x02
+#define XL_W0_MFG_ID 0x00
+
+/*
+ * Window 1
+ */
+
+#define XL_W1_TX_FIFO 0x10
+
+#define XL_W1_FREE_TX 0x0C
+#define XL_W1_TX_STATUS 0x0B
+#define XL_W1_TX_TIMER 0x0A
+#define XL_W1_RX_STATUS 0x08
+#define XL_W1_RX_FIFO 0x00
+
+/*
+ * RX status codes
+ */
+#define XL_RXSTATUS_OVERRUN 0x01
+#define XL_RXSTATUS_RUNT 0x02
+#define XL_RXSTATUS_ALIGN 0x04
+#define XL_RXSTATUS_CRC 0x08
+#define XL_RXSTATUS_OVERSIZE 0x10
+#define XL_RXSTATUS_DRIBBLE 0x20
+
+/*
+ * TX status codes
+ */
+#define XL_TXSTATUS_RECLAIM 0x02 /* 3c905B only */
+#define XL_TXSTATUS_OVERFLOW 0x04
+#define XL_TXSTATUS_MAXCOLS 0x08
+#define XL_TXSTATUS_UNDERRUN 0x10
+#define XL_TXSTATUS_JABBER 0x20
+#define XL_TXSTATUS_INTREQ 0x40
+#define XL_TXSTATUS_COMPLETE 0x80
+
+/*
+ * Window 2
+ */
+#define XL_W2_RESET_OPTIONS 0x0C /* 3c905B only */
+#define XL_W2_STATION_MASK_HI 0x0A
+#define XL_W2_STATION_MASK_MID 0x08
+#define XL_W2_STATION_MASK_LO 0x06
+#define XL_W2_STATION_ADDR_HI 0x04
+#define XL_W2_STATION_ADDR_MID 0x02
+#define XL_W2_STATION_ADDR_LO 0x00
+
+#define XL_RESETOPT_FEATUREMASK 0x0001|0x0002|0x004
+#define XL_RESETOPT_D3RESETDIS 0x0008
+#define XL_RESETOPT_DISADVFD 0x0010
+#define XL_RESETOPT_DISADV100 0x0020
+#define XL_RESETOPT_DISAUTONEG 0x0040
+#define XL_RESETOPT_DEBUGMODE 0x0080
+#define XL_RESETOPT_FASTAUTO 0x0100
+#define XL_RESETOPT_FASTEE 0x0200
+#define XL_RESETOPT_FORCEDCONF 0x0400
+#define XL_RESETOPT_TESTPDTPDR 0x0800
+#define XL_RESETOPT_TEST100TX 0x1000
+#define XL_RESETOPT_TEST100RX 0x2000
+
+#define XL_RESETOPT_INVERT_LED 0x0010
+#define XL_RESETOPT_INVERT_MII 0x4000
+
+/*
+ * Window 3 (fifo management)
+ */
+#define XL_W3_INTERNAL_CFG 0x00
+#define XL_W3_MAXPKTSIZE 0x04 /* 3c905B only */
+#define XL_W3_RESET_OPT 0x08
+#define XL_W3_FREE_TX 0x0C
+#define XL_W3_FREE_RX 0x0A
+#define XL_W3_MAC_CTRL 0x06
+
+#define XL_ICFG_CONNECTOR_MASK 0x00F00000
+#define XL_ICFG_CONNECTOR_BITS 20
+
+#define XL_ICFG_RAMSIZE_MASK 0x00000007
+#define XL_ICFG_RAMWIDTH 0x00000008
+#define XL_ICFG_ROMSIZE_MASK (0x00000040|0x00000080)
+#define XL_ICFG_DISABLE_BASSD 0x00000100
+#define XL_ICFG_RAMLOC 0x00000200
+#define XL_ICFG_RAMPART (0x00010000|0x00020000)
+#define XL_ICFG_XCVRSEL (0x00100000|0x00200000|0x00400000)
+#define XL_ICFG_AUTOSEL 0x01000000
+
+#define XL_XCVR_10BT 0x00
+#define XL_XCVR_AUI 0x01
+#define XL_XCVR_RSVD_0 0x02
+#define XL_XCVR_COAX 0x03
+#define XL_XCVR_100BTX 0x04
+#define XL_XCVR_100BFX 0x05
+#define XL_XCVR_MII 0x06
+#define XL_XCVR_RSVD_1 0x07
+#define XL_XCVR_AUTO 0x08 /* 3c905B only */
+
+#define XL_MACCTRL_DEFER_EXT_END 0x0001
+#define XL_MACCTRL_DEFER_0 0x0002
+#define XL_MACCTRL_DEFER_1 0x0004
+#define XL_MACCTRL_DEFER_2 0x0008
+#define XL_MACCTRL_DEFER_3 0x0010
+#define XL_MACCTRL_DUPLEX 0x0020
+#define XL_MACCTRL_ALLOW_LARGE_PACK 0x0040
+#define XL_MACCTRL_EXTEND_AFTER_COL 0x0080 (3c905B only)
+#define XL_MACCTRL_FLOW_CONTROL_ENB 0x0100 (3c905B only)
+#define XL_MACCTRL_VLT_END 0x0200 (3c905B only)
+
+/*
+ * The 'reset options' register contains power-on reset values
+ * loaded from the EEPROM. This includes the supported media
+ * types on the card. It is also known as the media options register.
+ */
+#define XL_W3_MEDIA_OPT 0x08
+
+#define XL_MEDIAOPT_BT4 0x0001 /* MII */
+#define XL_MEDIAOPT_BTX 0x0002 /* on-chip */
+#define XL_MEDIAOPT_BFX 0x0004 /* on-chip */
+#define XL_MEDIAOPT_BT 0x0008 /* on-chip */
+#define XL_MEDIAOPT_BNC 0x0010 /* on-chip */
+#define XL_MEDIAOPT_AUI 0x0020 /* on-chip */
+#define XL_MEDIAOPT_MII 0x0040 /* MII */
+#define XL_MEDIAOPT_VCO 0x0100 /* 1st gen chip only */
+
+#define XL_MEDIAOPT_10FL 0x0100 /* 3x905B only, on-chip */
+#define XL_MEDIAOPT_MASK 0x01FF
+
+/*
+ * Window 4 (diagnostics)
+ */
+#define XL_W4_UPPERBYTESOK 0x0D
+#define XL_W4_BADSSD 0x0C
+#define XL_W4_MEDIA_STATUS 0x0A
+#define XL_W4_PHY_MGMT 0x08
+#define XL_W4_NET_DIAG 0x06
+#define XL_W4_FIFO_DIAG 0x04
+#define XL_W4_VCO_DIAG 0x02
+
+#define XL_W4_CTRLR_STAT 0x08
+#define XL_W4_TX_DIAG 0x00
+
+#define XL_MII_CLK 0x01
+#define XL_MII_DATA 0x02
+#define XL_MII_DIR 0x04
+
+#define XL_MEDIA_SQE 0x0008
+#define XL_MEDIA_10TP 0x00C0
+#define XL_MEDIA_LNK 0x0080
+#define XL_MEDIA_LNKBEAT 0x0800
+
+#define XL_MEDIASTAT_CRCSTRIP 0x0004
+#define XL_MEDIASTAT_SQEENB 0x0008
+#define XL_MEDIASTAT_COLDET 0x0010
+#define XL_MEDIASTAT_CARRIER 0x0020
+#define XL_MEDIASTAT_JABGUARD 0x0040
+#define XL_MEDIASTAT_LINKBEAT 0x0080
+#define XL_MEDIASTAT_JABDETECT 0x0200
+#define XL_MEDIASTAT_POLREVERS 0x0400
+#define XL_MEDIASTAT_LINKDETECT 0x0800
+#define XL_MEDIASTAT_TXINPROG 0x1000
+#define XL_MEDIASTAT_DCENB 0x4000
+#define XL_MEDIASTAT_AUIDIS 0x8000
+
+#define XL_NETDIAG_TEST_LOWVOLT 0x0001
+#define XL_NETDIAG_ASIC_REVMASK (0x0002|0x0004|0x0008|0x0010|0x0020)
+#define XL_NETDIAG_UPPER_BYTES_ENABLE 0x0040
+#define XL_NETDIAG_STATS_ENABLED 0x0080
+#define XL_NETDIAG_TX_FATALERR 0x0100
+#define XL_NETDIAG_TRANSMITTING 0x0200
+#define XL_NETDIAG_RX_ENABLED 0x0400
+#define XL_NETDIAG_TX_ENABLED 0x0800
+#define XL_NETDIAG_FIFO_LOOPBACK 0x1000
+#define XL_NETDIAG_MAC_LOOPBACK 0x2000
+#define XL_NETDIAG_ENDEC_LOOPBACK 0x4000
+#define XL_NETDIAG_EXTERNAL_LOOP 0x8000
+
+/*
+ * Window 5
+ */
+#define XL_W5_STAT_ENB 0x0C
+#define XL_W5_INTR_ENB 0x0A
+#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */
+#define XL_W5_RX_FILTER 0x08
+#define XL_W5_RX_EARLYTHRESH 0x06
+#define XL_W5_TX_AVAILTHRESH 0x02
+#define XL_W5_TX_STARTTHRESH 0x00
+
+/*
+ * RX filter bits
+ */
+#define XL_RXFILTER_INDIVIDUAL 0x01
+#define XL_RXFILTER_ALLMULTI 0x02
+#define XL_RXFILTER_BROADCAST 0x04
+#define XL_RXFILTER_ALLFRAMES 0x08
+#define XL_RXFILTER_MULTIHASH 0x10 /* 3c905B only */
+
+/*
+ * Window 6 (stats)
+ */
+#define XL_W6_TX_BYTES_OK 0x0C
+#define XL_W6_RX_BYTES_OK 0x0A
+#define XL_W6_UPPER_FRAMES_OK 0x09
+#define XL_W6_DEFERRED 0x08
+#define XL_W6_RX_OK 0x07
+#define XL_W6_TX_OK 0x06
+#define XL_W6_RX_OVERRUN 0x05
+#define XL_W6_COL_LATE 0x04
+#define XL_W6_COL_SINGLE 0x03
+#define XL_W6_COL_MULTIPLE 0x02
+#define XL_W6_SQE_ERRORS 0x01
+#define XL_W6_CARRIER_LOST 0x00
+
+/*
+ * Window 7 (bus master control)
+ */
+#define XL_W7_BM_ADDR 0x00
+#define XL_W7_BM_LEN 0x06
+#define XL_W7_BM_STATUS 0x0B
+#define XL_W7_BM_TIMEr 0x0A
+
+/*
+ * bus master control registers
+ */
+#define XL_BM_PKTSTAT 0x20
+#define XL_BM_DOWNLISTPTR 0x24
+#define XL_BM_FRAGADDR 0x28
+#define XL_BM_FRAGLEN 0x2C
+#define XL_BM_TXFREETHRESH 0x2F
+#define XL_BM_UPPKTSTAT 0x30
+#define XL_BM_UPLISTPTR 0x38
+
+#define XL_LAST_FRAG 0x80000000
+
+/*
+ * Boomerang/Cyclone TX/RX list structure.
+ * For the TX lists, bits 0 to 12 of the status word indicate
+ * length.
+ * This looks suspiciously like the ThunderLAN, doesn't it.
+ */
+struct xl_frag {
+ u_int32_t xl_addr; /* 63 addr/len pairs */
+ u_int32_t xl_len;
+};
+
+struct xl_list {
+ u_int32_t xl_next; /* final entry has 0 nextptr */
+ u_int32_t xl_status;
+ struct xl_frag xl_frag[63];
+};
+
+struct xl_list_onefrag {
+ u_int32_t xl_next; /* final entry has 0 nextptr */
+ u_int32_t xl_status;
+ struct xl_frag xl_frag;
+};
+
+#define XL_MAXFRAGS 63
+#define XL_RX_LIST_CNT 128
+#define XL_TX_LIST_CNT 256
+#define XL_MIN_FRAMELEN 60
+#define ETHER_ALIGN 2
+#define XL_INC(x, y) (x) = (x + 1) % y
+
+struct xl_list_data {
+ struct xl_list_onefrag xl_rx_list[XL_RX_LIST_CNT];
+ struct xl_list xl_tx_list[XL_TX_LIST_CNT];
+ unsigned char xl_pad[XL_MIN_FRAMELEN];
+};
+
+struct xl_chain {
+ struct xl_list *xl_ptr;
+ struct mbuf *xl_mbuf;
+ struct xl_chain *xl_next;
+ struct xl_chain *xl_prev;
+ u_int32_t xl_phys;
+};
+
+struct xl_chain_onefrag {
+ struct xl_list_onefrag *xl_ptr;
+ struct mbuf *xl_mbuf;
+ struct xl_chain_onefrag *xl_next;
+};
+
+struct xl_chain_data {
+ struct xl_chain_onefrag xl_rx_chain[XL_RX_LIST_CNT];
+ struct xl_chain xl_tx_chain[XL_TX_LIST_CNT];
+
+ struct xl_chain_onefrag *xl_rx_head;
+
+ /* 3c90x "boomerang" queuing stuff */
+ struct xl_chain *xl_tx_head;
+ struct xl_chain *xl_tx_tail;
+ struct xl_chain *xl_tx_free;
+
+ /* 3c90xB "cyclone/hurricane/tornado" stuff */
+ int xl_tx_prod;
+ int xl_tx_cons;
+ int xl_tx_cnt;
+};
+
+#define XL_RXSTAT_LENMASK 0x00001FFF
+#define XL_RXSTAT_UP_ERROR 0x00004000
+#define XL_RXSTAT_UP_CMPLT 0x00008000
+#define XL_RXSTAT_UP_OVERRUN 0x00010000
+#define XL_RXSTAT_RUNT 0x00020000
+#define XL_RXSTAT_ALIGN 0x00040000
+#define XL_RXSTAT_CRC 0x00080000
+#define XL_RXSTAT_OVERSIZE 0x00100000
+#define XL_RXSTAT_DRIBBLE 0x00800000
+#define XL_RXSTAT_UP_OFLOW 0x01000000
+#define XL_RXSTAT_IPCKERR 0x02000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCKERR 0x04000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKERR 0x08000000 /* 3c905B only */
+#define XL_RXSTAT_BUFEN 0x10000000 /* 3c905B only */
+#define XL_RXSTAT_IPCKOK 0x20000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCOK 0x40000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKOK 0x80000000 /* 3c905B only */
+
+#define XL_TXSTAT_LENMASK 0x00001FFF
+#define XL_TXSTAT_CRCDIS 0x00002000
+#define XL_TXSTAT_TX_INTR 0x00008000
+#define XL_TXSTAT_DL_COMPLETE 0x00010000
+#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */
+#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */
+#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */
+#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */
+#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */
+#define XL_TXSTAT_DL_INTR 0x80000000
+
+#define XL_CAPABILITY_BM 0x20
+
+struct xl_type {
+ u_int16_t xl_vid;
+ u_int16_t xl_did;
+ char *xl_name;
+};
+
+struct xl_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define XL_MII_STARTDELIM 0x01
+#define XL_MII_READOP 0x02
+#define XL_MII_WRITEOP 0x01
+#define XL_MII_TURNAROUND 0x02
+
+/*
+ * The 3C905B adapters implement a few features that we want to
+ * take advantage of, namely the multicast hash filter. With older
+ * chips, you only have the option of turning on reception of all
+ * multicast frames, which is kind of lame.
+ *
+ * We also use this to decide on a transmit strategy. For the 3c90xB
+ * cards, we can use polled descriptor mode, which reduces CPU overhead.
+ */
+#define XL_TYPE_905B 1
+#define XL_TYPE_90X 2
+
+#define XL_FLAG_FUNCREG 0x0001
+#define XL_FLAG_PHYOK 0x0002
+#define XL_FLAG_EEPROM_OFFSET_30 0x0004
+#define XL_FLAG_WEIRDRESET 0x0008
+#define XL_FLAG_8BITROM 0x0010
+#define XL_FLAG_INVERT_LED_PWR 0x0020
+#define XL_FLAG_INVERT_MII_PWR 0x0040
+
+struct xl_softc {
+ struct arpcom arpcom; /* interface info */
+ struct ifmedia ifmedia; /* media info */
+ bus_space_handle_t xl_bhandle;
+ bus_space_tag_t xl_btag;
+ void *xl_intrhand;
+ struct resource *xl_irq;
+ struct resource *xl_res;
+ device_t xl_miibus;
+ struct xl_type *xl_info; /* 3Com adapter info */
+ u_int8_t xl_unit; /* interface number */
+ u_int8_t xl_type;
+ u_int32_t xl_xcvr;
+ u_int16_t xl_media;
+ u_int16_t xl_caps;
+ u_int8_t xl_stats_no_timeout;
+ u_int16_t xl_tx_thresh;
+ int xl_if_flags;
+ struct xl_list_data *xl_ldata;
+ struct xl_chain_data xl_cdata;
+ struct callout_handle xl_stat_ch;
+ int xl_flags;
+ struct resource *xl_fres;
+ bus_space_handle_t xl_fhandle;
+ bus_space_tag_t xl_ftag;
+ struct mtx xl_mtx;
+};
+
+#define XL_LOCK(_sc) mtx_lock(&(_sc)->xl_mtx)
+#define XL_UNLOCK(_sc) mtx_unlock(&(_sc)->xl_mtx)
+
+#define xl_rx_goodframes(x) \
+ ((x.xl_upper_frames_ok & 0x03) << 8) | x.xl_rx_frames_ok
+
+#define xl_tx_goodframes(x) \
+ ((x.xl_upper_frames_ok & 0x30) << 4) | x.xl_tx_frames_ok
+
+struct xl_stats {
+ u_int8_t xl_carrier_lost;
+ u_int8_t xl_sqe_errs;
+ u_int8_t xl_tx_multi_collision;
+ u_int8_t xl_tx_single_collision;
+ u_int8_t xl_tx_late_collision;
+ u_int8_t xl_rx_overrun;
+ u_int8_t xl_tx_frames_ok;
+ u_int8_t xl_rx_frames_ok;
+ u_int8_t xl_tx_deferred;
+ u_int8_t xl_upper_frames_ok;
+ u_int16_t xl_rx_bytes_ok;
+ u_int16_t xl_tx_bytes_ok;
+ u_int16_t status;
+};
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->xl_btag, sc->xl_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->xl_btag, sc->xl_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->xl_btag, sc->xl_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->xl_btag, sc->xl_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->xl_btag, sc->xl_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->xl_btag, sc->xl_bhandle, reg)
+
+#define XL_SEL_WIN(x) \
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)
+#define XL_TIMEOUT 1000
+
+/*
+ * General constants that are fun to know.
+ *
+ * 3Com PCI vendor ID
+ */
+#define TC_VENDORID 0x10B7
+
+/*
+ * 3Com chip device IDs.
+ */
+#define TC_DEVICEID_BOOMERANG_10BT 0x9000
+#define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001
+#define TC_DEVICEID_BOOMERANG_10_100BT 0x9050
+#define TC_DEVICEID_BOOMERANG_100BT4 0x9051
+#define TC_DEVICEID_KRAKATOA_10BT 0x9004
+#define TC_DEVICEID_KRAKATOA_10BT_COMBO 0x9005
+#define TC_DEVICEID_KRAKATOA_10BT_TPC 0x9006
+#define TC_DEVICEID_CYCLONE_10FL 0x900A
+#define TC_DEVICEID_HURRICANE_10_100BT 0x9055
+#define TC_DEVICEID_CYCLONE_10_100BT4 0x9056
+#define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058
+#define TC_DEVICEID_CYCLONE_10_100FX 0x905A
+#define TC_DEVICEID_TORNADO_10_100BT 0x9200
+#define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800
+#define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805
+#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646
+#define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500
+#define TC_DEVICEID_HURRICANE_556 0x6055
+#define TC_DEVICEID_HURRICANE_556B 0x6056
+#define TC_DEVICEID_HURRICANE_575A 0x5057
+#define TC_DEVICEID_HURRICANE_575B 0x5157
+#define TC_DEVICEID_HURRICANE_575C 0x5257
+#define TC_DEVICEID_HURRICANE_656 0x6560
+#define TC_DEVICEID_HURRICANE_656B 0x6562
+#define TC_DEVICEID_TORNADO_656C 0x6564
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers. Note: some are only available on
+ * the 3c905B, in particular those that related to power management.
+ */
+
+#define XL_PCI_VENDOR_ID 0x00
+#define XL_PCI_DEVICE_ID 0x02
+#define XL_PCI_COMMAND 0x04
+#define XL_PCI_STATUS 0x06
+#define XL_PCI_CLASSCODE 0x09
+#define XL_PCI_LATENCY_TIMER 0x0D
+#define XL_PCI_HEADER_TYPE 0x0E
+#define XL_PCI_LOIO 0x10
+#define XL_PCI_LOMEM 0x14
+#define XL_PCI_FUNCMEM 0x18
+#define XL_PCI_BIOSROM 0x30
+#define XL_PCI_INTLINE 0x3C
+#define XL_PCI_INTPIN 0x3D
+#define XL_PCI_MINGNT 0x3E
+#define XL_PCI_MINLAT 0x0F
+#define XL_PCI_RESETOPT 0x48
+#define XL_PCI_EEPROM_DATA 0x4C
+
+/* 3c905B-only registers */
+#define XL_PCI_CAPID 0xDC /* 8 bits */
+#define XL_PCI_NEXTPTR 0xDD /* 8 bits */
+#define XL_PCI_PWRMGMTCAP 0xDE /* 16 bits */
+#define XL_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
+
+#define XL_PSTATE_MASK 0x0003
+#define XL_PSTATE_D0 0x0000
+#define XL_PSTATE_D1 0x0002
+#define XL_PSTATE_D2 0x0002
+#define XL_PSTATE_D3 0x0003
+#define XL_PME_EN 0x0010
+#define XL_PME_STATUS 0x8000
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+
+#endif
+
+#ifndef IFM_10_FL
+#define IFM_10_FL 13 /* 10baseFL - Fiber */
+#endif
diff --git a/sys/pci/intpm.c b/sys/pci/intpm.c
new file mode 100644
index 0000000..747f192
--- /dev/null
+++ b/sys/pci/intpm.c
@@ -0,0 +1,752 @@
+/*-
+ * Copyright (c) 1998, 1999 Takanori Watanabe
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+
+#include <sys/uio.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <dev/smbus/smbconf.h>
+
+#include "smbus_if.h"
+
+/*This should be removed if force_pci_map_int supported*/
+#include <sys/interrupt.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#include <pci/intpmreg.h>
+
+#include "opt_intpm.h"
+
+static struct _pcsid
+{
+ u_int32_t type;
+ char *desc;
+} pci_ids[] =
+{
+ { 0x71138086,"Intel 82371AB Power management controller"},
+ { 0x719b8086,"Intel 82443MX Power management controller"},
+#if 0
+ /* Not a good idea yet, this stops isab0 functioning */
+ { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"},
+#endif
+
+ { 0x00000000, NULL }
+};
+static int intsmb_probe(device_t);
+static int intsmb_attach(device_t);
+
+static int intsmb_intr(device_t dev);
+static int intsmb_slvintr(device_t dev);
+static void intsmb_alrintr(device_t dev);
+static int intsmb_callback(device_t dev, int index, caddr_t data);
+static int intsmb_quick(device_t dev, u_char slave, int how);
+static int intsmb_sendb(device_t dev, u_char slave, char byte);
+static int intsmb_recvb(device_t dev, u_char slave, char *byte);
+static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
+static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
+static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
+static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
+static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
+static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
+static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
+static void intsmb_start(device_t dev,u_char cmd,int nointr);
+static int intsmb_stop(device_t dev);
+static int intsmb_stop_poll(device_t dev);
+static int intsmb_free(device_t dev);
+static int intpm_probe (device_t dev);
+static int intpm_attach (device_t dev);
+static devclass_t intsmb_devclass;
+
+static device_method_t intpm_methods[]={
+ DEVMETHOD(device_probe,intsmb_probe),
+ DEVMETHOD(device_attach,intsmb_attach),
+
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ DEVMETHOD(smbus_callback,intsmb_callback),
+ DEVMETHOD(smbus_quick,intsmb_quick),
+ DEVMETHOD(smbus_sendb,intsmb_sendb),
+ DEVMETHOD(smbus_recvb,intsmb_recvb),
+ DEVMETHOD(smbus_writeb,intsmb_writeb),
+ DEVMETHOD(smbus_writew,intsmb_writew),
+ DEVMETHOD(smbus_readb,intsmb_readb),
+ DEVMETHOD(smbus_readw,intsmb_readw),
+ DEVMETHOD(smbus_pcall,intsmb_pcall),
+ DEVMETHOD(smbus_bwrite,intsmb_bwrite),
+ DEVMETHOD(smbus_bread,intsmb_bread),
+ {0,0}
+};
+
+struct intpm_pci_softc{
+ bus_space_tag_t smbst;
+ bus_space_handle_t smbsh;
+ bus_space_tag_t pmst;
+ bus_space_handle_t pmsh;
+ device_t smbus;
+};
+
+
+struct intsmb_softc{
+ struct intpm_pci_softc *pci_sc;
+ bus_space_tag_t st;
+ bus_space_handle_t sh;
+ device_t smbus;
+ int isbusy;
+};
+
+static driver_t intpm_driver = {
+ "intsmb",
+ intpm_methods,
+ sizeof(struct intsmb_softc),
+};
+
+static devclass_t intpm_devclass;
+static device_method_t intpm_pci_methods[] = {
+ DEVMETHOD(device_probe,intpm_probe),
+ DEVMETHOD(device_attach,intpm_attach),
+ {0,0}
+};
+static driver_t intpm_pci_driver = {
+ "intpm",
+ intpm_pci_methods,
+ sizeof(struct intpm_pci_softc)
+};
+
+static int
+intsmb_probe(device_t dev)
+{
+ struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
+ sc->smbus=device_add_child(dev, "smbus", -1);
+ if (!sc->smbus)
+ return (EINVAL); /* XXX don't know what to return else */
+ device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
+
+ return (0); /* XXX don't know what to return else */
+}
+static int
+intsmb_attach(device_t dev)
+{
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ sc->pci_sc=device_get_softc(device_get_parent(dev));
+ sc->isbusy=0;
+ sc->sh=sc->pci_sc->smbsh;
+ sc->st=sc->pci_sc->smbst;
+ sc->pci_sc->smbus=dev;
+ device_probe_and_attach(sc->smbus);
+#ifdef ENABLE_ALART
+ /*Enable Arart*/
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
+ PIIX4_SMBSLVCNT_ALTEN);
+#endif
+ return (0);
+}
+
+static int
+intsmb_callback(device_t dev, int index, caddr_t data)
+{
+ int error = 0;
+ intrmask_t s;
+ s=splnet();
+ switch (index) {
+ case SMB_REQUEST_BUS:
+ break;
+ case SMB_RELEASE_BUS:
+ break;
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+/*counterpart of smbtx_smb_free*/
+static int
+intsmb_free(device_t dev){
+ intrmask_t s;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
+ PIIX4_SMBHSTSTAT_BUSY)
+#ifdef ENABLE_ALART
+ ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
+ PIIX4_SMBSLVSTS_BUSY)
+#endif
+ || sc->isbusy)
+ return EBUSY;
+ s=splhigh();
+ sc->isbusy=1;
+ /*Disable Intrrupt in slave part*/
+#ifndef ENABLE_ALART
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
+#endif
+ /*Reset INTR Flag to prepare INTR*/
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
+ (PIIX4_SMBHSTSTAT_INTR|
+ PIIX4_SMBHSTSTAT_ERR|
+ PIIX4_SMBHSTSTAT_BUSC|
+ PIIX4_SMBHSTSTAT_FAIL)
+ );
+ splx(s);
+ return 0;
+}
+
+static int
+intsmb_intr(device_t dev)
+{
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ int status;
+ status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
+ if(status&PIIX4_SMBHSTSTAT_BUSY){
+ return 1;
+
+ }
+ if(status&(PIIX4_SMBHSTSTAT_INTR|
+ PIIX4_SMBHSTSTAT_ERR|
+ PIIX4_SMBHSTSTAT_BUSC|
+ PIIX4_SMBHSTSTAT_FAIL)){
+ int tmp;
+ tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
+ tmp&~PIIX4_SMBHSTCNT_INTREN);
+ if(sc->isbusy){
+ sc->isbusy=0;
+ wakeup(sc);
+ }
+ return 0;
+ }
+ return 1;/* Not Completed*/
+}
+static int
+intsmb_slvintr(device_t dev)
+{
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ int status,retval;
+ retval=1;
+ status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
+ if(status&PIIX4_SMBSLVSTS_BUSY)
+ return retval;
+ if(status&PIIX4_SMBSLVSTS_ALART){
+ intsmb_alrintr(dev);
+ retval=0;
+ }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
+ |PIIX4_SMBSLVSTS_SDW1)){
+ retval=0;
+ }
+ /*Reset Status Register*/
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
+ PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
+ PIIX4_SMBSLVSTS_SLV);
+ return retval;
+}
+
+static void intsmb_alrintr(device_t dev)
+{
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ int slvcnt;
+#ifdef ENABLE_ALART
+ int error;
+#endif
+
+ /*stop generating INTR from ALART*/
+ slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
+#ifdef ENABLE_ALART
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
+ slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
+#endif
+ DELAY(5);
+ /*ask bus who assert it and then ask it what's the matter. */
+#ifdef ENABLE_ALART
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
+ |LSB);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
+ if(!(error=intsmb_stop_poll(dev))){
+ u_int8_t addr;
+ addr=bus_space_read_1(sc->st,sc->sh,
+ PIIX4_SMBHSTDAT0);
+ printf("ALART_RESPONSE: 0x%x\n", addr);
+ }
+ }else{
+ printf("ERROR\n");
+ }
+
+ /*Re-enable INTR from ALART*/
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
+ slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
+ DELAY(5);
+#endif
+
+ return;
+}
+static void
+intsmb_start(device_t dev,unsigned char cmd,int nointr)
+{
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ unsigned char tmp;
+ tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
+ tmp&= 0xe0;
+ tmp |= cmd;
+ tmp |=PIIX4_SMBHSTCNT_START;
+ /*While not in autoconfiguration Intrrupt Enabled*/
+ if(!cold||!nointr)
+ tmp |=PIIX4_SMBHSTCNT_INTREN;
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
+}
+
+/*Polling Code. Polling is not encouraged
+ * because It is required to wait for the device get busy.
+ *(29063505.pdf from Intel)
+ * But during boot,intrrupt cannot be used.
+ * so use polling code while in autoconfiguration.
+ */
+
+static int
+intsmb_stop_poll(device_t dev){
+ int error,i;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+
+ /*
+ * In smbtx driver ,Simply waiting.
+ * This loops 100-200 times.
+ */
+ for(i=0;i<0x7fff;i++){
+ if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
+ &PIIX4_SMBHSTSTAT_BUSY)){
+ break;
+ }
+ }
+ for(i=0;i<0x7fff;i++){
+ int status;
+ status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
+ if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
+ sc->isbusy=0;
+ error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
+ (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
+ (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
+ if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
+ printf("unknown cause why?");
+ }
+ return error;
+ }
+ }
+ {
+ int tmp;
+ sc->isbusy=0;
+ tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
+ tmp&~PIIX4_SMBHSTCNT_INTREN);
+ }
+ return EIO;
+}
+/*
+ *wait for completion and return result.
+ */
+static int
+intsmb_stop(device_t dev){
+ int error;
+ intrmask_t s;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ if(cold){
+ /*So that it can use device during probing device on SMBus.*/
+ error=intsmb_stop_poll(dev);
+ return error;
+ }else{
+ if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
+ int status;
+ status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
+ if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
+ error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
+ (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
+ (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
+ if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
+ printf("intsmb%d:unknown cause why?\n",
+ device_get_unit(dev));
+ }
+#ifdef ENABLE_ALART
+ bus_space_write_1(sc->st,sc->sh,
+ PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
+#endif
+ return error;
+ }
+ }
+ }
+ /*Timeout Procedure*/
+ s=splhigh();
+ sc->isbusy=0;
+ /*Re-enable supressed intrrupt from slave part*/
+ bus_space_write_1(sc->st,sc->sh,
+ PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
+ splx(s);
+ return EIO;
+}
+
+static int
+intsmb_quick(device_t dev, u_char slave, int how)
+{
+ int error=0;
+ u_char data;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ data=slave;
+ /*Quick command is part of Address, I think*/
+ switch(how){
+ case SMB_QWRITE:
+ data&=~LSB;
+ break;
+ case SMB_QREAD:
+ data|=LSB;
+ break;
+ default:
+ error=EINVAL;
+ }
+ if(!error){
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,
+ PIIX4_SMBHSTADD,data);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
+ error=intsmb_stop(dev);
+ }
+ }
+
+ return (error);
+}
+
+static int
+intsmb_sendb(device_t dev, u_char slave, char byte)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
+ error=intsmb_stop(dev);
+ }
+ return (error);
+}
+static int
+intsmb_recvb(device_t dev, u_char slave, char *byte)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
+ |LSB);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
+ if(!(error=intsmb_stop(dev))){
+#ifdef RECV_IS_IN_CMD
+ /*Linux SMBus stuff also troubles
+ Because Intel's datasheet will not make clear.
+ */
+ *byte=bus_space_read_1(sc->st,sc->sh,
+ PIIX4_SMBHSTCMD);
+#else
+ *byte=bus_space_read_1(sc->st,sc->sh,
+ PIIX4_SMBHSTDAT0);
+#endif
+ }
+ }
+ return (error);
+}
+static int
+intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
+ error=intsmb_stop(dev);
+ }
+ return (error);
+}
+static int
+intsmb_writew(device_t dev, u_char slave, char cmd, short word)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
+ word&0xff);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
+ (word>>8)&0xff);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
+ error=intsmb_stop(dev);
+ }
+ return (error);
+}
+
+static int
+intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
+ if(!(error=intsmb_stop(dev))){
+ *byte=bus_space_read_1(sc->st,sc->sh,
+ PIIX4_SMBHSTDAT0);
+ }
+ }
+ return (error);
+}
+static int
+intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
+ if(!(error=intsmb_stop(dev))){
+ *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
+ *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
+ }
+ }
+ return (error);
+}
+/*
+ * Data sheet claims that it implements all function, but also claims
+ * that it implements 7 function and not mention PCALL. So I don't know
+ * whether it will work.
+ */
+static int
+intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
+{
+#ifdef PROCCALL_TEST
+ int error;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(!error){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
+ }
+ if(!(error=intsmb_stop(dev))){
+ *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
+ *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
+ }
+ return error;
+#else
+ return 0;
+#endif
+}
+static int
+intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ int error,i;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(count>SMBBLOCKTRANS_MAX||count==0)
+ error=EINVAL;
+ if(!error){
+ /*Reset internal array index*/
+ bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
+
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ for(i=0;i<count;i++){
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
+ }
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
+ error=intsmb_stop(dev);
+ }
+ return (error);
+}
+
+static int
+intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ int error,i;
+ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
+ error=intsmb_free(dev);
+ if(count>SMBBLOCKTRANS_MAX||count==0)
+ error=EINVAL;
+ if(!error){
+ /*Reset internal array index*/
+ bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
+
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
+ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
+ intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
+ error=intsmb_stop(dev);
+ if(!error){
+ bzero(buf,count);/*Is it needed?*/
+ count= bus_space_read_1(sc->st,sc->sh,
+ PIIX4_SMBHSTDAT0);
+ if(count!=0&&count<=SMBBLOCKTRANS_MAX){
+ for(i=0;i<count;i++){
+ buf[i]=bus_space_read_1(sc->st,
+ sc->sh,
+ PIIX4_SMBBLKDAT);
+ }
+ }
+ else{
+ error=EIO;
+ }
+ }
+ }
+ return (error);
+}
+
+DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
+
+
+static void intpm_intr(void *arg);
+static int
+intpm_attach(device_t dev)
+{
+ int value;
+ int unit=device_get_unit(dev);
+ void *ih;
+ int error;
+ char * str;
+ {
+ struct intpm_pci_softc *sciic;
+ device_t smbinterface;
+ int rid;
+ struct resource *res;
+
+ sciic=device_get_softc(dev);
+ if(sciic==NULL){
+ return ENOMEM;
+ }
+
+ rid=PCI_BASE_ADDR_SMB;
+ res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
+ 0,~0,1,RF_ACTIVE);
+ if(res==NULL){
+ device_printf(dev,"Could not allocate Bus space\n");
+ return ENXIO;
+ }
+ sciic->smbst=rman_get_bustag(res);
+ sciic->smbsh=rman_get_bushandle(res);
+
+ device_printf(dev,"%s %x\n",
+ (sciic->smbst==I386_BUS_SPACE_IO)?
+ "I/O mapped":"Memory",
+ sciic->smbsh);
+
+
+#ifndef NO_CHANGE_PCICONF
+ pci_write_config(dev,PCIR_INTLINE,0x9,1);
+ pci_write_config(dev,PCI_HST_CFG_SMB,
+ PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
+#endif
+ value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
+ switch(value&0xe){
+ case PCI_INTR_SMB_SMI:
+ str="SMI";
+ break;
+ case PCI_INTR_SMB_IRQ9:
+ str="IRQ 9";
+ break;
+ default:
+ str="BOGUS";
+ }
+ device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
+ value=pci_read_config(dev,PCI_REVID_SMB,1);
+ printf("revision %d\n",value);
+ /*
+ * Install intr HANDLER here
+ */
+ rid=0;
+ res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
+ if(res==NULL){
+ device_printf(dev,"could not allocate irq");
+ return ENOMEM;
+ }
+ error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
+ if(error){
+ device_printf(dev,"Failed to map intr\n");
+ return error;
+ }
+ smbinterface=device_add_child(dev,"intsmb",unit);
+ if(!smbinterface){
+ printf("intsmb%d:could not add SMBus device\n",unit);
+ }
+ device_probe_and_attach(smbinterface);
+ }
+
+ value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
+ printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
+ return 0;
+}
+static int
+intpm_probe(device_t dev)
+{
+ struct _pcsid *ep =pci_ids;
+ u_int32_t device_id=pci_get_devid(dev);
+
+ while (ep->type && ep->type != device_id)
+ ++ep;
+ if(ep->desc!=NULL){
+ device_set_desc(dev,ep->desc);
+ bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */
+ return 0;
+ }else{
+ return ENXIO;
+ }
+}
+DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
+MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(intpm, 1);
+
+static void intpm_intr(void *arg)
+{
+ struct intpm_pci_softc *sc;
+ sc=(struct intpm_pci_softc *)arg;
+ intsmb_intr(sc->smbus);
+ intsmb_slvintr(sc->smbus);
+
+}
diff --git a/sys/pci/intpmreg.h b/sys/pci/intpmreg.h
new file mode 100644
index 0000000..73816e7
--- /dev/null
+++ b/sys/pci/intpmreg.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1998, 1999 Takanori Watanabe
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*Register Difinition for Intel Chipset with ACPI Support*/
+#define PCI_BASE_ADDR_SMB 0x90 /*Where to MAP IO*/
+#define PCI_BASE_ADDR_PM 0x40
+#define PCI_HST_CFG_SMB 0xd2 /*Host Configuration*/
+#define PCI_INTR_SMB_SMI 0
+#define PCI_INTR_SMB_IRQ9 8
+#define PCI_INTR_SMB_ENABLE 1
+#define PCI_SLV_CMD_SMB 0xd3 /*SLAVE COMMAND*/
+#define PCI_SLV_SDW_SMB_1 0xd4 /*SLAVE SHADOW PORT 1*/
+#define PCI_SLV_SDW_SMB_2 0xd5 /*SLAVE SHADOW PORT 2*/
+#define PCI_REVID_SMB 0xd6
+#define LSB 0x1
+#define PIIX4_SMBHSTSTS 0x00
+#define PIIX4_SMBHSTSTAT_BUSY (1<<0)
+#define PIIX4_SMBHSTSTAT_INTR (1<<1)
+#define PIIX4_SMBHSTSTAT_ERR (1<<2)
+#define PIIX4_SMBHSTSTAT_BUSC (1<<3)
+#define PIIX4_SMBHSTSTAT_FAIL (1<<4)
+#define PIIX4_SMBSLVSTS 0x01
+#define PIIX4_SMBSLVSTS_ALART (1<<5)
+#define PIIX4_SMBSLVSTS_SDW2 (1<<4)
+#define PIIX4_SMBSLVSTS_SDW1 (1<<3)
+#define PIIX4_SMBSLVSTS_SLV (1<<2)
+#define PIIX4_SMBSLVSTS_BUSY (1<<0)
+#define PIIX4_SMBHSTCNT 0x02
+#define PIIX4_SMBHSTCNT_START (1<<6)
+#define PIIX4_SMBHSTCNT_PROT_QUICK 0
+#define PIIX4_SMBHSTCNT_PROT_BYTE (1<<2)
+#define PIIX4_SMBHSTCNT_PROT_BDATA (2<<2)
+#define PIIX4_SMBHSTCNT_PROT_WDATA (3<<2)
+#define PIIX4_SMBHSTCNT_PROT_BLOCK (5<<2)
+#define SMBBLOCKTRANS_MAX 32
+#define PIIX4_SMBHSTCNT_KILL (1<<1)
+#define PIIX4_SMBHSTCNT_INTREN (1)
+#define PIIX4_SMBHSTCMD 0x03
+#define PIIX4_SMBHSTADD 0x04
+#define PIIX4_SMBHSTDAT0 0x05
+#define PIIX4_SMBHSTDAT1 0x06
+#define PIIX4_SMBBLKDAT 0x07
+#define PIIX4_SMBSLVCNT 0x08
+#define PIIX4_SMBSLVCNT_ALTEN (1<<3)
+#define PIIX4_SMBSLVCNT_SD2EN (1<<2)
+#define PIIX4_SMBSLVCNT_SD1EN (1<<1)
+#define PIIX4_SMBSLVCNT_SLVEN (1)
+#define PIIX4_SMBSLVCMD 0x09
+#define PIIX4_SMBSLVEVT 0x0a
+#define PIIX4_SMBSLVDAT 0x0c
+/*This is SMBus alart response address*/
+#define SMBALTRESP 0x18
diff --git a/sys/pci/locate.pl b/sys/pci/locate.pl
new file mode 100755
index 0000000..89688e1
--- /dev/null
+++ b/sys/pci/locate.pl
@@ -0,0 +1,45 @@
+#!/usr/bin/perl -w
+# $FreeBSD$
+
+use strict;
+
+if (!defined($ARGV[0])) {
+ print(
+"
+Perl script to convert NCR script address into label+offset.
+Useful to find the failed NCR instruction ...
+
+usage: $0 <address>
+");
+ exit(1);
+}
+
+my $errpos = hex($ARGV[0])/4;
+my $ofs=0;
+
+open (INPUT, "cc -E ncr.c 2>/dev/null |");
+
+while ($_ = <INPUT>)
+{
+ last if /^struct script \{/;
+}
+
+while ($_ = <INPUT>)
+{
+ last if /^\}\;/;
+ my ($label, $size) = /ncrcmd\s+(\S+)\s+\[([^]]+)/;
+ $size = eval($size);
+ if (defined($label) && $label) {
+ if ($errpos) {
+ if ($ofs + $size > $errpos) {
+ printf ("%4x: %s\n", $ofs * 4, $label);
+ printf ("%4x: %s + %d\n", $errpos * 4, $label, $errpos - $ofs);
+ last;
+ }
+ $ofs += $size;
+ } else {
+ printf ("%4x: %s\n", $ofs * 4, $label);
+ }
+ }
+}
+
diff --git a/sys/pci/meteor.c b/sys/pci/meteor.c
new file mode 100644
index 0000000..340c709
--- /dev/null
+++ b/sys/pci/meteor.c
@@ -0,0 +1,2131 @@
+/*
+ * Copyright (c) 1995 Mark Tinguely and Jim Lowe
+ * 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 Mark Tinguely and Jim Lowe
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Change History:
+ 8/21/95 Release
+ 8/23/95 On advice from Stefan Esser, added volatile to PCI
+ memory pointers to remove PCI caching .
+ 8/29/95 Fixes suggested by Bruce Evans.
+ meteor_mmap should return -1 on error rather than 0.
+ unit # > NMETEOR should be unit # >= NMETEOR.
+ 10/24/95 Turn 50 Hz processing for SECAM and 60 Hz processing
+ off for AUTOMODE.
+ 11/11/95 Change UV from always begin signed to ioctl selected
+ to either signed or unsigned.
+ 12/07/95 Changed 7196 startup codes for 50 Hz as recommended
+ by Luigi Rizzo (luigi@iet.unipi.it)
+ 12/08/95 Clear SECAM bit in PAL/NTSC and set input field count
+ bits for 50 Hz mode (PAL/SECAM) before I was setting the
+ output count bits. by Luigi Rizzo (luigi@iet.unipi.it)
+ 12/18/95 Correct odd DMA field (never exceed, but good for safety
+ Changed 7196 startup codes for 50 Hz as recommended
+ by Luigi Rizzo (luigi@iet.unipi.it)
+ 12/19/95 Changed field toggle mode to enable (offset 0x3c)
+ recommended by luigi@iet.unipi.it
+ Added in prototyping, include file, staticizing,
+ and DEVFS changes from FreeBSD team.
+ Changed the default allocated pages from 151 (NTSC)
+ to 217 (PAL).
+ Cleaned up some old comments in iic_write().
+ Added a Field (even or odd) only capture mode to
+ eliminate the high frequency problems with compression
+ algorithms. Recommended by luigi@iet.unipi.it.
+ Changed geometry ioctl so if it couldn't allocated a
+ large enough contiguous space, it wouldn't free the
+ stuff it already had.
+ Added new mode called YUV_422 which delivers the
+ data in planer Y followed by U followed by V. This
+ differs from the standard YUV_PACKED mode in that
+ the chrominance (UV) data is in the correct (different)
+ order. This is for programs like vic and mpeg_encode
+ so they don't have to reorder the chrominance data.
+ Added field count to stats.
+ Increment frame count stat if capturing continuous on
+ even frame grabs.
+ Added my email address to these comments
+ (james@cs.uwm.edu) suggested by (luigi@iet.unipt.it :-).
+ Changed the user mode signal mechanism to allow the
+ user program to be interrupted at the end of a frame
+ in any one of the modes. Added SSIGNAL ioctl.
+ Added a SFPS/GFPS ioctl so one may set the frames per
+ second that the card catpures. This code needs to be
+ completed.
+ Changed the interrupt routine so synchronous capture
+ will work on fields or frames and the starting frame
+ can be either even or odd.
+ Added HALT_N_FRAMES and CONT_N_FRAMES so one could
+ stop and continue synchronous capture mode.
+ Change the tsleep/wakeup function to wait on mtr
+ rather than &read_intr_wait.
+ 1/22/96 Add option (METEOR_FreeBSD_210) for FreeBSD 2.1
+ to compile.
+ Changed intr so it only printed errors every 50 times.
+ Added unit number to error messages.
+ Added get_meteor_mem and enabled range checking.
+ 1/30/96 Added prelim test stuff for direct video dma transfers
+ from Amancio Hasty (hasty@rah.star-gate.com). Until
+ we get some stuff sorted out, this will be ifdef'ed
+ with METEOR_DIRECT_VIDEO. This is very dangerous to
+ use at present since we don't check the address that
+ is passed by the user!!!!!
+ 2/26/96 Added special SVIDEO input device type.
+ 2/27/96 Added meteor_reg.h file and associate types Converted
+ meteor.c over to using meteor.h file. Prompted by
+ Lars Jonas Olsson <ljo@po.cwru.edu>.
+ 2/28/96 Added meteor RGB code from Lars Jonas Olsson
+ <ljo@po.cwru.edu>. I make some mods to this code, so
+ I hope it still works as I don't have an rgb card to
+ test with.
+ 2/29/96 <ljo@po.cwru.edu> tested the meteor RGB and supplied
+ me with diffs. Thanks, we now have a working RGB
+ version of the driver. Still need to clean up this
+ code.
+ 3/1/96 Fixed a nasty little bug that was clearing the VTR
+ mode bit when the 7196 status was requested.
+ 3/15/96 Fixed bug introduced in previous version that
+ stopped the only fields mode from working.
+ Added METEOR{GS}TS ioctl, still needs work.
+ 3/25/96 Added YUV_9 and YUV_12 modes. Cleaned up some of the
+ code and converted variables to use the new register
+ types.
+ 4/8/96 Fixed the a bug in with the range enable. Pointed
+ out by Jim Bray.
+ 5/13/96 Fix the FPS ioctl so it actually sets the frames
+ per second. Code supplied by ian@robots.ox.ac.uk.
+ The new code implements a new define:
+ METEOR_SYSTEM_DEFAULT which should be defined as
+ METEOR_PAL, METEOR_SECAM, or METEOR_NTSC in your system
+ configuration file. If METEOR_SYSTEM_DEFAULT isn't
+ defined, and there is not a signal when set_fps is
+ called, then the call has no effect.
+ Changed the spelling of PLANER to PLANAR as pointed
+ out by Paco Hope <paco@cs.virigina.edu> and define
+ PLANER to be PLANAR for backward compatibility.
+ 5/28/95 METEOR_INPUT_DEV_RCA -> METEOR_INPUT_DEV0, not
+ METEOR_GEO_DEV0. Pointed out by Ian Reid,
+ <ian@robots.ox.ac.uk>.
+ METEOR_DEV_MASK should be 0x0000f000 and not
+ 0x2000f000, otherwise METEOR_RGB gets masked
+ out. Pointed out by Ian Reid.
+ Changed the fps code to give even distribution for
+ low frame rates. Code supplied by Ian Reid.
+ Fix some problems with the RGB version. Patch supplied
+ by <ljo@po.cwru.edu>.
+ Added METEOR_FIELD_MODE to include files for a
+ future version of this driver.
+*/
+
+#ifdef COMPILING_LINT
+#warning "The meteor driver is broken and is not compiled with LINT"
+#else
+
+#include "meteor.h"
+
+#include "opt_meteor.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#if defined(METEOR_FreeBSD_210)
+#include <machine/cpu.h> /* bootverbose */
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <machine/ioctl_meteor.h>
+#include <pci/meteor_reg.h>
+
+#ifndef COMPAT_OLDPCI
+#error "The meteor device requires the old pci compatibility shims"
+#endif
+
+static void meteor_intr(void *arg);
+
+/*
+ * Allocate enough memory for:
+ * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages
+ *
+ * You may override this using the options "METEOR_ALLOC_PAGES=value" in your
+ * kernel configuration file.
+ */
+#ifndef METEOR_ALLOC_PAGES
+#define METEOR_ALLOC_PAGES 217
+#endif
+#define METEOR_ALLOC (METEOR_ALLOC_PAGES * PAGE_SIZE)
+
+static meteor_reg_t meteor[NMETEOR];
+#define METEOR_NUM(mtr) ((mtr - &meteor[0])/sizeof(meteor_reg_t))
+
+#define METPRI (PZERO+8)|PCATCH
+
+static const char* met_probe (pcici_t tag, pcidi_t type);
+static void met_attach(pcici_t tag, int unit);
+static u_long met_count;
+
+static struct pci_device met_device = {
+ "meteor",
+ met_probe,
+ met_attach,
+ &met_count
+};
+
+COMPAT_PCI_DRIVER (meteor, met_device);
+
+#if defined(METEOR_FreeBSD_210) /* XXX */
+d_open_t meteor_open;
+d_close_t meteor_close;
+d_read_t meteor_read;
+d_write_t meteor_write;
+d_ioctl_t meteor_ioctl;
+d_mmap_t meteor_mmap;
+#else
+static d_open_t meteor_open;
+static d_close_t meteor_close;
+static d_read_t meteor_read;
+static d_write_t meteor_write;
+static d_ioctl_t meteor_ioctl;
+static d_mmap_t meteor_mmap;
+
+#define CDEV_MAJOR 67
+static struct cdevsw meteor_cdevsw = {
+ /* open */ meteor_open,
+ /* close */ meteor_close,
+ /* read */ meteor_read,
+ /* write */ meteor_write,
+ /* ioctl */ meteor_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ meteor_mmap,
+ /* strategy */ nostrategy,
+ /* name */ "meteor",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+};
+#endif
+
+static mreg_t saa7116_pci_default[sizeof(struct saa7116_regs)/sizeof(mreg_t)]={
+ /* PCI Memory registers */
+ /* BITS Type Description */
+/* 0x00 */ 0x00000000, /* 31:1 e*RW DMA 1 (Even)
+ 0 RO 0x0 */
+/* 0x04 */ 0x00000000, /* 31:2 e*RW DMA 2 (Even)
+ 1:0 RO 0x0 */
+/* 0x08 */ 0x00000000, /* 31:2 e*RW DMA 3 (Even)
+ 1:0 RO 0x0 */
+/* 0x0c */ 0x00000000, /* 31:1 o*RW DMA 1 (Odd)
+ 0 RO 0x0 */
+/* 0x10 */ 0x00000000, /* 31:2 o*RW DMA 2 (Odd)
+ 1:0 RO 0x0 */
+/* 0x14 */ 0x00000000, /* 31:2 o*RW DMA 3 (Odd)
+ 1:0 RO 0x0 */
+/* 0x18 */ 0x00000500, /* 15:2 e*RW Stride 1 (Even)
+ 1:0 RO 0x0 */
+/* 0x1c */ 0x00000000, /* 15:2 e*RW Stride 2 (Even)
+ 1:0 RO 0x0 */
+/* 0x20 */ 0x00000000, /* 15:2 e*RW Stride 3 (Even)
+ 1:0 RO 0x0 */
+/* 0x24 */ 0x00000500, /* 15:2 o*RW Stride 1 (Odd)
+ 1:0 RO 0x0 */
+/* 0x28 */ 0x00000000, /* 15:2 o*RW Stride 2 (Odd)
+ 1:0 RO 0x0 */
+/* 0x2c */ 0x00000000, /* 15:2 o*RW Stride 3 (Odd)
+ 1:0 RO 0x0 */
+/* 0x30 */ 0xeeeeee01, /* 31:8 *RW Route (Even)
+ 7:0 *RW Mode (Even) */
+/* 0x34 */ 0xeeeeee01, /* 31:8 *RW Route (Odd)
+ 7:0 *RW Mode (Odd) */
+/* 0x38 */ 0x00200020, /* 22:16 *RW FIFO Trigger Planer Mode,
+ 6:0 *RW FIFO Trigger Packed Mode */
+/* 0x3c */ 0x00000107, /* 9:8 *RW Reserved (0x0)
+ 2 *RW Field Toggle
+ 1 *RW Reserved (0x1)
+ 0 *RW Reserved (0x1) */
+/* 0x40 */ 0x000000c0, /* 15 *RW Range Enable
+ 14 *RW Corrupt Disable
+ 11 *RR Address Error (Odd)
+ 10 *RR Address Error (Even)
+ 9 *RR Field Corrupt (Odd)
+ 8 *RR Field Corrupt (Even)
+ 7 *RW Fifo Enable
+ 6 *RW VRSTN#
+ 5 *RR Field Done (Odd)
+ 4 *RR Field Done (Even)
+ 3 *RS Single Field Capture (Odd)
+ 2 *RS Single Field Capture (Even)
+ 1 *RW Capture (ODD) Continous
+ 0 *RW Capture (Even) Continous */
+/* 0x44 */ 0x00000000, /* 7:0 *RW Retry Wait Counter */
+/* 0x48 */ 0x00000307, /* 10 *RW Interrupt mask, start of field
+ 9 *RW Interrupt mask, end odd field
+ 8 *RW Interrupt mask, end even field
+ 2 *RR Interrupt status, start of field
+ 1 *RR Interrupt status, end of odd
+ 0 *RR Interrupt status, end of even */
+/* 0x4c */ 0x00000001, /* 31:0 *RW Field Mask (Even) continous */
+/* 0x50 */ 0x00000001, /* 31:0 *RW Field Mask (Odd) continous */
+/* 0x54 */ 0x00000000, /* 20:16 *RW Mask Length (Odd)
+ 4:0 *RW Mask Length (Even) */
+/* 0x58 */ 0x0005007c, /* 22:16 *RW FIFO almost empty
+ 6:0 *RW FIFO almost full */
+/* 0x5c */ 0x461e1e0f, /* 31:24 *RW I2C Phase 4
+ 23:16 *RW I2C Phase 3
+ 15:8 *RW I2C Phase 2
+ 7:0 *RW I2C Phase 1 */
+/* 0x60 */ 0x00000300, /* 31:24 *RO I2C Read Data
+ 23:16 **RW I2C Auto Address
+ 11 RO I2C SCL Input
+ 10 RO I2C SDA Input
+ 9 RR I2C Direct Abort
+ 8 RR I2C Auto Abort
+ 3 RW I2C SCL Output
+ 2 RW I2C SDA Output
+ 1 RW I2C Bypass
+ 0 RW I2C Auto Enable */
+/* 0x64 */ 0x00000000, /* 24 RS I2C New Cycle
+ 23:16 **RW I2C Direct Address
+ 15:8 **RW I2C Direct Sub-address
+ 7:0 **RW I2C Direct Write Address */
+/* 0x68 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Even)
+ 23:16 **RW I2C Auto Data 1 (Even)
+ 15:8 **RW I2C Auto Sub-address 0 (Even)
+ 7:0 **RW I2C Auto Data 0 (Even) */
+/* 0x6c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Even)
+ 23:16 **RW I2C Auto Data 3 (Even)
+ 15:8 **RW I2C Auto Sub-address 2 (Even)
+ 7:0 **RW I2C Auto Data 2 (Even) */
+/* 0x70 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Even)
+ 23:16 **RW I2C Auto Data 5 (Even)
+ 15:8 **RW I2C Auto Sub-address 4 (Even)
+ 7:0 **RW I2C Auto Data 4 (Even) */
+/* 0x74 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Even)
+ 23:16 **RW I2C Auto Data 7 (Even)
+ 15:8 **RW I2C Auto Sub-address 6 (Even)
+ 7:0 **RW I2C Auto Data 6 (Even) */
+/* 0x78 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Odd)
+ 23:16 **RW I2C Auto Data 1 (Odd)
+ 15:8 **RW I2C Auto Sub-address 0 (Odd)
+ 7:0 **RW I2C Auto Data 0 (Odd) */
+/* 0x7c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Odd)
+ 23:16 **RW I2C Auto Data 3 (Odd)
+ 15:8 **RW I2C Auto Sub-address 2 (Odd)
+ 7:0 **RW I2C Auto Data 2 (Odd) */
+/* 0x80 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Odd)
+ 23:16 **RW I2C Auto Data 5 (Odd)
+ 15:8 **RW I2C Auto Sub-address 4 (Odd)
+ 7:0 **RW I2C Auto Data 4 (Odd) */
+/* 0x84 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Odd)
+ 23:16 **RW I2C Auto Data 7 (Odd)
+ 15:8 **RW I2C Auto Sub-address 6 (Odd)
+ 7:0 **RW I2C Auto Data 6 (Odd) */
+/* 0x88 */ 0x00000000, /* 23:16 **RW I2C Register Enable (Odd)
+ 7:0 **RW I2C Register Enable (Even) */
+/* 0x8c */ 0x00000000, /* 23:2 e*RW DMA End (Even)
+ 1:0 RO 0x0 */
+/* 0x90 */ 0x00000000 /* 23:2 e*RW DMA End (Odd)
+ 1:0 RO 0x0 */
+};
+
+static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
+ /* SAA7196 I2C bus control */
+ /* BITS Function */
+/* 00 */ 0x50, /* 7:0 Increment Delay */
+/* 01 */ 0x30, /* 7:0 Horizontal Sync Begin for 50hz */
+/* 02 */ 0x00, /* 7:0 Horizontal Sync Stop for 50hz */
+/* 03 */ 0xe8, /* 7:0 Horizontal Sync Clamp Start for 50hz */
+/* 04 */ 0xb6, /* 7:0 Horizontal Sync Clamp Stop for 50hz */
+/* 05 */ 0xf4, /* 7:0 Horizontal Sync Start after PH1 for 50hz */
+/* 06 */ 0x46, /* 7 Input mode =0 CVBS, =1 S-Video
+ 6 Pre filter
+ 5:4 Aperture Bandpass characteristics
+ 3:2 Coring range for high freq
+ 1:0 Aperture bandpass filter weights */
+/* 07 */ 0x00, /* 7:0 Hue */
+/* 08 */ 0x7f, /* 7:3 Colour-killer threshold QAM (PAL, NTSC) */
+/* 09 */ 0x7f, /* 7:3 Colour-killer threshold SECAM */
+/* 0a */ 0x7f, /* 7:0 PAL switch sensitivity */
+/* 0b */ 0x7f, /* 7:0 SECAM switch sensitivity */
+/* 0c */ 0x40, /* 7 Colour-on bit
+ 6:5 AGC filter */
+/* 0d */ 0x84, /* 7 VTR/TV mode bit = 1->VTR mode
+ 3 Realtime output mode select bit
+ 2 HREF position select
+ 1 Status byte select
+ 0 SECAM mode bit */
+/* 0e */ 0x38, /* 7 Horizontal clock PLL
+ 5 Select interal/external clock source
+ 4 Output enable of Horizontal/Vertical sync
+ 3 Data output YUV enable
+ 2 S-VHS bit
+ 1 GPSW2
+ 0 GPSW1 */
+/* 0f */ 0x50, /* 7 Automatic Field detection
+ 6 Field Select 0 = 50hz, 1=60hz
+ 5 SECAM cross-colour reduction
+ 4 Enable sync and clamping pulse
+ 3:1 Luminance delay compensation */
+/* 10 */ 0x00, /* 2 Select HREF Position
+ 1:0 Vertical noise reduction */
+/* 11 */ 0x2c, /* 7:0 Chrominance gain conrtol for QAM */
+/* 12 */ 0x40, /* 7:0 Chrominance saturation control for VRAM port */
+/* 13 */ 0x40, /* 7:0 Luminance contract control for VRAM port */
+/* 14 */ 0x34, /* 7:0 Horizontal sync begin for 60hz */
+#ifdef notdef
+/* 15 */ 0x0c, /* 7:0 Horizontal sync stop for 60hz */
+/* 16 */ 0xfb, /* 7:0 Horizontal clamp begin for 60hz */
+/* 17 */ 0xd4, /* 7:0 Horizontal clamp stop for 60hz */
+/* 18 */ 0xec, /* 7:0 Horizontal sync start after PH1 for 60hz */
+#else
+ 0x0a, 0xf4, 0xce, 0xf4,
+#endif
+/* 19 */ 0x80, /* 7:0 Luminance brightness control for VRAM port */
+/* 1a */ 0x00,
+/* 1b */ 0x00,
+/* 1c */ 0x00,
+/* 1d */ 0x00,
+/* 1e */ 0x00,
+/* 1f */ 0x00,
+/* 20 */ 0x90, /* 7 ROM table bypass switch
+ 6:5 Set output field mode
+ 4 VRAM port outputs enable
+ 3:2 First pixel position in VRO data
+ 1:0 FIFO output register select */
+/* 21 */ 0x80, /* 7:0 [7:0] Pixel number per line on output */
+/* 22 */ 0x80, /* 7:0 [7:0] Pixel number per line on input */
+/* 23 */ 0x03, /* 7:0 [7:0] Horizontal start position of scaling win*/
+/* 24 */ 0x8a, /* 7:5 Horizontal decimation filter
+ 4 [8] Horizontal start position of scaling win
+ 3:2 [9:8] Pixel number per line on input
+ 1:0 [9:8] Pixel number per line on output */
+/* 25 */ 0xf0, /* 7:0 [7:0] Line number per output field */
+/* 26 */ 0xf0, /* 7:0 [7:0] Line number per input field */
+/* 27 */ 0x0f, /* 7:0 [7:0] Vertical start of scaling window */
+/* 28 */ 0x80, /* 7 Adaptive filter switch
+ 6:5 Vertical luminance data processing
+ 4 [8] Vertical start of scaling window
+ 3:2 [9:8] Line number per input field
+ 1:0 [9:8] Line number per output field */
+/* 29 */ 0x16, /* 7:0 [7:0] Vertical bypass start */
+/* 2a */ 0x00, /* 7:0 [7:0] Vertical bypass count */
+/* 2b */ 0x00, /* 4 [8] Vertical bypass start
+ 2 [8] Vertical bypass count
+ 0 Polarity, internally detected odd even flag */
+/* 2c */ 0x80, /* 7:0 Set lower limit V for colour-keying */
+/* 2d */ 0x7f, /* 7:0 Set upper limit V for colour-keying */
+/* 2e */ 0x80, /* 7:0 Set lower limit U for colour-keying */
+/* 2f */ 0x7f, /* 7:0 Set upper limit U for colour-keying */
+/* 30 */ 0xbf /* 7 VRAM bus output format
+ 6 Adaptive geometrical filter
+ 5 Luminance limiting value
+ 4 Monochrome and two's complement output data sel
+ 3 Line quailifier flag
+ 2 Pixel qualifier flag
+ 1 Transparent data transfer
+ 0 Extended formats enable bit */
+};
+
+static u_char bt254_default[NUM_BT254_REGS] = {
+ 0x00, /* 24 bpp */
+ 0xa0,
+ 0xa0,
+ 0xa0,
+ 0x50,
+ 0x50,
+ 0x50,
+} ;
+
+/*
+ * i2c_write:
+ * Returns 0 Succesful completion.
+ * Returns 1 If transfer aborted or timeout occured.
+ *
+ */
+static int i2c_print_err = 1;
+static int
+i2c_write(meteor_reg_t * mtr, u_char slave, u_char rw, u_char reg, u_char data)
+{
+register unsigned long wait_counter = 0x0001ffff;
+register mreg_t * iic_write_loc = &mtr->base->i2c_write;
+register int err = 0;
+
+
+ /* Write the data the the i2c write register */
+ *iic_write_loc = SAA7116_IIC_NEW_CYCLE |
+ (((u_long)slave|(u_long)rw) << 16) |
+ ((u_long)reg << 8) | (u_long)data;
+
+ /* Wait until the i2c cycle is compeleted */
+ while((*iic_write_loc & SAA7116_IIC_NEW_CYCLE)) {
+ if(!wait_counter) break;
+ wait_counter--;
+ }
+
+ /* 1ffff should be enough delay time for the i2c cycle to complete */
+ if(!wait_counter) {
+ if(i2c_print_err)
+ printf("meteor%d: %d i2c %s transfer timeout 0x%x",
+ METEOR_NUM(mtr), slave,
+ rw ? "read" : "write", *iic_write_loc);
+
+ err=1;
+ }
+
+ /* Check for error on direct write, clear if any */
+ if(mtr->base->i2c_read & SAA7116_IIC_DIRECT_TRANSFER_ABORTED){
+ mtr->base->i2c_read |= SAA7116_IIC_DIRECT_TRANSFER_ABORTED;
+ if(i2c_print_err)
+ printf("meteor%d: 0x%x i2c %s tranfer aborted",
+ METEOR_NUM(mtr), slave,
+ rw ? "read" : "write" );
+ err= 1;
+ }
+
+ if(err) {
+ if(i2c_print_err)
+ printf(" - reg=0x%x, value=0x%x.\n", reg, data);
+ }
+
+ return err;
+}
+#undef i2c_print
+
+static const char *
+met_probe (pcici_t tag, pcidi_t type)
+{
+
+ switch (type) {
+ case SAA7116_PHILIPS_ID: /* meteor */
+ return("Philips SAA 7116");
+ };
+ return ((char *)0);
+}
+
+ /* interrupt handling routine
+ complete meteor_read() if using interrupts
+ */
+static void
+meteor_intr(void *arg)
+{
+ meteor_reg_t *mtr = (meteor_reg_t *) arg;
+ mreg_t *cap = &mtr->base->cap_cntl,
+ *base = &mtr->base->dma1e,
+ *stat = &mtr->base->irq_stat;
+ u_long status = *stat,
+ cap_err = *cap & 0x00000f00,
+#ifdef METEOR_CHECK_PCI_BUS
+ pci_err = pci_conf_read(mtr->tag,
+ PCI_COMMAND_STATUS_REG),
+#endif
+ next_base = (u_long)(vtophys(mtr->bigbuf));
+
+ /*
+ * Disable future interrupts if a capture mode is not selected.
+ * This can happen when we are in the process of closing or
+ * changing capture modes, otherwise it shouldn't happen.
+ */
+ if(!(mtr->flags & METEOR_CAP_MASK)) {
+ *cap &= 0x8ff0; /* disable future interrupts */
+ }
+#ifdef METEOR_CHECK_PCI_BUS
+ /*
+ * Check for pci bus errors.
+ */
+#define METEOR_MASTER_ABORT 0x20000000
+#define METEOR_TARGET_ABORT 0x10000000
+ if(pci_err & METEOR_MASTER_ABORT) {
+ printf("meteor%d: intr: pci bus master dma abort: 0x%x 0x%x.\n",
+ METEOR_NUM(mtr), *base, *(base+3));
+ pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err);
+ }
+ if(pci_err & METEOR_TARGET_ABORT) {
+ printf("meteor%d: intr: pci bus target dma abort: 0x%x 0x%x.\n",
+ METEOR_NUM(mtr), *base, *(base+3));
+ pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err);
+ }
+#endif
+ /*
+ * Check for errors.
+ */
+ if (cap_err) {
+ if (cap_err & 0x300) {
+ if(mtr->fifo_errors % 50 == 0) {
+ printf("meteor%d: capture error", METEOR_NUM(mtr));
+ printf(": %s FIFO overflow.\n",
+ cap_err&0x0100? "even" : "odd");
+ }
+ mtr->fifo_errors++ ; /* increment fifo capture errors cnt */
+ }
+ if (cap_err & 0xc00) {
+ if(mtr->dma_errors % 50 == 0) {
+ printf("meteor%d: capture error", METEOR_NUM(mtr));
+ printf(": %s DMA address.\n",
+ cap_err&0x0400? "even" : "odd");
+ }
+ mtr->dma_errors++ ; /* increment DMA capture errors cnt */
+ }
+ }
+ *cap |= 0x0f30; /* clear error and field done */
+
+ /*
+ * In synchronous capture mode we need to know what the address
+ * offset for the next field/frame will be. next_base holds the
+ * value for the even dma buffers (for odd, one must add stride).
+ */
+ if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait &&
+ (mtr->current < mtr->frames)) { /* could be !=, but < is safer */
+ /* next_base is initialized to mtr->bigbuf */
+ next_base += mtr->frame_size * mtr->current;
+ if(mtr->flags & METEOR_WANT_TS)
+ next_base += sizeof(struct timeval) * mtr->current;
+ }
+
+ /*
+ * Count the field and clear the field flag.
+ *
+ * In single mode capture, clear the continuous capture mode.
+ *
+ * In synchronous capture mode, if we have room for another field,
+ * adjust DMA buffer pointers.
+ * When we are above the hi water mark (hiwat), mtr->synch_wait will
+ * be set and we will not bump the DMA buffer pointers. Thus, once
+ * we reach the hi water mark, the driver acts like a continuous mode
+ * capture on the mtr->current frame until we hit the low water
+ * mark (lowat). The user had the option of stopping or halting
+ * the capture if this is not the desired effect.
+ */
+ if (status & 0x1) { /* even field */
+ mtr->even_fields_captured++;
+ mtr->flags &= ~METEOR_WANT_EVEN;
+ if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) {
+ *base = next_base;
+ /* XXX should add adjustments for YUV_422 & PLANAR */
+ }
+ /*
+ * If the user requested to be notified via signal,
+ * let them know the field is complete.
+ */
+ if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK)) {
+ PROC_LOCK(mtr->proc);
+ psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
+ PROC_UNLOCK(mtr->proc);
+ }
+ }
+ if (status & 0x2) { /* odd field */
+ mtr->odd_fields_captured++;
+ mtr->flags &= ~METEOR_WANT_ODD;
+ if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) {
+ *(base+3) = next_base + *(base+6);
+ /* XXX should add adjustments for YUV_422 & PLANAR */
+ }
+ /*
+ * If the user requested to be notified via signal,
+ * let them know the field is complete.
+ */
+ if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK)) {
+ PROC_LOCK(mtr->proc);
+ psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
+ PROC_UNLOCK(mtr->proc);
+ }
+ }
+
+ /*
+ * If we have a complete frame.
+ */
+ if(!(mtr->flags & METEOR_WANT_MASK)) {
+ mtr->frames_captured++;
+ /*
+ * post the completion time.
+ */
+ if(mtr->flags & METEOR_WANT_TS) {
+ struct timeval *ts;
+
+ if(mtr->alloc_pages * PAGE_SIZE <= (mtr->frame_size +
+ sizeof(struct timeval))) {
+ ts =(struct timeval *)mtr->bigbuf +
+ mtr->frame_size;
+ /* doesn't work in synch mode except for first frame */
+ /* XXX */
+ microtime(ts);
+ }
+ }
+ /*
+ * Wake up the user in single capture mode.
+ */
+ if(mtr->flags & METEOR_SINGLE)
+ wakeup((caddr_t)mtr);
+ /*
+ * If the user requested to be notified via signal,
+ * let them know the frame is complete.
+ */
+ if(mtr->proc && !(mtr->signal & METEOR_SIG_MODE_MASK)) {
+ PROC_LOCK(mtr->proc);
+ psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
+ PROC_UNLOCK(mtr->proc);
+ }
+ /*
+ * Reset the want flags if in continuous or
+ * synchronous capture mode.
+ */
+ if(mtr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) {
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ mtr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ mtr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ mtr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+ /*
+ * Special handling for synchronous capture mode.
+ */
+ if(mtr->flags & METEOR_SYNCAP) {
+ struct meteor_mem *mm = mtr->mem;
+ /*
+ * Mark the current frame as active. It is up to
+ * the user to clear this, but we will clear it
+ * for the user for the current frame being captured
+ * if we are within the water marks (see below).
+ */
+ mm->active |= 1 << (mtr->current - 1);
+
+ /*
+ * Since the user can muck with these values, we need
+ * to check and see if they are sane. If they don't
+ * pass the sanity check, disable the capture mode.
+ * This is rather rude, but then so was the user.
+ *
+ * Do we really need all of this or should we just
+ * eliminate the possiblity of allowing the
+ * user to change hi and lo water marks while it
+ * is running? XXX
+ */
+ if(mm->num_active_bufs < 0 ||
+ mm->num_active_bufs > mtr->frames ||
+ mm->lowat < 1 || mm->lowat >= mtr->frames ||
+ mm->hiwat < 1 || mm->hiwat >= mtr->frames ||
+ mm->lowat > mm->hiwat ) {
+ *cap &= 0x8ff0;
+ mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK);
+ } else {
+ /*
+ * Ok, they are sane, now we want to
+ * check the water marks.
+ */
+ if(mm->num_active_bufs <= mm->lowat)
+ mtr->synch_wait = 0;
+ if(mm->num_active_bufs >= mm->hiwat)
+ mtr->synch_wait = 1;
+ /*
+ * Clear the active frame bit for this frame
+ * and advance the counters if we are within
+ * the banks of the water marks.
+ */
+ if(!mtr->synch_wait) {
+ mm->active &= ~(1 << mtr->current);
+ mtr->current++;
+ if(mtr->current > mtr->frames)
+ mtr->current = 1;
+ mm->num_active_bufs++;
+ }
+ }
+ }
+ }
+
+ *stat |= 0x7; /* clear interrupt status */
+ return;
+}
+
+static void
+set_fps(meteor_reg_t *mtr, u_short fps)
+{
+ struct saa7116_regs *s7116 = mtr->base;
+ unsigned status;
+ unsigned maxfps, mask = 0x1, length = 0;
+
+ SAA7196_WRITE(mtr, SAA7196_STDC, SAA7196_REG(mtr, SAA7196_STDC) | 0x02);
+ SAA7196_READ(mtr);
+ status = (s7116->i2c_read & 0xff000000L) >> 24;
+
+ /*
+ * Determine if there is an input signal. Depending on the
+ * frequency we either have a max of 25 fps (50 hz) or 30 fps (60 hz).
+ * If there is no input signal, then we need some defaults. If the
+ * user neglected to specify any defaults, just set to the fps to max.
+ */
+ if((status & 0x40) == 0) { /* Is there a signal ? */
+ if(status & 0x20) {
+ maxfps = 30; /* 60 hz system */
+ } else {
+ maxfps = 25; /* 50 hz system */
+ }
+ } else { /* We have no signal, check defaults */
+#if METEOR_SYSTEM_DEFAULT == METEOR_PAL || METEOR_SYSTEM_DEFAULT == METEOR_SECAM
+ maxfps = 25;
+#elif METEOR_SYSTEM_DEFAULT == METEOR_NTSC
+ maxfps = 30;
+#else
+ /* Don't really know what to do, just set max */
+ maxfps = 30;
+ fps = 30;
+#endif
+ }
+
+ /*
+ * A little sanity checking...
+ */
+ if(fps < 1) fps = 1;
+ if(fps > maxfps) fps = maxfps;
+
+ /*
+ * Compute the mask/length using the fps.
+ */
+ if(fps == maxfps) {
+ mask = 0x1;
+ length = 0x0;
+ } else if ((float)fps == maxfps/2.0) {
+ mask = 0x1;
+ length = 0x1;
+ } else if (fps > maxfps/2) {
+ float step, b;
+
+ mask = (1<<maxfps) - 1;
+ length = maxfps - 1;
+ step = (float)(maxfps - 1)/(float)(maxfps - fps);
+ for(b=step; b < maxfps; b += step) {
+ mask &= ~(1<<((int)b)); /* mask out the bth frame */
+ }
+ } else { /* fps < maxfps/2 */
+ float step, b;
+
+ mask = 0x1;
+ length = maxfps - 1;
+ step = (float)(maxfps -1)/(float)(fps);
+ for(b = step + 1; b < maxfps - 1; b += step) {
+ mask |= (1<<((int)b)); /* mask in the bth frame */
+ }
+ }
+
+ /*
+ * Set the fps.
+ */
+ s7116->fme = s7116->fmo = mask;
+ s7116->fml = (length << 16) | length;;
+
+ mtr->fps = fps;
+
+ return;
+
+}
+
+/*
+ * There is also a problem with range checking on the 7116.
+ * It seems to only work for 22 bits, so the max size we can allocate
+ * is 22 bits long or 4194304 bytes assuming that we put the beginning
+ * of the buffer on a 2^24 bit boundary. The range registers will use
+ * the top 8 bits of the dma start registers along with the bottom 22
+ * bits of the range register to determine if we go out of range.
+ * This makes getting memory a real kludge.
+ *
+ */
+#define RANGE_BOUNDARY (1<<22)
+static vm_offset_t
+get_meteor_mem(int unit, unsigned size)
+{
+vm_offset_t addr = 0;
+
+ addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
+ if(addr == 0)
+ addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
+ if(addr == 0) {
+ printf("meteor%d: Unable to allocate %d bytes of memory.\n",
+ unit, size);
+ }
+
+ return addr;
+}
+
+static void
+bt254_write(meteor_reg_t *mtr, u_char addr, u_char data)
+{
+ addr &= 0x7; /* sanity? */
+ mtr->bt254_reg[addr] = data;
+ PCF8574_DATA_WRITE(mtr, data); /* set data */
+ PCF8574_CTRL_WRITE(mtr, (PCF8574_CTRL_REG(mtr) & ~0x7) | addr);
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x10); /* WR/ to 0 */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x10); /* WR to 1 */
+ PCF8574_DATA_WRITE(mtr, 0xff); /* clr data */
+
+}
+
+static void
+bt254_init(meteor_reg_t *mtr)
+{
+int i;
+
+ PCF8574_CTRL_WRITE(mtr, 0x7f);
+ PCF8574_DATA_WRITE(mtr, 0xff); /* data port must be 0xff */
+ PCF8574_CTRL_WRITE(mtr, 0x7f);
+
+ /* init RGB module for 24bpp, composite input */
+ for(i=0; i<NUM_BT254_REGS; i++)
+ bt254_write(mtr, i, bt254_default[i]);
+
+ bt254_write(mtr, BT254_COMMAND, 0x00); /* 24 bpp */
+}
+
+static void
+bt254_ntsc(meteor_reg_t *mtr, int arg)
+{
+ if (arg){
+ /* Set NTSC bit */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x20);
+ }
+ else {
+ /* reset NTSC bit */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) &= ~0x20);
+ }
+}
+
+static void
+select_bt254(meteor_reg_t *mtr)
+{
+ /* disable saa7196, saaen = 1 */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x80);
+ /* enable Bt254, bten = 0 */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x40);
+}
+
+static void
+select_saa7196(meteor_reg_t *mtr)
+{
+ /* disable Bt254, bten = 1 */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x40);
+ /* enable saa7196, saaen = 0 */
+ PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x80);
+}
+
+/*
+ * Initialize the 7116, 7196 and the RGB module.
+ */
+static void
+meteor_init ( meteor_reg_t *mtr )
+{
+ mreg_t *vbase_addr;
+ int i;
+
+ /*
+ * Initialize the Philips SAA7116
+ */
+ mtr->base->cap_cntl = 0x00000040L;
+ vbase_addr = &mtr->base->dma1e;
+ for (i = 0 ; i < (sizeof(struct saa7116_regs)/sizeof(mreg_t)); i++)
+ *vbase_addr++ = saa7116_pci_default[i];
+
+ /*
+ * Check for the Philips SAA7196
+ */
+ i2c_print_err = 0;
+ if(i2c_write(mtr, SAA7196_I2C_ADDR, SAA7116_I2C_WRITE, 0, 0xff) == 0) {
+ i2c_print_err = 1;
+ /*
+ * Initialize 7196
+ */
+ for (i = 0; i < NUM_SAA7196_I2C_REGS; i++)
+ SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]);
+ /*
+ * Get version number.
+ */
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ SAA7196_REG(mtr, SAA7196_STDC) & ~0x02);
+ SAA7196_READ(mtr);
+ printf("meteor%d: <Philips SAA 7196> rev 0x%x\n",
+ METEOR_NUM(mtr),
+ (unsigned)((mtr->base->i2c_read & 0xff000000L) >> 28));
+ } else {
+ i2c_print_err = 1;
+ printf("meteor%d: <Philips SAA 7196 NOT FOUND>\n",
+ METEOR_NUM(mtr));
+ }
+ /*
+ * Check for RGB module, initialized if found.
+ */
+ i2c_print_err = 0;
+ if(i2c_write(mtr,PCF8574_DATA_I2C_ADDR,SAA7116_I2C_WRITE,0,0xff) == 0) {
+ i2c_print_err = 1;
+ printf("meteor%d: <Booktree 254 (RGB module)>\n",
+ METEOR_NUM(mtr)); /* does this have a rev #? */
+ bt254_init(mtr); /* Set up RGB module */
+ mtr->flags = METEOR_RGB;
+ } else {
+ i2c_print_err = 1;
+ mtr->flags = 0;
+ }
+
+ set_fps(mtr, 30);
+
+}
+
+static void
+met_attach(pcici_t tag, int unit)
+{
+#ifdef METEOR_IRQ
+ u_long old_irq, new_irq;
+#endif METEOR_IRQ
+ meteor_reg_t *mtr;
+ vm_offset_t buf;
+ u_long latency;
+
+ if (unit >= NMETEOR) {
+ printf("meteor%d: attach: only %d units configured.\n",
+ unit, NMETEOR);
+ printf("meteor%d: attach: invalid unit number.\n", unit);
+ return ;
+ }
+
+ /*
+ * Check for Meteor/PPB (PCI-PCI Bridge)
+ * Reprogram IBM Bridge if detected.
+ * New Meteor cards have an IBM PCI-PCI bridge, creating a secondary
+ * PCI bus. The SAA chip is connected to this secondary bus.
+ */
+
+ /* If we are not on PCI Bus 0, check for the Bridge */
+ if ( pci_get_bus_from_tag( tag ) != 0) {
+ pcici_t bridge_tag;
+
+ /* get tag of parent bridge */
+ bridge_tag = pci_get_parent_from_tag( tag );
+
+ /* Look for IBM 82351, 82352 or 82353 */
+ if (pci_conf_read(bridge_tag, PCI_ID_REG) == 0x00221014) {
+
+ if ( bootverbose)
+ printf("meteor%d: PPB device detected, reprogramming IBM bridge.\n", unit);
+
+ /* disable SERR */
+ pci_cfgwrite(bridge_tag, 0x05, 0x00, 1);
+ /* set LATENCY */
+ pci_cfgwrite(bridge_tag, 0x0d, 0x20, 1);
+ /* write posting enable, prefetch enabled --> GRAB direction */
+ pci_cfgwrite(bridge_tag, 0x42, 0x14, 1);
+ /* set PRTR Primary retry timer register */
+ pci_cfgwrite(bridge_tag, 0x4c, 0x10, 1);
+ }
+ }
+
+ mtr = &meteor[unit];
+ mtr->tag = tag;
+ pci_map_mem(tag, PCI_MAP_REG_START, (vm_offset_t *)&mtr->base,
+ &mtr->phys_base);
+
+#ifdef METEOR_IRQ /* from the configuration file */
+ old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ pci_conf_write(tag, PCI_INTERRUPT_REG, METEOR_IRQ);
+ new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ printf("meteor%d: attach: irq changed from %d to %d\n",
+ unit, (old_irq & 0xff), (new_irq & 0xff));
+#endif METEOR_IRQ
+ /* setup the interrupt handling routine */
+ pci_map_int(tag, meteor_intr, (void*) mtr, &net_imask);
+
+/*
+ * PCI latency timer. 32 is a good value for 4 bus mastering slots, if
+ * you have more than for, then 16 would probably be a better value.
+ *
+ */
+#ifndef METEOR_DEF_LATENCY_VALUE
+#define METEOR_DEF_LATENCY_VALUE 32
+#endif
+ latency = pci_conf_read(tag, PCI_LATENCY_TIMER);
+ latency = (latency >> 8) & 0xff;
+ if(bootverbose) {
+ if(latency)
+ printf("meteor%d: PCI bus latency is", unit);
+ else
+ printf("meteor%d: PCI bus latency was 0 changing to",
+ unit);
+ }
+ if(!latency) {
+ latency = METEOR_DEF_LATENCY_VALUE;
+ pci_conf_write(tag, PCI_LATENCY_TIMER, latency<<8);
+ }
+ if(bootverbose) {
+ printf(" %lu.\n", latency);
+ }
+
+ meteor_init(mtr); /* set up saa7116, saa7196, and rgb module */
+
+ if(METEOR_ALLOC)
+ buf = get_meteor_mem(unit, METEOR_ALLOC);
+ else
+ buf = 0;
+ if(bootverbose) {
+ printf("meteor%d: buffer size %d, addr 0x%x\n",
+ unit, METEOR_ALLOC, vtophys(buf));
+ }
+
+ mtr->bigbuf = buf;
+ mtr->alloc_pages = METEOR_ALLOC_PAGES;
+ if(buf != 0) {
+ bzero((caddr_t) buf, METEOR_ALLOC);
+ buf = vtophys(buf);
+ /* 640x480 RGB 16 */
+ mtr->base->dma1e = buf;
+ mtr->base->dma1o = buf + 0x500;
+ mtr->base->dma_end_e =
+ mtr->base->dma_end_o = buf + METEOR_ALLOC;
+ }
+ /* 1 frame of 640x480 RGB 16 */
+ mtr->cols = 640;
+ mtr->rows = 480;
+ mtr->depth = 2; /* two bytes per pixel */
+ mtr->frames = 1; /* one frame */
+
+ mtr->flags |= METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 |
+ METEOR_RGB16;
+ make_dev(&meteor_cdevsw, unit, 0, 0, 0644, "meteor");
+}
+
+#define UNIT(x) ((x) & 0x07)
+
+#ifdef unused
+static int
+meteor_reset(dev_t dev)
+{
+int unit = UNIT(minor(dev));
+struct saa7116_regs *m;
+
+ if(unit >= NMETEOR)
+ return ENXIO;
+
+ m = meteor[unit].base;
+
+ m->cap_cntl = 0x0;
+ tsleep((caddr_t)m, METPRI, "Mreset", hz/50);
+
+ m->cap_cntl = 0x8ff0;
+ m->cap_cntl = 0x80c0;
+ m->cap_cntl = 0x8040;
+ tsleep((caddr_t)m, METPRI, "Mreset", hz/10);
+ m->cap_cntl = 0x80c0;
+
+ return 0;
+
+}
+#endif
+
+/*---------------------------------------------------------
+**
+** Meteor character device driver routines
+**
+**---------------------------------------------------------
+*/
+
+
+int
+meteor_open(dev_t dev, int flags, int fmt, struct thread *td)
+{
+ meteor_reg_t *mtr;
+ int unit;
+ int i;
+
+ unit = UNIT(minor(dev));
+ if (unit >= NMETEOR) /* unit out of range */
+ return(ENXIO);
+
+ mtr = &(meteor[unit]);
+
+ if (!(mtr->flags & METEOR_INITALIZED)) /* device not found */
+ return(ENXIO);
+
+ if (mtr->flags & METEOR_OPEN) /* device is busy */
+ return(EBUSY);
+
+ mtr->flags |= METEOR_OPEN;
+ /*
+ * Make sure that the i2c regs are set the same for each open.
+ */
+ for(i=0; i< NUM_SAA7196_I2C_REGS; i++) {
+ SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]);
+ }
+
+ mtr->fifo_errors = 0;
+ mtr->dma_errors = 0;
+ mtr->frames_captured = 0;
+ mtr->even_fields_captured = 0;
+ mtr->odd_fields_captured = 0;
+ mtr->proc = (struct proc *)0;
+ set_fps(mtr, 30);
+#ifdef METEOR_TEST_VIDEO
+ mtr->video.addr = 0;
+ mtr->video.width = 0;
+ mtr->video.banksize = 0;
+ mtr->video.ramsize = 0;
+#endif
+
+ return(0);
+}
+
+int
+meteor_close(dev_t dev, int flags, int fmt, struct thread *td)
+{
+ meteor_reg_t *mtr;
+ int unit;
+#ifdef METEOR_DEALLOC_ABOVE
+ int temp;
+#endif
+
+ unit = UNIT(minor(dev));
+ if (unit >= NMETEOR) /* unit out of range */
+ return(ENXIO);
+
+ mtr = &(meteor[unit]);
+ mtr->flags &= ~METEOR_OPEN;
+
+ if(mtr->flags & METEOR_SINGLE)
+ /* this should not happen, the read capture
+ should have completed or in the very least
+ recieved a signal before close is called. */
+ wakeup((caddr_t)mtr); /* continue read */
+ /*
+ * Turn off capture mode.
+ */
+ mtr->base->cap_cntl = 0x8ff0;
+ mtr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK);
+ mtr->proc = (struct proc *)0;
+
+#ifdef METEOR_DEALLOC_PAGES
+ if (mtr->bigbuf != NULL) {
+ kmem_free(kernel_map,mtr->bigbuf,(mtr->alloc_pages*PAGE_SIZE));
+ mtr->bigbuf = NULL;
+ mtr->alloc_pages = 0;
+ }
+#else
+#ifdef METEOR_DEALLOC_ABOVE
+ if (mtr->bigbuf != NULL && mtr->alloc_pages > METEOR_DEALLOC_ABOVE) {
+ temp = METEOR_DEALLOC_ABOVE - mtr->alloc_pages;
+ kmem_free(kernel_map,
+ mtr->bigbuf+((mtr->alloc_pages - temp) * PAGE_SIZE),
+ (temp * PAGE_SIZE));
+ mtr->alloc_pages = METEOR_DEALLOC_ABOVE;
+ }
+#endif
+#endif
+
+ return(0);
+}
+
+static void
+start_capture(meteor_reg_t *mtr, unsigned type)
+{
+mreg_t *cap = &mtr->base->cap_cntl;
+
+ mtr->flags |= type;
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_EVEN_FIELDS:
+ mtr->flags |= METEOR_WANT_EVEN;
+ if(type == METEOR_SINGLE)
+ *cap = 0x0ff4 | mtr->range_enable;
+ else
+ *cap = 0x0ff1 | mtr->range_enable;
+ break;
+ case METEOR_ONLY_ODD_FIELDS:
+ mtr->flags |= METEOR_WANT_ODD;
+ if(type == METEOR_SINGLE)
+ *cap = 0x0ff8 | mtr->range_enable;
+ else
+ *cap = 0x0ff2 | mtr->range_enable;
+ break;
+ default:
+ mtr->flags |= METEOR_WANT_MASK;
+ if(type == METEOR_SINGLE)
+ *cap = 0x0ffc | mtr->range_enable;
+ else
+ *cap = 0x0ff3 | mtr->range_enable;
+ break;
+ }
+}
+
+int
+meteor_read(dev_t dev, struct uio *uio, int ioflag)
+{
+ meteor_reg_t *mtr;
+ int unit;
+ int status;
+ int count;
+
+ unit = UNIT(minor(dev));
+ if (unit >= NMETEOR) /* unit out of range */
+ return(ENXIO);
+
+ mtr = &(meteor[unit]);
+ if (mtr->bigbuf == 0)/* no frame buffer allocated (ioctl failed) */
+ return(ENOMEM);
+
+ if (mtr->flags & METEOR_CAP_MASK)
+ return(EIO); /* already capturing */
+
+ count = mtr->rows * mtr->cols * mtr->depth;
+ if (uio->uio_iov->iov_len < count)
+ return(EINVAL);
+
+ /* Start capture */
+ start_capture(mtr, METEOR_SINGLE);
+
+ status=tsleep((caddr_t)mtr, METPRI, "capturing", 0);
+ if (!status) /* successful capture */
+ status = uiomove((caddr_t)mtr->bigbuf, count, uio);
+ else
+ printf ("meteor%d: read: tsleep error %d\n", unit, status);
+
+ mtr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
+
+ return(status);
+}
+
+int
+meteor_write(dev_t dev, struct uio *uio, int ioflag)
+{
+ return(0);
+}
+
+int
+meteor_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
+{
+ int error;
+ int unit;
+ unsigned int temp;
+ meteor_reg_t *mtr;
+ struct meteor_counts *cnt;
+ struct meteor_geomet *geo;
+ struct meteor_mem *mem;
+ struct meteor_capframe *frame;
+#ifdef METEOR_TEST_VIDEO
+ struct meteor_video *video;
+#endif
+ vm_offset_t buf;
+ struct saa7116_regs *base;
+
+ error = 0;
+
+ if (!arg) return(EINVAL);
+ unit = UNIT(minor(dev));
+ if (unit >= NMETEOR) /* unit out of range */
+ return(ENXIO);
+
+ mtr = &(meteor[unit]);
+ base = mtr->base;
+
+ switch (cmd) {
+ case METEORSTS:
+ if(*arg)
+ mtr->flags |= METEOR_WANT_TS;
+ else
+ mtr->flags &= ~METEOR_WANT_TS;
+ break;
+ case METEORGTS:
+ if(mtr->flags & METEOR_WANT_TS)
+ *arg = 1;
+ else
+ *arg = 0;
+ break;
+#ifdef METEOR_TEST_VIDEO
+ case METEORGVIDEO:
+ video = (struct meteor_video *)arg;
+ video->addr = mtr->video.addr;
+ video->width = mtr->video.width;
+ video->banksize = mtr->video.banksize;
+ video->ramsize = mtr->video.ramsize;
+ break;
+ case METEORSVIDEO:
+ video = (struct meteor_video *)arg;
+ mtr->video.addr = video->addr;
+ mtr->video.width = video->width;
+ mtr->video.banksize = video->banksize;
+ mtr->video.ramsize = video->ramsize;
+ break;
+#endif
+ case METEORSFPS:
+ set_fps(mtr, *(u_short *)arg);
+ break;
+ case METEORGFPS:
+ *(u_short *)arg = mtr->fps;
+ break;
+ case METEORSSIGNAL:
+ mtr->signal = *(int *) arg;
+ if (mtr->signal) {
+ mtr->proc = td->td_proc;
+ } else {
+ mtr->proc = (struct proc *)0;
+ }
+ break;
+ case METEORGSIGNAL:
+ *(int *)arg = mtr->signal;
+ break;
+ case METEORSTATUS: /* get 7196 status */
+ temp = 0;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ SAA7196_REG(mtr, SAA7196_STDC) | 0x02);
+ SAA7196_READ(mtr);
+ temp |= (base->i2c_read & 0xff000000L) >> 24;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ SAA7196_REG(mtr, SAA7196_STDC) & ~0x02);
+ SAA7196_READ(mtr);
+ temp |= (base->i2c_read & 0xff000000L) >> 16;
+ *(u_short *)arg = temp;
+ break;
+ case METEORSHUE: /* set hue */
+ SAA7196_WRITE(mtr, SAA7196_HUEC, *(char *)arg);
+ break;
+ case METEORGHUE: /* get hue */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_HUEC);
+ break;
+ case METEORSCHCV: /* set chrominance gain */
+ SAA7196_WRITE(mtr, SAA7196_CGAINR, *(char *)arg);
+ break;
+ case METEORGCHCV: /* get chrominance gain */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_CGAINR);
+ break;
+ case METEORSBRIG: /* set brightness */
+ SAA7196_WRITE(mtr, SAA7196_BRIG, *(char *)arg);
+ break;
+ case METEORGBRIG: /* get brightness */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_BRIG);
+ break;
+ case METEORSCSAT: /* set chroma saturation */
+ SAA7196_WRITE(mtr, SAA7196_CSAT, *(char *)arg);
+ break;
+ case METEORGCSAT: /* get chroma saturation */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_CSAT);
+ break;
+ case METEORSCONT: /* set contrast */
+ SAA7196_WRITE(mtr, SAA7196_CONT, *(char *)arg);
+ break;
+ case METEORGCONT: /* get contrast */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_CONT);
+ break;
+ case METEORSBT254:
+ if((mtr->flags & METEOR_RGB) == 0)
+ return EINVAL;
+ temp = *(unsigned short *)arg;
+ bt254_write(mtr, temp & 0xf, (temp & 0x0ff0) >> 4);
+ break;
+ case METEORGBT254:
+ if((mtr->flags & METEOR_RGB) == 0)
+ return EINVAL;
+ temp = *(unsigned short *)arg & 0x7;
+ *(unsigned short *)arg = mtr->bt254_reg[temp] << 4 | temp;
+ break;
+ case METEORSHWS: /* set horizontal window start */
+ SAA7196_WRITE(mtr, SAA7196_HWS, *(char *)arg);
+ break;
+ case METEORGHWS: /* get horizontal window start */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_HWS);
+ break;
+ case METEORSVWS: /* set vertical window start */
+ SAA7196_WRITE(mtr, SAA7196_VWS, *(char *)arg);
+ break;
+ case METEORGVWS: /* get vertical window start */
+ *(char *)arg = SAA7196_REG(mtr, SAA7196_VWS);
+ break;
+ case METEORSINPUT: /* set input device */
+ switch(*(unsigned long *)arg & METEOR_DEV_MASK) {
+ case 0: /* default */
+ case METEOR_INPUT_DEV0:
+ if(mtr->flags & METEOR_RGB)
+ select_saa7196(mtr);
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV0;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x0);
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80));
+ break;
+ case METEOR_INPUT_DEV1:
+ if(mtr->flags & METEOR_RGB)
+ select_saa7196(mtr);
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV1;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x1);
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80));
+ break;
+ case METEOR_INPUT_DEV2:
+ if(mtr->flags & METEOR_RGB)
+ select_saa7196(mtr);
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV2;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2);
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80));
+ break;
+ case METEOR_INPUT_DEV3:
+ if(mtr->flags & METEOR_RGB)
+ select_saa7196(mtr);
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV3;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) | 0x3));
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80) );
+ break;
+ case METEOR_INPUT_DEV_SVIDEO:
+ if(mtr->flags & METEOR_RGB)
+ select_saa7196(mtr);
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV_SVIDEO;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2);
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80) | 0x80);
+ break;
+ case METEOR_INPUT_DEV_RGB:
+ if((mtr->flags & METEOR_RGB) == 0)
+ return EINVAL;
+ mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV_RGB;
+ SAA7196_WRITE(mtr, 0x0e,
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3);
+ SAA7196_WRITE(mtr, 0x06,
+ (SAA7196_REG(mtr, 0x06) & ~0x80));
+ select_bt254(mtr);
+ SAA7196_WRITE(mtr, 0x0e, /* chn 3 for synch */
+ (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3);
+ break;
+ default:
+ return EINVAL;
+ }
+ break;
+ case METEORGINPUT: /* get input device */
+ *(u_long *)arg = mtr->flags & METEOR_DEV_MASK;
+ break;
+ case METEORSFMT: /* set input format */
+ switch(*(unsigned long *)arg & METEOR_FORM_MASK ) {
+ case 0: /* default */
+ case METEOR_FMT_NTSC:
+ mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
+ METEOR_NTSC;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
+ SAA7196_WRITE(mtr, 0x0f,
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x40);
+ SAA7196_WRITE(mtr, 0x22, 0x80);
+ SAA7196_WRITE(mtr, 0x24,
+ (SAA7196_REG(mtr, 0x24) & ~0x0c) | 0x08);
+ SAA7196_WRITE(mtr, 0x26, 0xf0);
+ SAA7196_WRITE(mtr, 0x28,
+ (SAA7196_REG(mtr, 0x28) & ~0x0c)) ;
+ if(mtr->flags & METEOR_RGB){
+ bt254_ntsc(mtr, 1);
+ }
+ break;
+ case METEOR_FMT_PAL:
+ mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
+ METEOR_PAL;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
+ SAA7196_WRITE(mtr, 0x0f,
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0));
+ SAA7196_WRITE(mtr, 0x22, 0x00);
+ SAA7196_WRITE(mtr, 0x24,
+ (SAA7196_REG(mtr, 0x24) | 0x0c));
+ SAA7196_WRITE(mtr, 0x26, 0x20);
+ SAA7196_WRITE(mtr, 0x28,
+ (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
+ if(mtr->flags & METEOR_RGB){
+ bt254_ntsc(mtr, 0);
+ }
+ break;
+ case METEOR_FMT_SECAM:
+ mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
+ METEOR_SECAM;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01) | 0x1);
+ SAA7196_WRITE(mtr, 0x0f,
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x20);
+ SAA7196_WRITE(mtr, 0x22, 0x00);
+ SAA7196_WRITE(mtr, 0x24,
+ (SAA7196_REG(mtr, 0x24) | 0x0c));
+ SAA7196_WRITE(mtr, 0x26, 0x20);
+ SAA7196_WRITE(mtr, 0x28,
+ (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
+ if(mtr->flags & METEOR_RGB){
+ bt254_ntsc(mtr, 0);
+ }
+ break;
+ case METEOR_FMT_AUTOMODE:
+ mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
+ METEOR_AUTOMODE;
+ SAA7196_WRITE(mtr, SAA7196_STDC,
+ (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
+ SAA7196_WRITE(mtr, 0x0f,
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x80);
+ break;
+ default:
+ return EINVAL;
+ }
+ break;
+ case METEORGFMT: /* get input format */
+ *(u_long *)arg = mtr->flags & METEOR_FORM_MASK;
+ break;
+ case METEORCAPTUR:
+ temp = mtr->flags;
+ switch (*(int *) arg) {
+ case METEOR_CAP_SINGLE:
+ if (mtr->bigbuf==0) /* no frame buffer allocated */
+ return(ENOMEM);
+
+ if (temp & METEOR_CAP_MASK)
+ return(EIO); /* already capturing */
+
+ start_capture(mtr, METEOR_SINGLE);
+
+ /* wait for capture to complete */
+ error=tsleep((caddr_t)mtr, METPRI, "capturing", 0);
+ if(error)
+ printf("meteor%d: ioctl: tsleep error %d\n",
+ unit, error);
+ mtr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
+ break;
+ case METEOR_CAP_CONTINOUS:
+ if (mtr->bigbuf==0) /* no frame buffer allocated */
+ return(ENOMEM);
+
+ if (temp & METEOR_CAP_MASK)
+ return(EIO); /* already capturing */
+
+ start_capture(mtr, METEOR_CONTIN);
+
+ break;
+ case METEOR_CAP_STOP_CONT:
+ if (mtr->flags & METEOR_CONTIN) {
+ /* turn off capture */
+ base->cap_cntl = 0x8ff0;
+ mtr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK);
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case METEORCAPFRM:
+ frame = (struct meteor_capframe *) arg;
+ if (!frame)
+ return(EINVAL);
+ switch (frame->command) {
+ case METEOR_CAP_N_FRAMES:
+ if (mtr->flags & METEOR_CAP_MASK)
+ return(EIO);
+ if (mtr->flags & (METEOR_YUV_PLANAR | METEOR_YUV_422)) /* XXX */
+ return(EINVAL); /* should fix intr so we allow these */
+ if (mtr->bigbuf == 0)
+ return(ENOMEM);
+ if ((mtr->frames < 2) ||
+ (frame->lowat < 1 || frame->lowat >= mtr->frames) ||
+ (frame->hiwat < 1 || frame->hiwat >= mtr->frames) ||
+ (frame->lowat > frame->hiwat))
+ return(EINVAL);
+ /* meteor_mem structure is on the page after the data */
+ mem = mtr->mem = (struct meteor_mem *) (mtr->bigbuf +
+ (round_page(mtr->frame_size * mtr->frames)));
+ mtr->current = 1;
+ mtr->synch_wait = 0;
+ mem->num_bufs = mtr->frames;
+ mem->frame_size= mtr->frame_size;
+ /* user and kernel change these */
+ mem->lowat = frame->lowat;
+ mem->hiwat = frame->hiwat;
+ mem->active = 0;
+ mem->num_active_bufs = 0;
+ /* Start capture */
+ start_capture(mtr, METEOR_SYNCAP);
+ break;
+ case METEOR_CAP_STOP_FRAMES:
+ if (mtr->flags & METEOR_SYNCAP) {
+ /* turn off capture */
+ base->cap_cntl = 0x8ff0;
+ mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK);
+ }
+ break;
+ case METEOR_HALT_N_FRAMES:
+ if(mtr->flags & METEOR_SYNCAP) {
+ base->cap_cntl = 0x8ff0;
+ mtr->flags &= ~(METEOR_WANT_MASK);
+ }
+ break;
+ case METEOR_CONT_N_FRAMES:
+ if(!(mtr->flags & METEOR_SYNCAP)) {
+ error = EINVAL;
+ break;
+ }
+ start_capture(mtr, METEOR_SYNCAP);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ case METEORSETGEO:
+ geo = (struct meteor_geomet *) arg;
+
+ /* Either even or odd, if even & odd, then these a zero */
+ if((geo->oformat & METEOR_GEO_ODD_ONLY) &&
+ (geo->oformat & METEOR_GEO_EVEN_ONLY)) {
+ printf("meteor%d: ioctl: Geometry odd or even only.\n",
+ unit);
+ return EINVAL;
+ }
+ /* set/clear even/odd flags */
+ if(geo->oformat & METEOR_GEO_ODD_ONLY)
+ mtr->flags |= METEOR_ONLY_ODD_FIELDS;
+ else
+ mtr->flags &= ~METEOR_ONLY_ODD_FIELDS;
+ if(geo->oformat & METEOR_GEO_EVEN_ONLY)
+ mtr->flags |= METEOR_ONLY_EVEN_FIELDS;
+ else
+ mtr->flags &= ~METEOR_ONLY_EVEN_FIELDS;
+
+ /* can't change parameters while capturing */
+ if (mtr->flags & METEOR_CAP_MASK)
+ return(EBUSY);
+
+ if ((geo->columns & 0x3fe) != geo->columns) {
+ printf(
+ "meteor%d: ioctl: %d: columns too large or not even.\n",
+ unit, geo->columns);
+ error = EINVAL;
+ }
+ if (((geo->rows & 0x7fe) != geo->rows) ||
+ ((geo->oformat & METEOR_GEO_FIELD_MASK) &&
+ ((geo->rows & 0x3fe) != geo->rows)) ) {
+ printf(
+ "meteor%d: ioctl: %d: rows too large or not even.\n",
+ unit, geo->rows);
+ error = EINVAL;
+ }
+ if (geo->frames > 32) {
+ printf("meteor%d: ioctl: too many frames.\n", unit);
+ error = EINVAL;
+ }
+ if(error) return error;
+
+ if ((temp=geo->rows * geo->columns * geo->frames * 2) != 0) {
+ if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
+
+ /* meteor_mem structure for SYNC Capture */
+ if (geo->frames > 1) temp += PAGE_SIZE;
+
+ temp = btoc(temp);
+ if (temp > mtr->alloc_pages
+#ifdef METEOR_TEST_VIDEO
+ && mtr->video.addr == 0
+#endif
+ ) {
+ buf = get_meteor_mem(unit, temp*PAGE_SIZE);
+ if(buf != 0) {
+ kmem_free(kernel_map, mtr->bigbuf,
+ (mtr->alloc_pages * PAGE_SIZE));
+ mtr->bigbuf = buf;
+ mtr->alloc_pages = temp;
+ if(bootverbose)
+ printf(
+ "meteor%d: ioctl: Allocating %d bytes\n",
+ unit, temp*PAGE_SIZE);
+ } else {
+ error = ENOMEM;
+ }
+ }
+ }
+ if(error) return error;
+
+ mtr->rows = geo->rows;
+ mtr->cols = geo->columns;
+ mtr->frames = geo->frames;
+
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr)
+ buf = vtophys(mtr->video.addr);
+ else
+#endif
+ buf = vtophys(mtr->bigbuf);
+
+ /* set defaults and end of buffer locations */
+ base->dma1e = buf;
+ base->dma2e = buf;
+ base->dma3e = buf;
+ base->dma1o = buf;
+ base->dma2o = buf;
+ base->dma3o = buf;
+ base->stride1e = 0;
+ base->stride2e = 0;
+ base->stride3e = 0;
+ base->stride1o = 0;
+ base->stride2o = 0;
+ base->stride3o = 0;
+ /* set end of DMA location, even/odd */
+ base->dma_end_e =
+ base->dma_end_o = buf + mtr->alloc_pages * PAGE_SIZE;
+
+ /*
+ * Determine if we can use the hardware range detect.
+ */
+ if(mtr->alloc_pages * PAGE_SIZE < RANGE_BOUNDARY &&
+ ((buf & 0xff000000) | base->dma_end_e) ==
+ (buf + mtr->alloc_pages * PAGE_SIZE) )
+ mtr->range_enable = 0x8000;
+ else {
+ mtr->range_enable = 0x0;
+ base->dma_end_e =
+ base->dma_end_o = 0xffffffff;
+ }
+
+
+ switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
+ case 0: /* default */
+ case METEOR_GEO_RGB16:
+ mtr->depth = 2;
+ mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_RGB16;
+ temp = mtr->cols * mtr->depth;
+ /* recal stride and starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ base->dma1o = buf;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width)
+ base->stride1o = mtr->video.width-temp;
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0xd0);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ base->dma1e = buf;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width)
+ base->stride1e = mtr->video.width-temp;
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0xf0);
+ break;
+ default: /* interlaced even/odd */
+ base->dma1e = buf;
+ base->dma1o = buf + temp;
+ base->stride1e = base->stride1o = temp;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width) {
+ base->dma1o = buf + mtr->video.width;
+ base->stride1e = base->stride1o =
+ mtr->video.width -
+ temp + mtr->video.width;
+ }
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0x90);
+ break;
+ }
+ base->routee = base->routeo = 0xeeeeee01;
+ break;
+ case METEOR_GEO_RGB24:
+ mtr->depth = 4;
+ mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_RGB24;
+ temp = mtr->cols * mtr->depth;
+ /* recal stride and starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ base->dma1o = buf;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width)
+ base->stride1o = mtr->video.width-temp;
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0xd2);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ base->dma1e = buf;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width)
+ base->stride1e = mtr->video.width-temp;
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0xf2);
+ break;
+ default: /* interlaced even/odd */
+ base->dma1e = buf;
+ base->dma1o = buf + mtr->cols * mtr->depth;
+ base->stride1e = base->stride1o =
+ mtr->cols * mtr->depth;
+#ifdef METEOR_TEST_VIDEO
+ if(mtr->video.addr && mtr->video.width) {
+ base->dma1o = buf + mtr->video.width;
+ base->stride1e = base->stride1o =
+ mtr->video.width -
+ temp + mtr->video.width;
+ }
+#endif
+ SAA7196_WRITE(mtr, 0x20, 0x92);
+ break;
+ }
+ base->routee= base->routeo= 0x39393900;
+ break;
+ case METEOR_GEO_YUV_PLANAR:
+ mtr->depth = 2;
+ temp = mtr->rows * mtr->cols; /* compute frame size */
+ mtr->frame_size = temp * mtr->depth;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_PLANAR;
+ /* recal stride and starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ base->dma1o = buf; /* Y Odd */
+ base->dma2o = buf + temp; /* U Odd */
+ temp >>= 1;
+ base->dma3o = base->dma2o + temp; /* V Odd */
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ base->dma1e = buf; /* Y Even */
+ base->dma2e = buf + temp; /* U Even */
+ temp >>= 1;
+ base->dma2e= base->dma2e + temp; /* V Even */
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ base->dma1e = buf; /* Y Even */
+ base->dma2e = buf + temp; /* U Even */
+ temp >>= 2;
+ base->dma3e = base->dma2e + temp; /* V Even */
+ base->dma1o = base->dma1e+mtr->cols;/* Y Odd */
+ base->dma2o = base->dma3e + temp; /* U Odd */
+ base->dma3o = base->dma2o + temp; /* V Odd */
+ base->stride1e = base->stride1o = mtr->cols;
+ SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
+ }
+ switch (geo->oformat &
+ (METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) {
+ case METEOR_GEO_YUV_9:
+ base->routee=base->routeo = 0xaaaaffc3;
+ break;
+ case METEOR_GEO_YUV_12:
+ base->routee=base->routeo = 0xaaaaffc2;
+ break;
+ default:
+ base->routee=base->routeo = 0xaaaaffc1;
+ break;
+ }
+ break;
+ case METEOR_GEO_YUV_422:/* same as planer, different uv order */
+ mtr->depth = 2;
+ temp = mtr->rows * mtr->cols; /* compute frame size */
+ mtr->frame_size = temp * mtr->depth;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_422;
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ base->dma1o = buf;
+ base->dma2o = buf + temp;
+ base->dma3o = base->dma2o + (temp >> 1);
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ base->dma1e = buf;
+ base->dma2e = buf + temp;
+ base->dma3e = base->dma2e + (temp >> 1);
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ base->dma1e = buf; /* Y even */
+ base->dma2e = buf + temp; /* U even */
+ base->dma3e =
+ base->dma2e + (temp >> 1);/* V even */
+ base->dma1o = base->dma1e+mtr->cols;/* Y odd */
+ temp = mtr->cols >> 1;
+ base->dma2o = base->dma2e+temp; /* U odd */
+ base->dma3o = base->dma3e+temp; /* V odd */
+ base->stride1e =
+ base->stride1o = mtr->cols; /* Y stride */
+ base->stride2e =
+ base->stride2o = temp; /* U stride */
+ base->stride3e =
+ base->stride3o = temp; /* V stride */
+ SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
+ }
+ switch (geo->oformat &
+ (METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) {
+ case METEOR_GEO_YUV_9:
+ base->routee=base->routeo = 0xaaaaffc3;
+ break;
+ case METEOR_GEO_YUV_12:
+ base->routee=base->routeo = 0xaaaaffc2;
+ break;
+ default:
+ base->routee=base->routeo = 0xaaaaffc1;
+ break;
+ }
+ break;
+ case METEOR_GEO_YUV_PACKED:
+ mtr->depth = 2;
+ mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_PACKED;
+ /* recal stride and odd starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ base->dma1o = buf;
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ base->dma1e = buf;
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ base->dma1e = buf;
+ base->dma1o = buf + mtr->cols * mtr->depth;
+ base->stride1e = base->stride1o =
+ mtr->cols * mtr->depth;
+ SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
+ }
+ base->routee = base->routeo = 0xeeeeee41;
+ break;
+ default:
+ error = EINVAL; /* invalid argument */
+ printf("meteor%d: ioctl: invalid output format\n",unit);
+ break;
+ }
+ /* set cols */
+ SAA7196_WRITE(mtr, 0x21, mtr->cols & 0xff);
+ SAA7196_WRITE(mtr, 0x24,
+ ((SAA7196_REG(mtr, 0x24) & ~0x03) |
+ ((mtr->cols >> 8) & 0x03)));
+ /* set rows */
+ if(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ SAA7196_WRITE(mtr, 0x25, ((mtr->rows) & 0xff));
+ SAA7196_WRITE(mtr, 0x28,
+ ((SAA7196_REG(mtr, 0x28) & ~0x03) |
+ ((mtr->rows >> 8) & 0x03)));
+ } else { /* Interlaced */
+ SAA7196_WRITE(mtr, 0x25, ((mtr->rows >> 1) & 0xff));
+ SAA7196_WRITE(mtr, 0x28,
+ ((SAA7196_REG(mtr, 0x28) & ~0x03) |
+ ((mtr->rows >> 9) & 0x03)));
+ }
+ /* set signed/unsigned chrominance */
+ SAA7196_WRITE(mtr, 0x30, (SAA7196_REG(mtr, 0x30) & ~0x10) |
+ ((geo->oformat&METEOR_GEO_UNSIGNED)?0:0x10));
+ break;
+ case METEORGETGEO:
+ geo = (struct meteor_geomet *) arg;
+ geo->rows = mtr->rows;
+ geo->columns = mtr->cols;
+ geo->frames = mtr->frames;
+ geo->oformat = (mtr->flags & METEOR_OUTPUT_FMT_MASK) |
+ (mtr->flags & METEOR_ONLY_FIELDS_MASK) |
+ (SAA7196_REG(mtr, 0x30) & 0x10 ?
+ 0:METEOR_GEO_UNSIGNED);
+ switch(base->routee & 0xff) {
+ case 0xc3:
+ geo->oformat |= METEOR_GEO_YUV_9;
+ break;
+ case 0xc2:
+ geo->oformat |= METEOR_GEO_YUV_12;
+ break;
+ default:
+ break;
+ }
+ break;
+ case METEORSCOUNT: /* (re)set error counts */
+ cnt = (struct meteor_counts *) arg;
+ mtr->fifo_errors = cnt->fifo_errors;
+ mtr->dma_errors = cnt->dma_errors;
+ mtr->frames_captured = cnt->frames_captured;
+ mtr->even_fields_captured = cnt->even_fields_captured;
+ mtr->odd_fields_captured = cnt->odd_fields_captured;
+ break;
+ case METEORGCOUNT: /* get error counts */
+ cnt = (struct meteor_counts *) arg;
+ cnt->fifo_errors = mtr->fifo_errors;
+ cnt->dma_errors = mtr->dma_errors;
+ cnt->frames_captured = mtr->frames_captured;
+ cnt->even_fields_captured = mtr->even_fields_captured;
+ cnt->odd_fields_captured = mtr->odd_fields_captured;
+ break;
+ default:
+ printf("meteor%d: ioctl: invalid ioctl request\n", unit);
+ error = ENOTTY;
+ break;
+ }
+ return(error);
+}
+
+int
+meteor_mmap(dev_t dev, vm_offset_t offset, int nprot)
+{
+
+ int unit;
+ meteor_reg_t *mtr;
+
+ unit = UNIT(minor(dev));
+ if (unit >= NMETEOR) /* at this point could this happen? */
+ return(-1);
+
+ mtr = &(meteor[unit]);
+
+
+ if(nprot & PROT_EXEC)
+ return -1;
+
+ if(offset >= mtr->alloc_pages * PAGE_SIZE)
+ return -1;
+
+ return i386_btop(vtophys(mtr->bigbuf) + offset);
+}
+#endif
diff --git a/sys/pci/meteor_reg.h b/sys/pci/meteor_reg.h
new file mode 100644
index 0000000..a1f5ecc
--- /dev/null
+++ b/sys/pci/meteor_reg.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1995 Mark Tinguely and Jim Lowe
+ * 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 Mark Tinguely and Jim Lowe
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef PCI_LATENCY_TIMER
+#define PCI_LATENCY_TIMER 0x0c /* pci timer register */
+#endif
+
+/*
+ * Definitions for the Philips SAA7116 digital video to pci interface.
+ */
+#define SAA7116_PHILIPS_ID 0x12238086ul
+#define SAA7116_I2C_WRITE 0x00
+#define SAA7116_I2C_READ 0x01
+#define SAA7116_IIC_NEW_CYCLE 0x1000000L
+#define SAA7116_IIC_DIRECT_TRANSFER_ABORTED 0x0000200L
+
+typedef volatile u_int mreg_t;
+struct saa7116_regs {
+ mreg_t dma1e; /* Base address for even field dma chn 1 */
+ mreg_t dma2e; /* Base address for even field dma chn 2 */
+ mreg_t dma3e; /* Base address for even field dma chn 3 */
+ mreg_t dma1o; /* Base address for odd field dma chn 1 */
+ mreg_t dma2o; /* Base address for odd field dma chn 2 */
+ mreg_t dma3o; /* Base address for odd field dma chn 3 */
+ mreg_t stride1e; /* Address stride for even field dma chn 1 */
+ mreg_t stride2e; /* Address stride for even field dma chn 2 */
+ mreg_t stride3e; /* Address stride for even field dma chn 3 */
+ mreg_t stride1o; /* Address stride for odd field dma chn 1 */
+ mreg_t stride2o; /* Address stride for odd field dma chn 2 */
+ mreg_t stride3o; /* Address stride for odd field dma chn 3 */
+ mreg_t routee; /* Route/mode even */
+ mreg_t routeo; /* Route/mode odd */
+ mreg_t fifo_t; /* FIFO trigger for PCI int */
+ mreg_t field_t; /* Field toggle */
+ mreg_t cap_cntl; /* Capture control */
+ mreg_t retry_wait_cnt; /* Clks for master to wait after disconnect */
+ mreg_t irq_stat; /* IRQ mask and status reg */
+ mreg_t fme; /* Field Mask even */
+ mreg_t fmo; /* Field mask odd */
+ mreg_t fml; /* Field mask length */
+ mreg_t fifo_t_err; /* FIFO almost empty/almost full ptrs */
+ mreg_t i2c_phase; /* i2c phase register */
+ mreg_t i2c_read; /* i2c read register */
+ mreg_t i2c_write; /* i2c write register */
+ mreg_t i2c_auto_a_e; /* i2c auto register a, even */
+ mreg_t i2c_auto_b_e; /* i2c auto register b, even */
+ mreg_t i2c_auto_c_e; /* i2c auto register c, even */
+ mreg_t i2c_auto_d_e; /* i2c auto register d, even */
+ mreg_t i2c_auto_a_o; /* i2c auto register a, odd */
+ mreg_t i2c_auto_b_o; /* i2c auto register b, odd */
+ mreg_t i2c_auto_c_o; /* i2c auto register c, odd */
+ mreg_t i2c_auto_d_o; /* i2c auto register d, odd */
+ mreg_t i2c_auto_enable;/* enable above auto registers */
+ mreg_t dma_end_e; /* DMA end even (range) */
+ mreg_t dma_end_o; /* DMA end odd (range) */
+};
+
+
+/*
+ * Definitions for the Philips SAA7196 digital video decoder,
+ * scalar, and clock generator circuit (DESCpro).
+ */
+#define NUM_SAA7196_I2C_REGS 49
+#define SAA7196_I2C_ADDR 0x40
+#define SAA7196_WRITE(mtr, reg, data) \
+ i2c_write(mtr, SAA7196_I2C_ADDR, SAA7116_I2C_WRITE, reg, data), \
+ mtr->saa7196_i2c[reg] = data
+#define SAA7196_REG(mtr, reg) mtr->saa7196_i2c[reg]
+#define SAA7196_READ(mtr) \
+ i2c_write(mtr, SAA7196_I2C_ADDR, SAA7116_I2C_READ, 0x0, 0x0)
+
+#define SAA7196_IDEL 0x00 /* Increment delay */
+#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */
+#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */
+#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */
+#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */
+#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */
+#define SAA7196_LUMC 0x06 /* Luminance control */
+#define SAA7196_HUEC 0x07 /* Hue control */
+#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */
+#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */
+#define SAA7196_PALS 0x0a /* PAL switch sensitivity */
+#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */
+#define SAA7196_CGAINC 0x0c /* Chroma gain control */
+#define SAA7196_STDC 0x0d /* Standard/Mode control */
+#define SAA7196_IOCC 0x0e /* I/O and Clock Control */
+#define SAA7196_CTRL1 0x0f /* Control #1 */
+#define SAA7196_CTRL2 0x10 /* Control #2 */
+#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */
+#define SAA7196_CSAT 0x12 /* Chroma Saturation */
+#define SAA7196_CONT 0x13 /* Luminance Contrast */
+#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */
+#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */
+#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */
+#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */
+#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */
+#define SAA7196_BRIG 0x19 /* Luminance Brightness */
+#define SAA7196_FMTS 0x20 /* Formats and sequence */
+#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */
+#define SAA7196_INPIX 0x22 /* Input data pixel/line */
+#define SAA7196_HWS 0x23 /* Horiz. window start */
+#define SAA7196_HFILT 0x24 /* Horiz. filter */
+#define SAA7196_OUTLINE 0x25 /* Output data lines/field */
+#define SAA7196_INLINE 0x26 /* Input data lines/field */
+#define SAA7196_VWS 0x27 /* Vertical window start */
+#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */
+#define SAA7196_VBS 0x29 /* Vertical Bypass start */
+#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */
+#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */
+#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */
+#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */
+#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */
+#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */
+#define SAA7196_DPATH 0x30 /* Data path setting */
+
+/*
+ * Defines for the PCF8574.
+ */
+#define NUM_PCF8574_I2C_REGS 2
+#define PCF8574_CTRL_I2C_ADDR 0x70
+#define PCF8574_DATA_I2C_ADDR 0x72
+#define PCF8574_CTRL_WRITE(mtr, data) \
+ i2c_write(mtr, PCF8574_CTRL_I2C_ADDR, SAA7116_I2C_WRITE, data, data), \
+ mtr->pcf_i2c[0] = data
+#define PCF8574_DATA_WRITE(mtr, data) \
+ i2c_write(mtr, PCF8574_DATA_I2C_ADDR, SAA7116_I2C_WRITE, data, data), \
+ mtr->pcf_i2c[1] = data
+#define PCF8574_CTRL_REG(mtr) mtr->pcf_i2c[0]
+#define PCF8574_DATA_REG(mtr) mtr->pcf_i2c[1]
+
+
+/*
+ * Defines for the BT254.
+ */
+#define NUM_BT254_REGS 7
+
+#define BT254_COMMAND 0
+#define BT254_IOUT1 1
+#define BT254_IOUT2 2
+#define BT254_IOUT3 3
+#define BT254_IOUT4 4
+#define BT254_IOUT5 5
+#define BT254_IOUT6 6
+
+/*
+ * Meteor info structure, one per meteor card installed.
+ */
+typedef struct meteor_softc {
+ struct saa7116_regs *base; /* saa7116 register virtual address */
+ vm_offset_t phys_base; /* saa7116 register physical address */
+ pcici_t tag; /* PCI tag, for doing PCI commands */
+ vm_offset_t bigbuf; /* buffer that holds the captured image */
+ int alloc_pages; /* number of pages in bigbuf */
+ struct proc *proc; /* process to receive raised signal */
+ int signal; /* signal to send to process */
+#define METEOR_SIG_MODE_MASK 0xffff0000
+#define METEOR_SIG_FIELD_MODE 0x00010000
+#define METEOR_SIG_FRAME_MODE 0x00000000
+ struct meteor_mem *mem; /* used to control sync. multi-frame output */
+ u_long synch_wait; /* wait for free buffer before continuing */
+ short current; /* frame number in buffer (1-frames) */
+ short rows; /* number of rows in a frame */
+ short cols; /* number of columns in a frame */
+ short depth; /* number of byte per pixel */
+ short frames; /* number of frames allocated */
+ int frame_size; /* number of bytes in a frame */
+ u_long fifo_errors; /* number of fifo capture errors since open */
+ u_long dma_errors; /* number of DMA capture errors since open */
+ u_long frames_captured;/* number of frames captured since open */
+ u_long even_fields_captured; /* number of even fields captured */
+ u_long odd_fields_captured; /* number of odd fields captured */
+ u_long range_enable; /* enable range checking ?? */
+ unsigned flags;
+#define METEOR_INITALIZED 0x00000001
+#define METEOR_OPEN 0x00000002
+#define METEOR_MMAP 0x00000004
+#define METEOR_INTR 0x00000008
+#define METEOR_READ 0x00000010 /* XXX never gets referenced */
+#define METEOR_SINGLE 0x00000020 /* get single frame */
+#define METEOR_CONTIN 0x00000040 /* continuously get frames */
+#define METEOR_SYNCAP 0x00000080 /* synchronously get frames */
+#define METEOR_CAP_MASK 0x000000f0
+#define METEOR_NTSC 0x00000100
+#define METEOR_PAL 0x00000200
+#define METEOR_SECAM 0x00000400
+#define METEOR_AUTOMODE 0x00000800
+#define METEOR_FORM_MASK 0x00000f00
+#define METEOR_DEV0 0x00001000
+#define METEOR_DEV1 0x00002000
+#define METEOR_DEV2 0x00004000
+#define METEOR_DEV3 0x00008000
+#define METEOR_DEV_SVIDEO 0x00006000
+#define METEOR_DEV_RGB 0x0000a000
+#define METEOR_DEV_MASK 0x0000f000
+#define METEOR_RGB16 0x00010000
+#define METEOR_RGB24 0x00020000
+#define METEOR_YUV_PACKED 0x00040000
+#define METEOR_YUV_PLANAR 0x00080000
+#define METEOR_WANT_EVEN 0x00100000 /* want even frame */
+#define METEOR_WANT_ODD 0x00200000 /* want odd frame */
+#define METEOR_WANT_MASK 0x00300000
+#define METEOR_ONLY_EVEN_FIELDS 0x01000000
+#define METEOR_ONLY_ODD_FIELDS 0x02000000
+#define METEOR_ONLY_FIELDS_MASK 0x03000000
+#define METEOR_YUV_422 0x04000000
+#define METEOR_OUTPUT_FMT_MASK 0x040f0000
+#define METEOR_WANT_TS 0x08000000 /* time-stamp a frame */
+#define METEOR_RGB 0x20000000 /* meteor rgb unit */
+#define METEOR_FIELD_MODE 0x80000000
+ u_char saa7196_i2c[NUM_SAA7196_I2C_REGS]; /* saa7196 register values */
+ u_char pcf_i2c[NUM_PCF8574_I2C_REGS]; /* PCF8574 register values */
+ u_char bt254_reg[NUM_BT254_REGS]; /* BT254 register values */
+ u_short fps; /* frames per second */
+#ifdef METEOR_TEST_VIDEO
+ struct meteor_video video;
+#endif
+} meteor_reg_t;
diff --git a/sys/pci/ncr.c b/sys/pci/ncr.c
new file mode 100644
index 0000000..8d6fb90
--- /dev/null
+++ b/sys/pci/ncr.c
@@ -0,0 +1,7163 @@
+/**************************************************************************
+**
+** $FreeBSD$
+**
+** Device driver for the NCR 53C8XX PCI-SCSI-Controller Family.
+**
+**-------------------------------------------------------------------------
+**
+** Written for 386bsd and FreeBSD by
+** Wolfgang Stanglmeier <wolf@cologne.de>
+** Stefan Esser <se@mi.Uni-Koeln.de>
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier. 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. 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 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.
+**
+***************************************************************************
+*/
+
+#define NCR_DATE "pl30 98/1/1"
+
+#define NCR_VERSION (2)
+#define MAX_UNITS (16)
+
+#define NCR_GETCC_WITHMSG
+
+#if defined (__FreeBSD__) && defined(_KERNEL)
+#include "opt_ncr.h"
+#endif
+
+/*==========================================================
+**
+** Configuration and Debugging
+**
+** May be overwritten in <arch/conf/xxxx>
+**
+**==========================================================
+*/
+
+/*
+** SCSI address of this device.
+** The boot routines should have set it.
+** If not, use this.
+*/
+
+#ifndef SCSI_NCR_MYADDR
+#define SCSI_NCR_MYADDR (7)
+#endif /* SCSI_NCR_MYADDR */
+
+/*
+** The default synchronous period factor
+** (0=asynchronous)
+** If maximum synchronous frequency is defined, use it instead.
+*/
+
+#ifndef SCSI_NCR_MAX_SYNC
+
+#ifndef SCSI_NCR_DFLT_SYNC
+#define SCSI_NCR_DFLT_SYNC (12)
+#endif /* SCSI_NCR_DFLT_SYNC */
+
+#else
+
+#if SCSI_NCR_MAX_SYNC == 0
+#define SCSI_NCR_DFLT_SYNC 0
+#else
+#define SCSI_NCR_DFLT_SYNC (250000 / SCSI_NCR_MAX_SYNC)
+#endif
+
+#endif
+
+/*
+** The minimal asynchronous pre-scaler period (ns)
+** Shall be 40.
+*/
+
+#ifndef SCSI_NCR_MIN_ASYNC
+#define SCSI_NCR_MIN_ASYNC (40)
+#endif /* SCSI_NCR_MIN_ASYNC */
+
+/*
+** The maximal bus with (in log2 byte)
+** (0=8 bit, 1=16 bit)
+*/
+
+#ifndef SCSI_NCR_MAX_WIDE
+#define SCSI_NCR_MAX_WIDE (1)
+#endif /* SCSI_NCR_MAX_WIDE */
+
+/*==========================================================
+**
+** Configuration and Debugging
+**
+**==========================================================
+*/
+
+/*
+** Number of targets supported by the driver.
+** n permits target numbers 0..n-1.
+** Default is 7, meaning targets #0..#6.
+** #7 .. is myself.
+*/
+
+#define MAX_TARGET (16)
+
+/*
+** Number of logic units supported by the driver.
+** n enables logic unit numbers 0..n-1.
+** The common SCSI devices require only
+** one lun, so take 1 as the default.
+*/
+
+#ifndef MAX_LUN
+#define MAX_LUN (8)
+#endif /* MAX_LUN */
+
+/*
+** The maximum number of jobs scheduled for starting.
+** There should be one slot per target, and one slot
+** for each tag of each target in use.
+*/
+
+#define MAX_START (256)
+
+/*
+** The maximum number of segments a transfer is split into.
+*/
+
+#define MAX_SCATTER (33)
+
+/*
+** The maximum transfer length (should be >= 64k).
+** MUST NOT be greater than (MAX_SCATTER-1) * PAGE_SIZE.
+*/
+
+#define MAX_SIZE ((MAX_SCATTER-1) * (long) PAGE_SIZE)
+
+/*
+** other
+*/
+
+#define NCR_SNOOP_TIMEOUT (1000000)
+
+/*==========================================================
+**
+** Include files
+**
+**==========================================================
+*/
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <machine/md_var.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#endif
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/ncrreg.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+/*==========================================================
+**
+** Debugging tags
+**
+**==========================================================
+*/
+
+#define DEBUG_ALLOC (0x0001)
+#define DEBUG_PHASE (0x0002)
+#define DEBUG_POLL (0x0004)
+#define DEBUG_QUEUE (0x0008)
+#define DEBUG_RESULT (0x0010)
+#define DEBUG_SCATTER (0x0020)
+#define DEBUG_SCRIPT (0x0040)
+#define DEBUG_TINY (0x0080)
+#define DEBUG_TIMING (0x0100)
+#define DEBUG_NEGO (0x0200)
+#define DEBUG_TAGS (0x0400)
+#define DEBUG_FREEZE (0x0800)
+#define DEBUG_RESTART (0x1000)
+
+/*
+** Enable/Disable debug messages.
+** Can be changed at runtime too.
+*/
+#ifdef SCSI_NCR_DEBUG
+ #define DEBUG_FLAGS ncr_debug
+#else /* SCSI_NCR_DEBUG */
+ #define SCSI_NCR_DEBUG 0
+ #define DEBUG_FLAGS 0
+#endif /* SCSI_NCR_DEBUG */
+
+
+
+/*==========================================================
+**
+** assert ()
+**
+**==========================================================
+**
+** modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
+
+#ifdef DIAGNOSTIC
+#define assert(expression) { \
+ if (!(expression)) { \
+ (void)printf("assertion \"%s\" failed: " \
+ "file \"%s\", line %d\n", \
+ #expression, __FILE__, __LINE__); \
+ Debugger(""); \
+ } \
+}
+#else
+#define assert(expression) { \
+ if (!(expression)) { \
+ (void)printf("assertion \"%s\" failed: " \
+ "file \"%s\", line %d\n", \
+ #expression, __FILE__, __LINE__); \
+ } \
+}
+#endif
+
+/*==========================================================
+**
+** Access to the controller chip.
+**
+**==========================================================
+*/
+
+#ifdef __alpha__
+/* XXX */
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
+
+#define INB(r) bus_space_read_1(np->bst, np->bsh, offsetof(struct ncr_reg, r))
+#define INW(r) bus_space_read_2(np->bst, np->bsh, offsetof(struct ncr_reg, r))
+#define INL(r) bus_space_read_4(np->bst, np->bsh, offsetof(struct ncr_reg, r))
+
+#define OUTB(r, val) bus_space_write_1(np->bst, np->bsh, \
+ offsetof(struct ncr_reg, r), val)
+#define OUTW(r, val) bus_space_write_2(np->bst, np->bsh, \
+ offsetof(struct ncr_reg, r), val)
+#define OUTL(r, val) bus_space_write_4(np->bst, np->bsh, \
+ offsetof(struct ncr_reg, r), val)
+#define OUTL_OFF(o, val) bus_space_write_4(np->bst, np->bsh, o, val)
+
+#define INB_OFF(o) bus_space_read_1(np->bst, np->bsh, o)
+#define INW_OFF(o) bus_space_read_2(np->bst, np->bsh, o)
+#define INL_OFF(o) bus_space_read_4(np->bst, np->bsh, o)
+
+#define READSCRIPT_OFF(base, off) \
+ (base ? *((volatile u_int32_t *)((volatile char *)base + (off))) : \
+ bus_space_read_4(np->bst2, np->bsh2, off))
+
+#define WRITESCRIPT_OFF(base, off, val) \
+ do { \
+ if (base) \
+ *((volatile u_int32_t *) \
+ ((volatile char *)base + (off))) = (val); \
+ else \
+ bus_space_write_4(np->bst2, np->bsh2, off, val); \
+ } while (0)
+
+#define READSCRIPT(r) \
+ READSCRIPT_OFF(np->script, offsetof(struct script, r))
+
+#define WRITESCRIPT(r, val) \
+ WRITESCRIPT_OFF(np->script, offsetof(struct script, r), val)
+
+/*
+** Set bit field ON, OFF
+*/
+
+#define OUTONB(r, m) OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m) OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m) OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m))
+
+/*==========================================================
+**
+** Command control block states.
+**
+**==========================================================
+*/
+
+#define HS_IDLE (0)
+#define HS_BUSY (1)
+#define HS_NEGOTIATE (2) /* sync/wide data transfer*/
+#define HS_DISCONNECT (3) /* Disconnected by target */
+
+#define HS_COMPLETE (4)
+#define HS_SEL_TIMEOUT (5) /* Selection timeout */
+#define HS_RESET (6) /* SCSI reset */
+#define HS_ABORTED (7) /* Transfer aborted */
+#define HS_TIMEOUT (8) /* Software timeout */
+#define HS_FAIL (9) /* SCSI or PCI bus errors */
+#define HS_UNEXPECTED (10) /* Unexpected disconnect */
+#define HS_STALL (11) /* QUEUE FULL or BUSY */
+
+#define HS_DONEMASK (0xfc)
+
+/*==========================================================
+**
+** Software Interrupt Codes
+**
+**==========================================================
+*/
+
+#define SIR_SENSE_RESTART (1)
+#define SIR_SENSE_FAILED (2)
+#define SIR_STALL_RESTART (3)
+#define SIR_STALL_QUEUE (4)
+#define SIR_NEGO_SYNC (5)
+#define SIR_NEGO_WIDE (6)
+#define SIR_NEGO_FAILED (7)
+#define SIR_NEGO_PROTO (8)
+#define SIR_REJECT_RECEIVED (9)
+#define SIR_REJECT_SENT (10)
+#define SIR_IGN_RESIDUE (11)
+#define SIR_MISSING_SAVE (12)
+#define SIR_MAX (12)
+
+/*==========================================================
+**
+** Extended error codes.
+** xerr_status field of struct nccb.
+**
+**==========================================================
+*/
+
+#define XE_OK (0)
+#define XE_EXTRA_DATA (1) /* unexpected data phase */
+#define XE_BAD_PHASE (2) /* illegal phase (4/5) */
+
+/*==========================================================
+**
+** Negotiation status.
+** nego_status field of struct nccb.
+**
+**==========================================================
+*/
+
+#define NS_SYNC (1)
+#define NS_WIDE (2)
+
+/*==========================================================
+**
+** XXX These are no longer used. Remove once the
+** script is updated.
+** "Special features" of targets.
+** quirks field of struct tcb.
+** actualquirks field of struct nccb.
+**
+**==========================================================
+*/
+
+#define QUIRK_AUTOSAVE (0x01)
+#define QUIRK_NOMSG (0x02)
+#define QUIRK_NOSYNC (0x10)
+#define QUIRK_NOWIDE16 (0x20)
+#define QUIRK_NOTAGS (0x40)
+#define QUIRK_UPDATE (0x80)
+
+/*==========================================================
+**
+** Misc.
+**
+**==========================================================
+*/
+
+#define CCB_MAGIC (0xf2691ad2)
+#define MAX_TAGS (32) /* hard limit */
+
+/*==========================================================
+**
+** OS dependencies.
+**
+**==========================================================
+*/
+
+#define PRINT_ADDR(ccb) xpt_print_path((ccb)->ccb_h.path)
+
+/*==========================================================
+**
+** Declaration of structs.
+**
+**==========================================================
+*/
+
+struct tcb;
+struct lcb;
+struct nccb;
+struct ncb;
+struct script;
+
+typedef struct ncb * ncb_p;
+typedef struct tcb * tcb_p;
+typedef struct lcb * lcb_p;
+typedef struct nccb * nccb_p;
+
+struct link {
+ ncrcmd l_cmd;
+ ncrcmd l_paddr;
+};
+
+struct usrcmd {
+ u_long target;
+ u_long lun;
+ u_long data;
+ u_long cmd;
+};
+
+#define UC_SETSYNC 10
+#define UC_SETTAGS 11
+#define UC_SETDEBUG 12
+#define UC_SETORDER 13
+#define UC_SETWIDE 14
+#define UC_SETFLAG 15
+
+#define UF_TRACE (0x01)
+
+/*---------------------------------------
+**
+** Timestamps for profiling
+**
+**---------------------------------------
+*/
+
+/* Type of the kernel variable `ticks'. XXX should be declared with the var. */
+typedef int ticks_t;
+
+struct tstamp {
+ ticks_t start;
+ ticks_t end;
+ ticks_t select;
+ ticks_t command;
+ ticks_t data;
+ ticks_t status;
+ ticks_t disconnect;
+};
+
+/*
+** profiling data (per device)
+*/
+
+struct profile {
+ u_long num_trans;
+ u_long num_bytes;
+ u_long num_disc;
+ u_long num_break;
+ u_long num_int;
+ u_long num_fly;
+ u_long ms_setup;
+ u_long ms_data;
+ u_long ms_disc;
+ u_long ms_post;
+};
+
+/*==========================================================
+**
+** Declaration of structs: target control block
+**
+**==========================================================
+*/
+
+#define NCR_TRANS_CUR 0x01 /* Modify current neogtiation status */
+#define NCR_TRANS_ACTIVE 0x03 /* Assume this is the active target */
+#define NCR_TRANS_GOAL 0x04 /* Modify negotiation goal */
+#define NCR_TRANS_USER 0x08 /* Modify user negotiation settings */
+
+struct ncr_transinfo {
+ u_int8_t width;
+ u_int8_t period;
+ u_int8_t offset;
+};
+
+struct ncr_target_tinfo {
+ /* Hardware version of our sync settings */
+ u_int8_t disc_tag;
+#define NCR_CUR_DISCENB 0x01
+#define NCR_CUR_TAGENB 0x02
+#define NCR_USR_DISCENB 0x04
+#define NCR_USR_TAGENB 0x08
+ u_int8_t sval;
+ struct ncr_transinfo current;
+ struct ncr_transinfo goal;
+ struct ncr_transinfo user;
+ /* Hardware version of our wide settings */
+ u_int8_t wval;
+};
+
+struct tcb {
+ /*
+ ** during reselection the ncr jumps to this point
+ ** with SFBR set to the encoded target number
+ ** with bit 7 set.
+ ** if it's not this target, jump to the next.
+ **
+ ** JUMP IF (SFBR != #target#)
+ ** @(next tcb)
+ */
+
+ struct link jump_tcb;
+
+ /*
+ ** load the actual values for the sxfer and the scntl3
+ ** register (sync/wide mode).
+ **
+ ** SCR_COPY (1);
+ ** @(sval field of this tcb)
+ ** @(sxfer register)
+ ** SCR_COPY (1);
+ ** @(wval field of this tcb)
+ ** @(scntl3 register)
+ */
+
+ ncrcmd getscr[6];
+
+ /*
+ ** if next message is "identify"
+ ** then load the message to SFBR,
+ ** else load 0 to SFBR.
+ **
+ ** CALL
+ ** <RESEL_LUN>
+ */
+
+ struct link call_lun;
+
+ /*
+ ** now look for the right lun.
+ **
+ ** JUMP
+ ** @(first nccb of this lun)
+ */
+
+ struct link jump_lcb;
+
+ /*
+ ** pointer to interrupted getcc nccb
+ */
+
+ nccb_p hold_cp;
+
+ /*
+ ** pointer to nccb used for negotiating.
+ ** Avoid to start a nego for all queued commands
+ ** when tagged command queuing is enabled.
+ */
+
+ nccb_p nego_cp;
+
+ /*
+ ** statistical data
+ */
+
+ u_long transfers;
+ u_long bytes;
+
+ /*
+ ** user settable limits for sync transfer
+ ** and tagged commands.
+ */
+
+ struct ncr_target_tinfo tinfo;
+
+ /*
+ ** the lcb's of this tcb
+ */
+
+ lcb_p lp[MAX_LUN];
+};
+
+/*==========================================================
+**
+** Declaration of structs: lun control block
+**
+**==========================================================
+*/
+
+struct lcb {
+ /*
+ ** during reselection the ncr jumps to this point
+ ** with SFBR set to the "Identify" message.
+ ** if it's not this lun, jump to the next.
+ **
+ ** JUMP IF (SFBR != #lun#)
+ ** @(next lcb of this target)
+ */
+
+ struct link jump_lcb;
+
+ /*
+ ** if next message is "simple tag",
+ ** then load the tag to SFBR,
+ ** else load 0 to SFBR.
+ **
+ ** CALL
+ ** <RESEL_TAG>
+ */
+
+ struct link call_tag;
+
+ /*
+ ** now look for the right nccb.
+ **
+ ** JUMP
+ ** @(first nccb of this lun)
+ */
+
+ struct link jump_nccb;
+
+ /*
+ ** start of the nccb chain
+ */
+
+ nccb_p next_nccb;
+
+ /*
+ ** Control of tagged queueing
+ */
+
+ u_char reqnccbs;
+ u_char reqlink;
+ u_char actlink;
+ u_char usetags;
+ u_char lasttag;
+};
+
+/*==========================================================
+**
+** Declaration of structs: COMMAND control block
+**
+**==========================================================
+**
+** This substructure is copied from the nccb to a
+** global address after selection (or reselection)
+** and copied back before disconnect.
+**
+** These fields are accessible to the script processor.
+**
+**----------------------------------------------------------
+*/
+
+struct head {
+ /*
+ ** Execution of a nccb starts at this point.
+ ** It's a jump to the "SELECT" label
+ ** of the script.
+ **
+ ** After successful selection the script
+ ** processor overwrites it with a jump to
+ ** the IDLE label of the script.
+ */
+
+ struct link launch;
+
+ /*
+ ** Saved data pointer.
+ ** Points to the position in the script
+ ** responsible for the actual transfer
+ ** of data.
+ ** It's written after reception of a
+ ** "SAVE_DATA_POINTER" message.
+ ** The goalpointer points after
+ ** the last transfer command.
+ */
+
+ u_int32_t savep;
+ u_int32_t lastp;
+ u_int32_t goalp;
+
+ /*
+ ** The virtual address of the nccb
+ ** containing this header.
+ */
+
+ nccb_p cp;
+
+ /*
+ ** space for some timestamps to gather
+ ** profiling data about devices and this driver.
+ */
+
+ struct tstamp stamp;
+
+ /*
+ ** status fields.
+ */
+
+ u_char status[8];
+};
+
+/*
+** The status bytes are used by the host and the script processor.
+**
+** The first four byte are copied to the scratchb register
+** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
+** and copied back just after disconnecting.
+** Inside the script the XX_REG are used.
+**
+** The last four bytes are used inside the script by "COPY" commands.
+** Because source and destination must have the same alignment
+** in a longword, the fields HAVE to be at the choosen offsets.
+** xerr_st (4) 0 (0x34) scratcha
+** sync_st (5) 1 (0x05) sxfer
+** wide_st (7) 3 (0x03) scntl3
+*/
+
+/*
+** First four bytes (script)
+*/
+#define QU_REG scr0
+#define HS_REG scr1
+#define HS_PRT nc_scr1
+#define SS_REG scr2
+#define PS_REG scr3
+
+/*
+** First four bytes (host)
+*/
+#define actualquirks phys.header.status[0]
+#define host_status phys.header.status[1]
+#define s_status phys.header.status[2]
+#define parity_status phys.header.status[3]
+
+/*
+** Last four bytes (script)
+*/
+#define xerr_st header.status[4] /* MUST be ==0 mod 4 */
+#define sync_st header.status[5] /* MUST be ==1 mod 4 */
+#define nego_st header.status[6]
+#define wide_st header.status[7] /* MUST be ==3 mod 4 */
+
+/*
+** Last four bytes (host)
+*/
+#define xerr_status phys.xerr_st
+#define sync_status phys.sync_st
+#define nego_status phys.nego_st
+#define wide_status phys.wide_st
+
+/*==========================================================
+**
+** Declaration of structs: Data structure block
+**
+**==========================================================
+**
+** During execution of a nccb by the script processor,
+** the DSA (data structure address) register points
+** to this substructure of the nccb.
+** This substructure contains the header with
+** the script-processor-changable data and
+** data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+struct dsb {
+
+ /*
+ ** Header.
+ ** Has to be the first entry,
+ ** because it's jumped to by the
+ ** script processor
+ */
+
+ struct head header;
+
+ /*
+ ** Table data for Script
+ */
+
+ struct scr_tblsel select;
+ struct scr_tblmove smsg ;
+ struct scr_tblmove smsg2 ;
+ struct scr_tblmove cmd ;
+ struct scr_tblmove scmd ;
+ struct scr_tblmove sense ;
+ struct scr_tblmove data [MAX_SCATTER];
+};
+
+/*==========================================================
+**
+** Declaration of structs: Command control block.
+**
+**==========================================================
+**
+** During execution of a nccb by the script processor,
+** the DSA (data structure address) register points
+** to this substructure of the nccb.
+** This substructure contains the header with
+** the script-processor-changable data and then
+** data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+
+struct nccb {
+ /*
+ ** This filler ensures that the global header is
+ ** cache line size aligned.
+ */
+ ncrcmd filler[4];
+
+ /*
+ ** during reselection the ncr jumps to this point.
+ ** If a "SIMPLE_TAG" message was received,
+ ** then SFBR is set to the tag.
+ ** else SFBR is set to 0
+ ** If looking for another tag, jump to the next nccb.
+ **
+ ** JUMP IF (SFBR != #TAG#)
+ ** @(next nccb of this lun)
+ */
+
+ struct link jump_nccb;
+
+ /*
+ ** After execution of this call, the return address
+ ** (in the TEMP register) points to the following
+ ** data structure block.
+ ** So copy it to the DSA register, and start
+ ** processing of this data structure.
+ **
+ ** CALL
+ ** <RESEL_TMP>
+ */
+
+ struct link call_tmp;
+
+ /*
+ ** This is the data structure which is
+ ** to be executed by the script processor.
+ */
+
+ struct dsb phys;
+
+ /*
+ ** If a data transfer phase is terminated too early
+ ** (after reception of a message (i.e. DISCONNECT)),
+ ** we have to prepare a mini script to transfer
+ ** the rest of the data.
+ */
+
+ ncrcmd patch[8];
+
+ /*
+ ** The general SCSI driver provides a
+ ** pointer to a control block.
+ */
+
+ union ccb *ccb;
+
+ /*
+ ** We prepare a message to be sent after selection,
+ ** and a second one to be sent after getcc selection.
+ ** Contents are IDENTIFY and SIMPLE_TAG.
+ ** While negotiating sync or wide transfer,
+ ** a SDTM or WDTM message is appended.
+ */
+
+ u_char scsi_smsg [8];
+ u_char scsi_smsg2[8];
+
+ /*
+ ** Lock this nccb.
+ ** Flag is used while looking for a free nccb.
+ */
+
+ u_long magic;
+
+ /*
+ ** Physical address of this instance of nccb
+ */
+
+ u_long p_nccb;
+
+ /*
+ ** Completion time out for this job.
+ ** It's set to time of start + allowed number of seconds.
+ */
+
+ time_t tlimit;
+
+ /*
+ ** All nccbs of one hostadapter are chained.
+ */
+
+ nccb_p link_nccb;
+
+ /*
+ ** All nccbs of one target/lun are chained.
+ */
+
+ nccb_p next_nccb;
+
+ /*
+ ** Sense command
+ */
+
+ u_char sensecmd[6];
+
+ /*
+ ** Tag for this transfer.
+ ** It's patched into jump_nccb.
+ ** If it's not zero, a SIMPLE_TAG
+ ** message is included in smsg.
+ */
+
+ u_char tag;
+};
+
+#define CCB_PHYS(cp,lbl) (cp->p_nccb + offsetof(struct nccb, lbl))
+
+/*==========================================================
+**
+** Declaration of structs: NCR device descriptor
+**
+**==========================================================
+*/
+
+struct ncb {
+ /*
+ ** The global header.
+ ** Accessible to both the host and the
+ ** script-processor.
+ ** We assume it is cache line size aligned.
+ */
+ struct head header;
+
+ int unit;
+
+ /*-----------------------------------------------
+ ** Scripts ..
+ **-----------------------------------------------
+ **
+ ** During reselection the ncr jumps to this point.
+ ** The SFBR register is loaded with the encoded target id.
+ **
+ ** Jump to the first target.
+ **
+ ** JUMP
+ ** @(next tcb)
+ */
+ struct link jump_tcb;
+
+ /*-----------------------------------------------
+ ** Configuration ..
+ **-----------------------------------------------
+ **
+ ** virtual and physical addresses
+ ** of the 53c810 chip.
+ */
+ int reg_rid;
+ struct resource *reg_res;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ int sram_rid;
+ struct resource *sram_res;
+ bus_space_tag_t bst2;
+ bus_space_handle_t bsh2;
+
+ struct resource *irq_res;
+ void *irq_handle;
+
+ /*
+ ** Scripts instance virtual address.
+ */
+ struct script *script;
+ struct scripth *scripth;
+
+ /*
+ ** Scripts instance physical address.
+ */
+ u_long p_script;
+ u_long p_scripth;
+
+ /*
+ ** The SCSI address of the host adapter.
+ */
+ u_char myaddr;
+
+ /*
+ ** timing parameters
+ */
+ u_char minsync; /* Minimum sync period factor */
+ u_char maxsync; /* Maximum sync period factor */
+ u_char maxoffs; /* Max scsi offset */
+ u_char clock_divn; /* Number of clock divisors */
+ u_long clock_khz; /* SCSI clock frequency in KHz */
+ u_long features; /* Chip features map */
+ u_char multiplier; /* Clock multiplier (1,2,4) */
+
+ u_char maxburst; /* log base 2 of dwords burst */
+
+ /*
+ ** BIOS supplied PCI bus options
+ */
+ u_char rv_scntl3;
+ u_char rv_dcntl;
+ u_char rv_dmode;
+ u_char rv_ctest3;
+ u_char rv_ctest4;
+ u_char rv_ctest5;
+ u_char rv_gpcntl;
+ u_char rv_stest2;
+
+ /*-----------------------------------------------
+ ** CAM SIM information for this instance
+ **-----------------------------------------------
+ */
+
+ struct cam_sim *sim;
+ struct cam_path *path;
+
+ /*-----------------------------------------------
+ ** Job control
+ **-----------------------------------------------
+ **
+ ** Commands from user
+ */
+ struct usrcmd user;
+
+ /*
+ ** Target data
+ */
+ struct tcb target[MAX_TARGET];
+
+ /*
+ ** Start queue.
+ */
+ u_int32_t squeue [MAX_START];
+ u_short squeueput;
+
+ /*
+ ** Timeout handler
+ */
+ time_t heartbeat;
+ u_short ticks;
+ u_short latetime;
+ time_t lasttime;
+ struct callout_handle timeout_ch;
+
+ /*-----------------------------------------------
+ ** Debug and profiling
+ **-----------------------------------------------
+ **
+ ** register dump
+ */
+ struct ncr_reg regdump;
+ time_t regtime;
+
+ /*
+ ** Profiling data
+ */
+ struct profile profile;
+ u_long disc_phys;
+ u_long disc_ref;
+
+ /*
+ ** Head of list of all nccbs for this controller.
+ */
+ nccb_p link_nccb;
+
+ /*
+ ** message buffers.
+ ** Should be longword aligned,
+ ** because they're written with a
+ ** COPY script command.
+ */
+ u_char msgout[8];
+ u_char msgin [8];
+ u_int32_t lastmsg;
+
+ /*
+ ** Buffer for STATUS_IN phase.
+ */
+ u_char scratch;
+
+ /*
+ ** controller chip dependent maximal transfer width.
+ */
+ u_char maxwide;
+
+#ifdef NCR_IOMAPPED
+ /*
+ ** address of the ncr control registers in io space
+ */
+ pci_port_t port;
+#endif
+};
+
+#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
+#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl))
+
+/*==========================================================
+**
+**
+** Script for NCR-Processor.
+**
+** Use ncr_script_fill() to create the variable parts.
+** Use ncr_script_copy_and_bind() to make a copy and
+** bind to physical addresses.
+**
+**
+**==========================================================
+**
+** We have to know the offsets of all labels before
+** we reach them (for forward jumps).
+** Therefore we declare a struct here.
+** If you make changes inside the script,
+** DONT FORGET TO CHANGE THE LENGTHS HERE!
+**
+**----------------------------------------------------------
+*/
+
+/*
+** Script fragments which are loaded into the on-board RAM
+** of 825A, 875 and 895 chips.
+*/
+struct script {
+ ncrcmd start [ 7];
+ ncrcmd start0 [ 2];
+ ncrcmd start1 [ 3];
+ ncrcmd startpos [ 1];
+ ncrcmd trysel [ 8];
+ ncrcmd skip [ 8];
+ ncrcmd skip2 [ 3];
+ ncrcmd idle [ 2];
+ ncrcmd select [ 18];
+ ncrcmd prepare [ 4];
+ ncrcmd loadpos [ 14];
+ ncrcmd prepare2 [ 24];
+ ncrcmd setmsg [ 5];
+ ncrcmd clrack [ 2];
+ ncrcmd dispatch [ 33];
+ ncrcmd no_data [ 17];
+ ncrcmd checkatn [ 10];
+ ncrcmd command [ 15];
+ ncrcmd status [ 27];
+ ncrcmd msg_in [ 26];
+ ncrcmd msg_bad [ 6];
+ ncrcmd complete [ 13];
+ ncrcmd cleanup [ 12];
+ ncrcmd cleanup0 [ 9];
+ ncrcmd signal [ 12];
+ ncrcmd save_dp [ 5];
+ ncrcmd restore_dp [ 5];
+ ncrcmd disconnect [ 12];
+ ncrcmd disconnect0 [ 5];
+ ncrcmd disconnect1 [ 23];
+ ncrcmd msg_out [ 9];
+ ncrcmd msg_out_done [ 7];
+ ncrcmd badgetcc [ 6];
+ ncrcmd reselect [ 8];
+ ncrcmd reselect1 [ 8];
+ ncrcmd reselect2 [ 8];
+ ncrcmd resel_tmp [ 5];
+ ncrcmd resel_lun [ 18];
+ ncrcmd resel_tag [ 24];
+ ncrcmd data_in [MAX_SCATTER * 4 + 7];
+ ncrcmd data_out [MAX_SCATTER * 4 + 7];
+};
+
+/*
+** Script fragments which stay in main memory for all chips.
+*/
+struct scripth {
+ ncrcmd tryloop [MAX_START*5+2];
+ ncrcmd msg_parity [ 6];
+ ncrcmd msg_reject [ 8];
+ ncrcmd msg_ign_residue [ 32];
+ ncrcmd msg_extended [ 18];
+ ncrcmd msg_ext_2 [ 18];
+ ncrcmd msg_wdtr [ 27];
+ ncrcmd msg_ext_3 [ 18];
+ ncrcmd msg_sdtr [ 27];
+ ncrcmd msg_out_abort [ 10];
+ ncrcmd getcc [ 4];
+ ncrcmd getcc1 [ 5];
+#ifdef NCR_GETCC_WITHMSG
+ ncrcmd getcc2 [ 29];
+#else
+ ncrcmd getcc2 [ 14];
+#endif
+ ncrcmd getcc3 [ 6];
+ ncrcmd aborttag [ 4];
+ ncrcmd abort [ 22];
+ ncrcmd snooptest [ 9];
+ ncrcmd snoopend [ 2];
+};
+
+/*==========================================================
+**
+**
+** Function headers.
+**
+**
+**==========================================================
+*/
+
+#ifdef _KERNEL
+static nccb_p ncr_alloc_nccb (ncb_p np, u_long target, u_long lun);
+static void ncr_complete (ncb_p np, nccb_p cp);
+static int ncr_delta (int * from, int * to);
+static void ncr_exception (ncb_p np);
+static void ncr_free_nccb (ncb_p np, nccb_p cp);
+static void ncr_freeze_devq (ncb_p np, struct cam_path *path);
+static void ncr_selectclock (ncb_p np, u_char scntl3);
+static void ncr_getclock (ncb_p np, u_char multiplier);
+static nccb_p ncr_get_nccb (ncb_p np, u_long t,u_long l);
+#if 0
+static u_int32_t ncr_info (int unit);
+#endif
+static void ncr_init (ncb_p np, char * msg, u_long code);
+static void ncr_intr (void *vnp);
+static void ncr_int_ma (ncb_p np, u_char dstat);
+static void ncr_int_sir (ncb_p np);
+static void ncr_int_sto (ncb_p np);
+#if 0
+static void ncr_min_phys (struct buf *bp);
+#endif
+static void ncr_poll (struct cam_sim *sim);
+static void ncb_profile (ncb_p np, nccb_p cp);
+static void ncr_script_copy_and_bind
+ (ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
+static void ncr_script_fill (struct script * scr, struct scripth *scrh);
+static int ncr_scatter (struct dsb* phys, vm_offset_t vaddr,
+ vm_size_t datalen);
+static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp,
+ u_char *scntl3p);
+static void ncr_setsync (ncb_p np, nccb_p cp,u_char scntl3,u_char sxfer,
+ u_char period);
+static void ncr_setwide (ncb_p np, nccb_p cp, u_char wide, u_char ack);
+static int ncr_show_msg (u_char * msg);
+static int ncr_snooptest (ncb_p np);
+static void ncr_action (struct cam_sim *sim, union ccb *ccb);
+static void ncr_timeout (void *arg);
+static void ncr_wakeup (ncb_p np, u_long code);
+
+static int ncr_probe (device_t dev);
+static int ncr_attach (device_t dev);
+
+#endif /* _KERNEL */
+
+/*==========================================================
+**
+**
+** Global static data.
+**
+**
+**==========================================================
+*/
+
+
+#if !defined(lint)
+static const char ident[] =
+ "\n$FreeBSD$\n";
+#endif
+
+static const u_long ncr_version = NCR_VERSION * 11
+ + (u_long) sizeof (struct ncb) * 7
+ + (u_long) sizeof (struct nccb) * 5
+ + (u_long) sizeof (struct lcb) * 3
+ + (u_long) sizeof (struct tcb) * 2;
+
+#ifdef _KERNEL
+
+static int ncr_debug = SCSI_NCR_DEBUG;
+SYSCTL_INT(_debug, OID_AUTO, ncr_debug, CTLFLAG_RW, &ncr_debug, 0, "");
+
+static int ncr_cache; /* to be aligned _NOT_ static */
+
+/*==========================================================
+**
+**
+** Global static data: auto configure
+**
+**
+**==========================================================
+*/
+
+#define NCR_810_ID (0x00011000ul)
+#define NCR_815_ID (0x00041000ul)
+#define NCR_820_ID (0x00021000ul)
+#define NCR_825_ID (0x00031000ul)
+#define NCR_860_ID (0x00061000ul)
+#define NCR_875_ID (0x000f1000ul)
+#define NCR_875_ID2 (0x008f1000ul)
+#define NCR_885_ID (0x000d1000ul)
+#define NCR_895_ID (0x000c1000ul)
+#define NCR_896_ID (0x000b1000ul)
+#define NCR_895A_ID (0x00121000ul)
+#define NCR_1510D_ID (0x000a1000ul)
+
+
+static char *ncr_name (ncb_p np)
+{
+ static char name[10];
+ snprintf(name, sizeof(name), "ncr%d", np->unit);
+ return (name);
+}
+
+/*==========================================================
+**
+**
+** Scripts for NCR-Processor.
+**
+** Use ncr_script_bind for binding to physical addresses.
+**
+**
+**==========================================================
+**
+** NADDR generates a reference to a field of the controller data.
+** PADDR generates a reference to another part of the script.
+** RADDR generates a reference to a script processor register.
+** FADDR generates a reference to a script processor register
+** with offset.
+**
+**----------------------------------------------------------
+*/
+
+#define RELOC_SOFTC 0x40000000
+#define RELOC_LABEL 0x50000000
+#define RELOC_REGISTER 0x60000000
+#define RELOC_KVAR 0x70000000
+#define RELOC_LABELH 0x80000000
+#define RELOC_MASK 0xf0000000
+
+#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label))
+#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label))
+#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label))
+#define RADDR(label) (RELOC_REGISTER | REG(label))
+#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
+#define KVAR(which) (RELOC_KVAR | (which))
+
+#define KVAR_SECOND (0)
+#define KVAR_TICKS (1)
+#define KVAR_NCR_CACHE (2)
+
+#define SCRIPT_KVAR_FIRST (0)
+#define SCRIPT_KVAR_LAST (3)
+
+/*
+ * Kernel variables referenced in the scripts.
+ * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
+ */
+static void *script_kvars[] =
+ { &time_second, &ticks, &ncr_cache };
+
+static struct script script0 = {
+/*--------------------------< START >-----------------------*/ {
+ /*
+ ** Claim to be still alive ...
+ */
+ SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)),
+ KVAR (KVAR_SECOND),
+ NADDR (heartbeat),
+ /*
+ ** Make data structure address invalid.
+ ** clear SIGP.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_FROM_REG (ctest2),
+ 0,
+}/*-------------------------< START0 >----------------------*/,{
+ /*
+ ** Hook for interrupted GetConditionCode.
+ ** Will be patched to ... IFTRUE by
+ ** the interrupt handler.
+ */
+ SCR_INT ^ IFFALSE (0),
+ SIR_SENSE_RESTART,
+
+}/*-------------------------< START1 >----------------------*/,{
+ /*
+ ** Hook for stalled start queue.
+ ** Will be patched to IFTRUE by the interrupt handler.
+ */
+ SCR_INT ^ IFFALSE (0),
+ SIR_STALL_RESTART,
+ /*
+ ** Then jump to a certain point in tryloop.
+ ** Due to the lack of indirect addressing the code
+ ** is self modifying here.
+ */
+ SCR_JUMP,
+}/*-------------------------< STARTPOS >--------------------*/,{
+ PADDRH(tryloop),
+
+}/*-------------------------< TRYSEL >----------------------*/,{
+ /*
+ ** Now:
+ ** DSA: Address of a Data Structure
+ ** or Address of the IDLE-Label.
+ **
+ ** TEMP: Address of a script, which tries to
+ ** start the NEXT entry.
+ **
+ ** Save the TEMP register into the SCRATCHA register.
+ ** Then copy the DSA to TEMP and RETURN.
+ ** This is kind of an indirect jump.
+ ** (The script processor has NO stack, so the
+ ** CALL is actually a jump and link, and the
+ ** RETURN is an indirect jump.)
+ **
+ ** If the slot was empty, DSA contains the address
+ ** of the IDLE part of this script. The processor
+ ** jumps to IDLE and waits for a reselect.
+ ** It will wake up and try the same slot again
+ ** after the SIGP bit becomes set by the host.
+ **
+ ** If the slot was not empty, DSA contains
+ ** the address of the phys-part of a nccb.
+ ** The processor jumps to this address.
+ ** phys starts with head,
+ ** head starts with launch,
+ ** so actually the processor jumps to
+ ** the lauch part.
+ ** If the entry is scheduled for execution,
+ ** then launch contains a jump to SELECT.
+ ** If it's not scheduled, it contains a jump to IDLE.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ RADDR (scratcha),
+ SCR_COPY (4),
+ RADDR (dsa),
+ RADDR (temp),
+ SCR_RETURN,
+ 0
+
+}/*-------------------------< SKIP >------------------------*/,{
+ /*
+ ** This entry has been canceled.
+ ** Next time use the next slot.
+ */
+ SCR_COPY (4),
+ RADDR (scratcha),
+ PADDR (startpos),
+ /*
+ ** patch the launch field.
+ ** should look like an idle process.
+ */
+ SCR_COPY_F (4),
+ RADDR (dsa),
+ PADDR (skip2),
+ SCR_COPY (8),
+ PADDR (idle),
+}/*-------------------------< SKIP2 >-----------------------*/,{
+ 0,
+ SCR_JUMP,
+ PADDR(start),
+}/*-------------------------< IDLE >------------------------*/,{
+ /*
+ ** Nothing to do?
+ ** Wait for reselect.
+ */
+ SCR_JUMP,
+ PADDR(reselect),
+
+}/*-------------------------< SELECT >----------------------*/,{
+ /*
+ ** DSA contains the address of a scheduled
+ ** data structure.
+ **
+ ** SCRATCHA contains the address of the script,
+ ** which starts the next entry.
+ **
+ ** Set Initiator mode.
+ **
+ ** (Target mode is left as an exercise for the reader)
+ */
+
+ SCR_CLR (SCR_TRG),
+ 0,
+ SCR_LOAD_REG (HS_REG, 0xff),
+ 0,
+
+ /*
+ ** And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+ PADDR (reselect),
+
+ /*
+ ** Now there are 4 possibilities:
+ **
+ ** (1) The ncr looses arbitration.
+ ** This is ok, because it will try again,
+ ** when the bus becomes idle.
+ ** (But beware of the timeout function!)
+ **
+ ** (2) The ncr is reselected.
+ ** Then the script processor takes the jump
+ ** to the RESELECT label.
+ **
+ ** (3) The ncr completes the selection.
+ ** Then it will execute the next statement.
+ **
+ ** (4) There is a selection timeout.
+ ** Then the ncr should interrupt the host and stop.
+ ** Unfortunately, it seems to continue execution
+ ** of the script. But it will fail with an
+ ** IID-interrupt on the next WHEN.
+ */
+
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ 0,
+
+ /*
+ ** Send the IDENTIFY and SIMPLE_TAG messages
+ ** (and the MSG_EXT_SDTR message)
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct dsb, smsg),
+#ifdef undef /* XXX better fail than try to deal with this ... */
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ -16,
+#endif
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ /*
+ ** Selection complete.
+ ** Next time use the next slot.
+ */
+ SCR_COPY (4),
+ RADDR (scratcha),
+ PADDR (startpos),
+}/*-------------------------< PREPARE >----------------------*/,{
+ /*
+ ** The ncr doesn't have an indirect load
+ ** or store command. So we have to
+ ** copy part of the control block to a
+ ** fixed place, where we can access it.
+ **
+ ** We patch the address part of a
+ ** COPY command with the DSA-register.
+ */
+ SCR_COPY_F (4),
+ RADDR (dsa),
+ PADDR (loadpos),
+ /*
+ ** then we do the actual copy.
+ */
+ SCR_COPY (sizeof (struct head)),
+ /*
+ ** continued after the next label ...
+ */
+
+}/*-------------------------< LOADPOS >---------------------*/,{
+ 0,
+ NADDR (header),
+ /*
+ ** Mark this nccb as not scheduled.
+ */
+ SCR_COPY (8),
+ PADDR (idle),
+ NADDR (header.launch),
+ /*
+ ** Set a time stamp for this selection
+ */
+ SCR_COPY (sizeof (ticks)),
+ KVAR (KVAR_TICKS),
+ NADDR (header.stamp.select),
+ /*
+ ** load the savep (saved pointer) into
+ ** the TEMP register (actual pointer)
+ */
+ SCR_COPY (4),
+ NADDR (header.savep),
+ RADDR (temp),
+ /*
+ ** Initialize the status registers
+ */
+ SCR_COPY (4),
+ NADDR (header.status),
+ RADDR (scr0),
+
+}/*-------------------------< PREPARE2 >---------------------*/,{
+ /*
+ ** Load the synchronous mode register
+ */
+ SCR_COPY (1),
+ NADDR (sync_st),
+ RADDR (sxfer),
+ /*
+ ** Load the wide mode and timing register
+ */
+ SCR_COPY (1),
+ NADDR (wide_st),
+ RADDR (scntl3),
+ /*
+ ** Initialize the msgout buffer with a NOOP message.
+ */
+ SCR_LOAD_REG (scratcha, MSG_NOOP),
+ 0,
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (msgout),
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (msgin),
+ /*
+ ** Message in phase ?
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** Extended or reject message ?
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (MSG_EXTENDED)),
+ PADDR (msg_in),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_MESSAGE_REJECT)),
+ PADDRH (msg_reject),
+ /*
+ ** normal processing
+ */
+ SCR_JUMP,
+ PADDR (dispatch),
+}/*-------------------------< SETMSG >----------------------*/,{
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (msgout),
+ SCR_SET (SCR_ATN),
+ 0,
+}/*-------------------------< CLRACK >----------------------*/,{
+ /*
+ ** Terminate possible pending message phase.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+
+}/*-----------------------< DISPATCH >----------------------*/,{
+ SCR_FROM_REG (HS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+ SIR_NEGO_FAILED,
+ /*
+ ** remove bogus output signals
+ */
+ SCR_REG_REG (socl, SCR_AND, CACK|CATN),
+ 0,
+ SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ 0,
+ SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)),
+ 0,
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+ PADDR (msg_out),
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
+ PADDR (msg_in),
+ SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+ PADDR (command),
+ SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+ PADDR (status),
+ /*
+ ** Discard one illegal phase byte, if required.
+ */
+ SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+ 0,
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (xerr_st),
+ SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+ NADDR (scratch),
+ SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+ NADDR (scratch),
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< NO_DATA >--------------------*/,{
+ /*
+ ** The target wants to tranfer too much data
+ ** or in the wrong direction.
+ ** Remember that in extended error.
+ */
+ SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+ 0,
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (xerr_st),
+ /*
+ ** Discard one data byte, if required.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
+ NADDR (scratch),
+ SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+ 8,
+ SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+ NADDR (scratch),
+ /*
+ ** .. and repeat as required.
+ */
+ SCR_CALL,
+ PADDR (dispatch),
+ SCR_JUMP,
+ PADDR (no_data),
+}/*-------------------------< CHECKATN >--------------------*/,{
+ /*
+ ** If AAP (bit 1 of scntl0 register) is set
+ ** and a parity error is detected,
+ ** the script processor asserts ATN.
+ **
+ ** The target should switch to a MSG_OUT phase
+ ** to get the message.
+ */
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)),
+ PADDR (dispatch),
+ /*
+ ** count it
+ */
+ SCR_REG_REG (PS_REG, SCR_ADD, 1),
+ 0,
+ /*
+ ** Prepare a MSG_INITIATOR_DET_ERR message
+ ** (initiator detected error).
+ ** The target should retry the transfer.
+ */
+ SCR_LOAD_REG (scratcha, MSG_INITIATOR_DET_ERR),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+
+}/*-------------------------< COMMAND >--------------------*/,{
+ /*
+ ** If this is not a GETCC transfer ...
+ */
+ SCR_FROM_REG (SS_REG),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (SCSI_STATUS_CHECK_COND)),
+ 28,
+ /*
+ ** ... set a timestamp ...
+ */
+ SCR_COPY (sizeof (ticks)),
+ KVAR (KVAR_TICKS),
+ NADDR (header.stamp.command),
+ /*
+ ** ... and send the command
+ */
+ SCR_MOVE_TBL ^ SCR_COMMAND,
+ offsetof (struct dsb, cmd),
+ SCR_JUMP,
+ PADDR (dispatch),
+ /*
+ ** Send the GETCC command
+ */
+/*>>>*/ SCR_MOVE_TBL ^ SCR_COMMAND,
+ offsetof (struct dsb, scmd),
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< STATUS >--------------------*/,{
+ /*
+ ** set the timestamp.
+ */
+ SCR_COPY (sizeof (ticks)),
+ KVAR (KVAR_TICKS),
+ NADDR (header.stamp.status),
+ /*
+ ** If this is a GETCC transfer,
+ */
+ SCR_FROM_REG (SS_REG),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (SCSI_STATUS_CHECK_COND)),
+ 40,
+ /*
+ ** get the status
+ */
+ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ NADDR (scratch),
+ /*
+ ** Save status to scsi_status.
+ ** Mark as complete.
+ ** And wait for disconnect.
+ */
+ SCR_TO_REG (SS_REG),
+ 0,
+ SCR_REG_REG (SS_REG, SCR_OR, SCSI_STATUS_SENSE),
+ 0,
+ SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ 0,
+ SCR_JUMP,
+ PADDR (checkatn),
+ /*
+ ** If it was no GETCC transfer,
+ ** save the status to scsi_status.
+ */
+/*>>>*/ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ NADDR (scratch),
+ SCR_TO_REG (SS_REG),
+ 0,
+ /*
+ ** if it was no check condition ...
+ */
+ SCR_JUMP ^ IFTRUE (DATA (SCSI_STATUS_CHECK_COND)),
+ PADDR (checkatn),
+ /*
+ ** ... mark as complete.
+ */
+ SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ 0,
+ SCR_JUMP,
+ PADDR (checkatn),
+
+}/*-------------------------< MSG_IN >--------------------*/,{
+ /*
+ ** Get the first byte of the message
+ ** and save it to SCRATCHA.
+ **
+ ** The script processor doesn't negate the
+ ** ACK signal after this transfer.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[0]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ ** Parity was ok, handle this message.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (MSG_CMDCOMPLETE)),
+ PADDR (complete),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_SAVEDATAPOINTER)),
+ PADDR (save_dp),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_RESTOREPOINTERS)),
+ PADDR (restore_dp),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_DISCONNECT)),
+ PADDR (disconnect),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_EXTENDED)),
+ PADDRH (msg_extended),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_NOOP)),
+ PADDR (clrack),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_MESSAGE_REJECT)),
+ PADDRH (msg_reject),
+ SCR_JUMP ^ IFTRUE (DATA (MSG_IGN_WIDE_RESIDUE)),
+ PADDRH (msg_ign_residue),
+ /*
+ ** Rest of the messages left as
+ ** an exercise ...
+ **
+ ** Unimplemented messages:
+ ** fall through to MSG_BAD.
+ */
+}/*-------------------------< MSG_BAD >------------------*/,{
+ /*
+ ** unimplemented message - reject it.
+ */
+ SCR_INT,
+ SIR_REJECT_SENT,
+ SCR_LOAD_REG (scratcha, MSG_MESSAGE_REJECT),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+
+}/*-------------------------< COMPLETE >-----------------*/,{
+ /*
+ ** Complete message.
+ **
+ ** If it's not the get condition code,
+ ** copy TEMP register to LASTP in header.
+ */
+ SCR_FROM_REG (SS_REG),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (SCSI_STATUS_SENSE, SCSI_STATUS_SENSE)),
+ 12,
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.lastp),
+/*>>>*/ /*
+ ** When we terminate the cycle by clearing ACK,
+ ** the target may disconnect immediately.
+ **
+ ** We don't want to be told of an
+ ** "unexpected disconnect",
+ ** so we disable this feature.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ /*
+ ** Terminate cycle ...
+ */
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ ** ... and wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+}/*-------------------------< CLEANUP >-------------------*/,{
+ /*
+ ** dsa: Pointer to nccb
+ ** or xxxxxxFF (no nccb)
+ **
+ ** HS_REG: Host-Status (<>0!)
+ */
+ SCR_FROM_REG (dsa),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (0xff)),
+ PADDR (signal),
+ /*
+ ** dsa is valid.
+ ** save the status registers
+ */
+ SCR_COPY (4),
+ RADDR (scr0),
+ NADDR (header.status),
+ /*
+ ** and copy back the header to the nccb.
+ */
+ SCR_COPY_F (4),
+ RADDR (dsa),
+ PADDR (cleanup0),
+ SCR_COPY (sizeof (struct head)),
+ NADDR (header),
+}/*-------------------------< CLEANUP0 >--------------------*/,{
+ 0,
+
+ /*
+ ** If command resulted in "check condition"
+ ** status and is not yet completed,
+ ** try to get the condition code.
+ */
+ SCR_FROM_REG (HS_REG),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
+ 16,
+ SCR_FROM_REG (SS_REG),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (SCSI_STATUS_CHECK_COND)),
+ PADDRH(getcc2),
+}/*-------------------------< SIGNAL >----------------------*/,{
+ /*
+ ** if status = queue full,
+ ** reinsert in startqueue and stall queue.
+ */
+/*>>>*/ SCR_FROM_REG (SS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (SCSI_STATUS_QUEUE_FULL)),
+ SIR_STALL_QUEUE,
+ /*
+ ** And make the DSA register invalid.
+ */
+ SCR_LOAD_REG (dsa, 0xff), /* invalid */
+ 0,
+ /*
+ ** if job completed ...
+ */
+ SCR_FROM_REG (HS_REG),
+ 0,
+ /*
+ ** ... signal completion to the host
+ */
+ SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)),
+ 0,
+ /*
+ ** Auf zu neuen Schandtaten!
+ */
+ SCR_JUMP,
+ PADDR(start),
+
+}/*-------------------------< SAVE_DP >------------------*/,{
+ /*
+ ** SAVE_DP message:
+ ** Copy TEMP register to SAVEP in header.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.savep),
+ SCR_JUMP,
+ PADDR (clrack),
+}/*-------------------------< RESTORE_DP >---------------*/,{
+ /*
+ ** RESTORE_DP message:
+ ** Copy SAVEP in header to TEMP register.
+ */
+ SCR_COPY (4),
+ NADDR (header.savep),
+ RADDR (temp),
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< DISCONNECT >---------------*/,{
+ /*
+ ** If QUIRK_AUTOSAVE is set,
+ ** do an "save pointer" operation.
+ */
+ SCR_FROM_REG (QU_REG),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
+ 12,
+ /*
+ ** like SAVE_DP message:
+ ** Copy TEMP register to SAVEP in header.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.savep),
+/*>>>*/ /*
+ ** Check if temp==savep or temp==goalp:
+ ** if not, log a missing save pointer message.
+ ** In fact, it's a comparison mod 256.
+ **
+ ** Hmmm, I hadn't thought that I would be urged to
+ ** write this kind of ugly self modifying code.
+ **
+ ** It's unbelievable, but the ncr53c8xx isn't able
+ ** to subtract one register from another.
+ */
+ SCR_FROM_REG (temp),
+ 0,
+ /*
+ ** You are not expected to understand this ..
+ **
+ ** CAUTION: only little endian architectures supported! XXX
+ */
+ SCR_COPY_F (1),
+ NADDR (header.savep),
+ PADDR (disconnect0),
+}/*-------------------------< DISCONNECT0 >--------------*/,{
+/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)),
+ 20,
+ /*
+ ** neither this
+ */
+ SCR_COPY_F (1),
+ NADDR (header.goalp),
+ PADDR (disconnect1),
+}/*-------------------------< DISCONNECT1 >--------------*/,{
+ SCR_INT ^ IFFALSE (DATA (1)),
+ SIR_MISSING_SAVE,
+/*>>>*/
+
+ /*
+ ** DISCONNECTing ...
+ **
+ ** disable the "unexpected disconnect" feature,
+ ** and remove the ACK signal.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ ** Wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** Profiling:
+ ** Set a time stamp,
+ ** and count the disconnects.
+ */
+ SCR_COPY (sizeof (ticks)),
+ KVAR (KVAR_TICKS),
+ NADDR (header.stamp.disconnect),
+ SCR_COPY (4),
+ NADDR (disc_phys),
+ RADDR (temp),
+ SCR_REG_REG (temp, SCR_ADD, 0x01),
+ 0,
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (disc_phys),
+ /*
+ ** Status is: DISCONNECTED.
+ */
+ SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+ 0,
+ SCR_JUMP,
+ PADDR (cleanup),
+
+}/*-------------------------< MSG_OUT >-------------------*/,{
+ /*
+ ** The target requests a message.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ /*
+ ** If it was no ABORT message ...
+ */
+ SCR_JUMP ^ IFTRUE (DATA (MSG_ABORT)),
+ PADDRH (msg_out_abort),
+ /*
+ ** ... wait for the next phase
+ ** if it's a message out, send it again, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR (msg_out),
+}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+ /*
+ ** ... else clear the message ...
+ */
+ SCR_LOAD_REG (scratcha, MSG_NOOP),
+ 0,
+ SCR_COPY (4),
+ RADDR (scratcha),
+ NADDR (msgout),
+ /*
+ ** ... and process the next phase
+ */
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*------------------------< BADGETCC >---------------------*/,{
+ /*
+ ** If SIGP was set, clear it and try again.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+ PADDRH (getcc2),
+ SCR_INT,
+ SIR_SENSE_FAILED,
+}/*-------------------------< RESELECT >--------------------*/,{
+ /*
+ ** This NOP will be patched with LED OFF
+ ** SCR_REG_REG (gpreg, SCR_OR, 0x01)
+ */
+ SCR_NO_OP,
+ 0,
+
+ /*
+ ** make the DSA invalid.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ ** Sleep waiting for a reselection.
+ ** If SIGP is set, special treatment.
+ **
+ ** Zu allem bereit ..
+ */
+ SCR_WAIT_RESEL,
+ PADDR(reselect2),
+}/*-------------------------< RESELECT1 >--------------------*/,{
+ /*
+ ** This NOP will be patched with LED ON
+ ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+ */
+ SCR_NO_OP,
+ 0,
+ /*
+ ** ... zu nichts zu gebrauchen ?
+ **
+ ** load the target id into the SFBR
+ ** and jump to the control block.
+ **
+ ** Look at the declarations of
+ ** - struct ncb
+ ** - struct tcb
+ ** - struct lcb
+ ** - struct nccb
+ ** to understand what's going on.
+ */
+ SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+ 0,
+ SCR_TO_REG (sdid),
+ 0,
+ SCR_JUMP,
+ NADDR (jump_tcb),
+}/*-------------------------< RESELECT2 >-------------------*/,{
+ /*
+ ** This NOP will be patched with LED ON
+ ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+ */
+ SCR_NO_OP,
+ 0,
+ /*
+ ** If it's not connected :(
+ ** -> interrupted by SIGP bit.
+ ** Jump to start.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+ PADDR (start),
+ SCR_JUMP,
+ PADDR (reselect),
+
+}/*-------------------------< RESEL_TMP >-------------------*/,{
+ /*
+ ** The return address in TEMP
+ ** is in fact the data structure address,
+ ** so copy it to the DSA register.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ RADDR (dsa),
+ SCR_JUMP,
+ PADDR (prepare),
+
+}/*-------------------------< RESEL_LUN >-------------------*/,{
+ /*
+ ** come back to this point
+ ** to get an IDENTIFY message
+ ** Wait for a msg_in phase.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 48,
+ /*
+ ** message phase
+ ** It's not a sony, it's a trick:
+ ** read the data without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (MSG_IDENTIFYFLAG, 0x98)),
+ 32,
+ /*
+ ** It WAS an Identify message.
+ ** get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin),
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Mask out the lun.
+ */
+ SCR_REG_REG (sfbr, SCR_AND, 0x07),
+ 0,
+ SCR_RETURN,
+ 0,
+ /*
+ ** No message phase or no IDENTIFY message:
+ ** return 0.
+ */
+/*>>>*/ SCR_LOAD_SFBR (0),
+ 0,
+ SCR_RETURN,
+ 0,
+
+}/*-------------------------< RESEL_TAG >-------------------*/,{
+ /*
+ ** come back to this point
+ ** to get a SIMPLE_TAG message
+ ** Wait for a MSG_IN phase.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 64,
+ /*
+ ** message phase
+ ** It's a trick - read the data
+ ** without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (MSG_SIMPLE_Q_TAG)),
+ 48,
+ /*
+ ** It WAS a SIMPLE_TAG message.
+ ** get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin),
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Wait for the second byte (the tag)
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 24,
+ /*
+ ** Get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin),
+ SCR_CLR (SCR_ACK|SCR_CARRY),
+ 0,
+ SCR_RETURN,
+ 0,
+ /*
+ ** No message phase or no SIMPLE_TAG message
+ ** or no second byte: return 0.
+ */
+/*>>>*/ SCR_LOAD_SFBR (0),
+ 0,
+ SCR_SET (SCR_CARRY),
+ 0,
+ SCR_RETURN,
+ 0,
+
+}/*-------------------------< DATA_IN >--------------------*/,{
+/*
+** Because the size depends on the
+** #define MAX_SCATTER parameter,
+** it is filled in at runtime.
+**
+** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** PADDR (no_data),
+** SCR_COPY (sizeof (ticks)),
+** KVAR (KVAR_TICKS),
+** NADDR (header.stamp.data),
+** SCR_MOVE_TBL ^ SCR_DATA_IN,
+** offsetof (struct dsb, data[ 0]),
+**
+** ##===========< i=1; i<MAX_SCATTER >=========
+** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** || PADDR (checkatn),
+** || SCR_MOVE_TBL ^ SCR_DATA_IN,
+** || offsetof (struct dsb, data[ i]),
+** ##==========================================
+**
+** SCR_CALL,
+** PADDR (checkatn),
+** SCR_JUMP,
+** PADDR (no_data),
+*/
+0
+}/*-------------------------< DATA_OUT >-------------------*/,{
+/*
+** Because the size depends on the
+** #define MAX_SCATTER parameter,
+** it is filled in at runtime.
+**
+** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+** PADDR (no_data),
+** SCR_COPY (sizeof (ticks)),
+** KVAR (KVAR_TICKS),
+** NADDR (header.stamp.data),
+** SCR_MOVE_TBL ^ SCR_DATA_OUT,
+** offsetof (struct dsb, data[ 0]),
+**
+** ##===========< i=1; i<MAX_SCATTER >=========
+** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+** || PADDR (dispatch),
+** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
+** || offsetof (struct dsb, data[ i]),
+** ##==========================================
+**
+** SCR_CALL,
+** PADDR (dispatch),
+** SCR_JUMP,
+** PADDR (no_data),
+**
+**---------------------------------------------------------
+*/
+(u_long)0
+
+}/*--------------------------------------------------------*/
+};
+
+
+static struct scripth scripth0 = {
+/*-------------------------< TRYLOOP >---------------------*/{
+/*
+** Load an entry of the start queue into dsa
+** and try to start it by jumping to TRYSEL.
+**
+** Because the size depends on the
+** #define MAX_START parameter, it is filled
+** in at runtime.
+**
+**-----------------------------------------------------------
+**
+** ##===========< I=0; i<MAX_START >===========
+** || SCR_COPY (4),
+** || NADDR (squeue[i]),
+** || RADDR (dsa),
+** || SCR_CALL,
+** || PADDR (trysel),
+** ##==========================================
+**
+** SCR_JUMP,
+** PADDRH(tryloop),
+**
+**-----------------------------------------------------------
+*/
+0
+}/*-------------------------< MSG_PARITY >---------------*/,{
+ /*
+ ** count it
+ */
+ SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+ 0,
+ /*
+ ** send a "message parity error" message.
+ */
+ SCR_LOAD_REG (scratcha, MSG_PARITY_ERROR),
+ 0,
+ SCR_JUMP,
+ PADDR (setmsg),
+}/*-------------------------< MSG_MESSAGE_REJECT >---------------*/,{
+ /*
+ ** If a negotiation was in progress,
+ ** negotiation failed.
+ */
+ SCR_FROM_REG (HS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+ SIR_NEGO_FAILED,
+ /*
+ ** else make host log this message
+ */
+ SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
+ SIR_REJECT_RECEIVED,
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+ /*
+ ** Terminate cycle
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get residue size.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[1]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ ** Size is 0 .. ignore message.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (0)),
+ PADDR (clrack),
+ /*
+ ** Size is not 1 .. have to interrupt.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)),
+ 40,
+ /*
+ ** Check for residue byte in swide register
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+ 16,
+ /*
+ ** There IS data in the swide register.
+ ** Discard it.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ SCR_JUMP,
+ PADDR (clrack),
+ /*
+ ** Load again the size to the sfbr register.
+ */
+/*>>>*/ SCR_FROM_REG (scratcha),
+ 0,
+/*>>>*/ SCR_INT,
+ SIR_IGN_RESIDUE,
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< MSG_EXTENDED >-------------*/,{
+ /*
+ ** Terminate cycle
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get length.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[1]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ */
+ SCR_JUMP ^ IFTRUE (DATA (3)),
+ PADDRH (msg_ext_3),
+ SCR_JUMP ^ IFFALSE (DATA (2)),
+ PADDR (msg_bad),
+}/*-------------------------< MSG_EXT_2 >----------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get extended message code.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[2]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (MSG_EXT_WDTR)),
+ PADDRH (msg_wdtr),
+ /*
+ ** unknown extended message
+ */
+ SCR_JUMP,
+ PADDR (msg_bad)
+}/*-------------------------< MSG_WDTR >-----------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get data bus width
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[3]),
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ /*
+ ** let the host do the real work.
+ */
+ SCR_INT,
+ SIR_NEGO_WIDE,
+ /*
+ ** let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ SIR_NEGO_PROTO,
+ /*
+ ** Send the MSG_EXT_WDTR
+ */
+ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ SCR_JUMP,
+ PADDR (msg_out_done),
+
+}/*-------------------------< MSG_EXT_3 >----------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get extended message code.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[2]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ SCR_JUMP ^ IFTRUE (DATA (MSG_EXT_SDTR)),
+ PADDRH (msg_sdtr),
+ /*
+ ** unknown extended message
+ */
+ SCR_JUMP,
+ PADDR (msg_bad)
+
+}/*-------------------------< MSG_SDTR >-----------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get period and offset
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ NADDR (msgin[3]),
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ /*
+ ** let the host do the real work.
+ */
+ SCR_INT,
+ SIR_NEGO_SYNC,
+ /*
+ ** let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ SIR_NEGO_PROTO,
+ /*
+ ** Send the MSG_EXT_SDTR
+ */
+ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ SCR_JUMP,
+ PADDR (msg_out_done),
+
+}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
+ /*
+ ** After ABORT message,
+ **
+ ** expect an immediate disconnect, ...
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** ... and set the status to "ABORTED"
+ */
+ SCR_LOAD_REG (HS_REG, HS_ABORTED),
+ 0,
+ SCR_JUMP,
+ PADDR (cleanup),
+
+}/*-------------------------< GETCC >-----------------------*/,{
+ /*
+ ** The ncr doesn't have an indirect load
+ ** or store command. So we have to
+ ** copy part of the control block to a
+ ** fixed place, where we can modify it.
+ **
+ ** We patch the address part of a COPY command
+ ** with the address of the dsa register ...
+ */
+ SCR_COPY_F (4),
+ RADDR (dsa),
+ PADDRH (getcc1),
+ /*
+ ** ... then we do the actual copy.
+ */
+ SCR_COPY (sizeof (struct head)),
+}/*-------------------------< GETCC1 >----------------------*/,{
+ 0,
+ NADDR (header),
+ /*
+ ** Initialize the status registers
+ */
+ SCR_COPY (4),
+ NADDR (header.status),
+ RADDR (scr0),
+}/*-------------------------< GETCC2 >----------------------*/,{
+ /*
+ ** Get the condition code from a target.
+ **
+ ** DSA points to a data structure.
+ ** Set TEMP to the script location
+ ** that receives the condition code.
+ **
+ ** Because there is no script command
+ ** to load a longword into a register,
+ ** we use a CALL command.
+ */
+/*<<<*/ SCR_CALLR,
+ 24,
+ /*
+ ** Get the condition code.
+ */
+ SCR_MOVE_TBL ^ SCR_DATA_IN,
+ offsetof (struct dsb, sense),
+ /*
+ ** No data phase may follow!
+ */
+ SCR_CALL,
+ PADDR (checkatn),
+ SCR_JUMP,
+ PADDR (no_data),
+/*>>>*/
+
+ /*
+ ** The CALL jumps to this point.
+ ** Prepare for a RESTORE_POINTER message.
+ ** Save the TEMP register into the saved pointer.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.savep),
+ /*
+ ** Load scratcha, because in case of a selection timeout,
+ ** the host will expect a new value for startpos in
+ ** the scratcha register.
+ */
+ SCR_COPY (4),
+ PADDR (startpos),
+ RADDR (scratcha),
+#ifdef NCR_GETCC_WITHMSG
+ /*
+ ** If QUIRK_NOMSG is set, select without ATN.
+ ** and don't send a message.
+ */
+ SCR_FROM_REG (QU_REG),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)),
+ PADDRH(getcc3),
+ /*
+ ** Then try to connect to the target.
+ ** If we are reselected, special treatment
+ ** of the current job is required before
+ ** accepting the reselection.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+ PADDR(badgetcc),
+ /*
+ ** Send the IDENTIFY message.
+ ** In case of short transfer, remove ATN.
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct dsb, smsg2),
+ SCR_CLR (SCR_ATN),
+ 0,
+ /*
+ ** save the first byte of the message.
+ */
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ SCR_JUMP,
+ PADDR (prepare2),
+
+#endif
+}/*-------------------------< GETCC3 >----------------------*/,{
+ /*
+ ** Try to connect to the target.
+ ** If we are reselected, special treatment
+ ** of the current job is required before
+ ** accepting the reselection.
+ **
+ ** Silly target won't accept a message.
+ ** Select without ATN.
+ */
+ SCR_SEL_TBL ^ offsetof (struct dsb, select),
+ PADDR(badgetcc),
+ /*
+ ** Force error if selection timeout
+ */
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ 0,
+ /*
+ ** don't negotiate.
+ */
+ SCR_JUMP,
+ PADDR (prepare2),
+}/*-------------------------< ABORTTAG >-------------------*/,{
+ /*
+ ** Abort a bad reselection.
+ ** Set the message to ABORT vs. ABORT_TAG
+ */
+ SCR_LOAD_REG (scratcha, MSG_ABORT_TAG),
+ 0,
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+}/*-------------------------< ABORT >----------------------*/,{
+ SCR_LOAD_REG (scratcha, MSG_ABORT),
+ 0,
+ SCR_COPY (1),
+ RADDR (scratcha),
+ NADDR (msgout),
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** and send it.
+ ** we expect an immediate disconnect
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ SCR_JUMP,
+ PADDR (start),
+}/*-------------------------< SNOOPTEST >-------------------*/,{
+ /*
+ ** Read the variable.
+ */
+ SCR_COPY (4),
+ KVAR (KVAR_NCR_CACHE),
+ RADDR (scratcha),
+ /*
+ ** Write the variable.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ KVAR (KVAR_NCR_CACHE),
+ /*
+ ** Read back the variable.
+ */
+ SCR_COPY (4),
+ KVAR (KVAR_NCR_CACHE),
+ RADDR (temp),
+}/*-------------------------< SNOOPEND >-------------------*/,{
+ /*
+ ** And stop.
+ */
+ SCR_INT,
+ 99,
+}/*--------------------------------------------------------*/
+};
+
+
+/*==========================================================
+**
+**
+** Fill in #define dependent parts of the script
+**
+**
+**==========================================================
+*/
+
+void ncr_script_fill (struct script * scr, struct scripth * scrh)
+{
+ int i;
+ ncrcmd *p;
+
+ p = scrh->tryloop;
+ for (i=0; i<MAX_START; i++) {
+ *p++ =SCR_COPY (4);
+ *p++ =NADDR (squeue[i]);
+ *p++ =RADDR (dsa);
+ *p++ =SCR_CALL;
+ *p++ =PADDR (trysel);
+ };
+ *p++ =SCR_JUMP;
+ *p++ =PADDRH(tryloop);
+
+ assert ((char *)p == (char *)&scrh->tryloop + sizeof (scrh->tryloop));
+
+ p = scr->data_in;
+
+ *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
+ *p++ =PADDR (no_data);
+ *p++ =SCR_COPY (sizeof (ticks));
+ *p++ =(ncrcmd) KVAR (KVAR_TICKS);
+ *p++ =NADDR (header.stamp.data);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+ *p++ =offsetof (struct dsb, data[ 0]);
+
+ for (i=1; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+ *p++ =PADDR (checkatn);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+ *p++ =offsetof (struct dsb, data[i]);
+ };
+
+ *p++ =SCR_CALL;
+ *p++ =PADDR (checkatn);
+ *p++ =SCR_JUMP;
+ *p++ =PADDR (no_data);
+
+ assert ((char *)p == (char *)&scr->data_in + sizeof (scr->data_in));
+
+ p = scr->data_out;
+
+ *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
+ *p++ =PADDR (no_data);
+ *p++ =SCR_COPY (sizeof (ticks));
+ *p++ =(ncrcmd) KVAR (KVAR_TICKS);
+ *p++ =NADDR (header.stamp.data);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+ *p++ =offsetof (struct dsb, data[ 0]);
+
+ for (i=1; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+ *p++ =PADDR (dispatch);
+ *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+ *p++ =offsetof (struct dsb, data[i]);
+ };
+
+ *p++ =SCR_CALL;
+ *p++ =PADDR (dispatch);
+ *p++ =SCR_JUMP;
+ *p++ =PADDR (no_data);
+
+ assert ((char *)p == (char *)&scr->data_out + sizeof (scr->data_out));
+}
+
+/*==========================================================
+**
+**
+** Copy and rebind a script.
+**
+**
+**==========================================================
+*/
+
+static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+{
+ ncrcmd opcode, new, old, tmp1, tmp2;
+ ncrcmd *start, *end;
+ int relocs, offset;
+
+ start = src;
+ end = src + len/4;
+ offset = 0;
+
+ while (src < end) {
+
+ opcode = *src++;
+ WRITESCRIPT_OFF(dst, offset, opcode);
+ offset += 4;
+
+ /*
+ ** If we forget to change the length
+ ** in struct script, a field will be
+ ** padded with 0. This is an illegal
+ ** command.
+ */
+
+ if (opcode == 0) {
+ printf ("%s: ERROR0 IN SCRIPT at %d.\n",
+ ncr_name(np), (int) (src-start-1));
+ DELAY (1000000);
+ };
+
+ if (DEBUG_FLAGS & DEBUG_SCRIPT)
+ printf ("%p: <%x>\n",
+ (src-1), (unsigned)opcode);
+
+ /*
+ ** We don't have to decode ALL commands
+ */
+ switch (opcode >> 28) {
+
+ case 0xc:
+ /*
+ ** COPY has TWO arguments.
+ */
+ relocs = 2;
+ tmp1 = src[0];
+ if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
+ tmp1 = 0;
+ tmp2 = src[1];
+ if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
+ tmp2 = 0;
+ if ((tmp1 ^ tmp2) & 3) {
+ printf ("%s: ERROR1 IN SCRIPT at %d.\n",
+ ncr_name(np), (int) (src-start-1));
+ DELAY (1000000);
+ }
+ /*
+ ** If PREFETCH feature not enabled, remove
+ ** the NO FLUSH bit if present.
+ */
+ if ((opcode & SCR_NO_FLUSH) && !(np->features&FE_PFEN))
+ WRITESCRIPT_OFF(dst, offset - 4,
+ (opcode & ~SCR_NO_FLUSH));
+ break;
+
+ case 0x0:
+ /*
+ ** MOVE (absolute address)
+ */
+ relocs = 1;
+ break;
+
+ case 0x8:
+ /*
+ ** JUMP / CALL
+ ** dont't relocate if relative :-)
+ */
+ if (opcode & 0x00800000)
+ relocs = 0;
+ else
+ relocs = 1;
+ break;
+
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ relocs = 1;
+ break;
+
+ default:
+ relocs = 0;
+ break;
+ };
+
+ if (relocs) {
+ while (relocs--) {
+ old = *src++;
+
+ switch (old & RELOC_MASK) {
+ case RELOC_REGISTER:
+ new = (old & ~RELOC_MASK) + rman_get_start(np->reg_res);
+ break;
+ case RELOC_LABEL:
+ new = (old & ~RELOC_MASK) + np->p_script;
+ break;
+ case RELOC_LABELH:
+ new = (old & ~RELOC_MASK) + np->p_scripth;
+ break;
+ case RELOC_SOFTC:
+ new = (old & ~RELOC_MASK) + vtophys(np);
+ break;
+ case RELOC_KVAR:
+ if (((old & ~RELOC_MASK) <
+ SCRIPT_KVAR_FIRST) ||
+ ((old & ~RELOC_MASK) >
+ SCRIPT_KVAR_LAST))
+ panic("ncr KVAR out of range");
+ new = vtophys(script_kvars[old &
+ ~RELOC_MASK]);
+ break;
+ case 0:
+ /* Don't relocate a 0 address. */
+ if (old == 0) {
+ new = old;
+ break;
+ }
+ /* fall through */
+ default:
+ panic("ncr_script_copy_and_bind: weird relocation %x @ %d\n", old, (int)(src - start));
+ break;
+ }
+
+ WRITESCRIPT_OFF(dst, offset, new);
+ offset += 4;
+ }
+ } else {
+ WRITESCRIPT_OFF(dst, offset, *src++);
+ offset += 4;
+ }
+
+ };
+}
+
+/*==========================================================
+**
+**
+** Auto configuration.
+**
+**
+**==========================================================
+*/
+
+#if 0
+/*----------------------------------------------------------
+**
+** Reduce the transfer length to the max value
+** we can transfer safely.
+**
+** Reading a block greater then MAX_SIZE from the
+** raw (character) device exercises a memory leak
+** in the vm subsystem. This is common to ALL devices.
+** We have submitted a description of this bug to
+** <FreeBSD-bugs@freefall.cdrom.com>.
+** It should be fixed in the current release.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_min_phys (struct buf *bp)
+{
+ if ((unsigned long)bp->b_bcount > MAX_SIZE) bp->b_bcount = MAX_SIZE;
+}
+
+#endif
+
+#if 0
+/*----------------------------------------------------------
+**
+** Maximal number of outstanding requests per target.
+**
+**----------------------------------------------------------
+*/
+
+u_int32_t ncr_info (int unit)
+{
+ return (1); /* may be changed later */
+}
+
+#endif
+
+/*----------------------------------------------------------
+**
+** NCR chip devices table and chip look up function.
+** Features bit are defined in ncrreg.h. Is it the
+** right place?
+**
+**----------------------------------------------------------
+*/
+typedef struct {
+ unsigned long device_id;
+ unsigned short minrevid;
+ char *name;
+ unsigned char maxburst;
+ unsigned char maxoffs;
+ unsigned char clock_divn;
+ unsigned int features;
+} ncr_chip;
+
+static ncr_chip ncr_chip_table[] = {
+ {NCR_810_ID, 0x00, "ncr 53c810 fast10 scsi", 4, 8, 4,
+ FE_ERL}
+ ,
+ {NCR_810_ID, 0x10, "ncr 53c810a fast10 scsi", 4, 8, 4,
+ FE_ERL|FE_LDSTR|FE_PFEN|FE_BOF}
+ ,
+ {NCR_815_ID, 0x00, "ncr 53c815 fast10 scsi", 4, 8, 4,
+ FE_ERL|FE_BOF}
+ ,
+ {NCR_820_ID, 0x00, "ncr 53c820 fast10 wide scsi", 4, 8, 4,
+ FE_WIDE|FE_ERL}
+ ,
+ {NCR_825_ID, 0x00, "ncr 53c825 fast10 wide scsi", 4, 8, 4,
+ FE_WIDE|FE_ERL|FE_BOF}
+ ,
+ {NCR_825_ID, 0x10, "ncr 53c825a fast10 wide scsi", 7, 8, 4,
+ FE_WIDE|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_860_ID, 0x00, "ncr 53c860 fast20 scsi", 4, 8, 5,
+ FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_LDSTR|FE_PFEN}
+ ,
+ {NCR_875_ID, 0x00, "ncr 53c875 fast20 wide scsi", 7, 16, 5,
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_875_ID, 0x02, "ncr 53c875 fast20 wide scsi", 7, 16, 5,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_875_ID2, 0x00, "ncr 53c875j fast20 wide scsi", 7, 16, 5,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_885_ID, 0x00, "ncr 53c885 fast20 wide scsi", 7, 16, 5,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_895_ID, 0x00, "ncr 53c895 fast40 wide scsi", 7, 31, 7,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_896_ID, 0x00, "ncr 53c896 fast40 wide scsi", 7, 31, 7,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_895A_ID, 0x00, "ncr 53c895a fast40 wide scsi", 7, 31, 7,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+ ,
+ {NCR_1510D_ID, 0x00, "ncr 53c1510d fast40 wide scsi", 7, 31, 7,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}
+};
+
+static int ncr_chip_lookup(u_long device_id, u_char revision_id)
+{
+ int i, found;
+
+ found = -1;
+ for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+ if (device_id == ncr_chip_table[i].device_id &&
+ ncr_chip_table[i].minrevid <= revision_id) {
+ if (found < 0 ||
+ ncr_chip_table[found].minrevid
+ < ncr_chip_table[i].minrevid) {
+ found = i;
+ }
+ }
+ }
+ return found;
+}
+
+/*----------------------------------------------------------
+**
+** Probe the hostadapter.
+**
+**----------------------------------------------------------
+*/
+
+
+
+static int ncr_probe (device_t dev)
+{
+ int i;
+
+ i = ncr_chip_lookup(pci_get_devid(dev), pci_get_revid(dev));
+ if (i >= 0) {
+ device_set_desc(dev, ncr_chip_table[i].name);
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+
+
+/*==========================================================
+**
+** NCR chip clock divisor table.
+** Divisors are multiplied by 10,000,000 in order to make
+** calculations more simple.
+**
+**==========================================================
+*/
+
+#define _5M 5000000
+static u_long div_10M[] =
+ {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
+
+/*===============================================================
+**
+** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
+** transfers. 32,64,128 are only supported by 875 and 895 chips.
+** We use log base 2 (burst length) as internal code, with
+** value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ * Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ * Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+ (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ * Set initial io register bits from burst code.
+ */
+static void
+ncr_init_burst(ncb_p np, u_char bc)
+{
+ np->rv_ctest4 &= ~0x80;
+ np->rv_dmode &= ~(0x3 << 6);
+ np->rv_ctest5 &= ~0x4;
+
+ if (!bc) {
+ np->rv_ctest4 |= 0x80;
+ }
+ else {
+ --bc;
+ np->rv_dmode |= ((bc & 0x3) << 6);
+ np->rv_ctest5 |= (bc & 0x4);
+ }
+}
+
+/*==========================================================
+**
+**
+** Auto configuration: attach and init a host adapter.
+**
+**
+**==========================================================
+*/
+
+
+static int
+ncr_attach (device_t dev)
+{
+ ncb_p np = (struct ncb*) device_get_softc(dev);
+ u_char rev = 0;
+ u_long period;
+ int i, rid;
+ u_int8_t usrsync;
+ u_int8_t usrwide;
+ struct cam_devq *devq;
+
+ /*
+ ** allocate and initialize structures.
+ */
+
+ np->unit = device_get_unit(dev);
+
+ /*
+ ** Try to map the controller chip to
+ ** virtual and physical memory.
+ */
+
+ np->reg_rid = 0x14;
+ np->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &np->reg_rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!np->reg_res) {
+ device_printf(dev, "could not map memory\n");
+ return ENXIO;
+ }
+
+ /*
+ ** Make the controller's registers available.
+ ** Now the INB INW INL OUTB OUTW OUTL macros
+ ** can be used safely.
+ */
+
+ np->bst = rman_get_bustag(np->reg_res);
+ np->bsh = rman_get_bushandle(np->reg_res);
+
+
+#ifdef NCR_IOMAPPED
+ /*
+ ** Try to map the controller chip into iospace.
+ */
+
+ if (!pci_map_port (config_id, 0x10, &np->port))
+ return;
+#endif
+
+
+ /*
+ ** Save some controller register default values
+ */
+
+ np->rv_scntl3 = INB(nc_scntl3) & 0x77;
+ np->rv_dmode = INB(nc_dmode) & 0xce;
+ np->rv_dcntl = INB(nc_dcntl) & 0xa9;
+ np->rv_ctest3 = INB(nc_ctest3) & 0x01;
+ np->rv_ctest4 = INB(nc_ctest4) & 0x88;
+ np->rv_ctest5 = INB(nc_ctest5) & 0x24;
+ np->rv_gpcntl = INB(nc_gpcntl);
+ np->rv_stest2 = INB(nc_stest2) & 0x20;
+
+ if (bootverbose >= 2) {
+ printf ("\tBIOS values: SCNTL3:%02x DMODE:%02x DCNTL:%02x\n",
+ np->rv_scntl3, np->rv_dmode, np->rv_dcntl);
+ printf ("\t CTEST3:%02x CTEST4:%02x CTEST5:%02x\n",
+ np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+ }
+
+ np->rv_dcntl |= NOCOM;
+
+ /*
+ ** Do chip dependent initialization.
+ */
+
+ rev = pci_get_revid(dev);
+
+ /*
+ ** Get chip features from chips table.
+ */
+ i = ncr_chip_lookup(pci_get_devid(dev), rev);
+
+ if (i >= 0) {
+ np->maxburst = ncr_chip_table[i].maxburst;
+ np->maxoffs = ncr_chip_table[i].maxoffs;
+ np->clock_divn = ncr_chip_table[i].clock_divn;
+ np->features = ncr_chip_table[i].features;
+ } else { /* Should'nt happen if probe() is ok */
+ np->maxburst = 4;
+ np->maxoffs = 8;
+ np->clock_divn = 4;
+ np->features = FE_ERL;
+ }
+
+ np->maxwide = np->features & FE_WIDE ? 1 : 0;
+ np->clock_khz = np->features & FE_CLK80 ? 80000 : 40000;
+ if (np->features & FE_QUAD) np->multiplier = 4;
+ else if (np->features & FE_DBLR) np->multiplier = 2;
+ else np->multiplier = 1;
+
+ /*
+ ** Get the frequency of the chip's clock.
+ ** Find the right value for scntl3.
+ */
+ if (np->features & (FE_ULTRA|FE_ULTRA2))
+ ncr_getclock(np, np->multiplier);
+
+#ifdef NCR_TEKRAM_EEPROM
+ if (bootverbose) {
+ printf ("%s: Tekram EEPROM read %s\n",
+ ncr_name(np),
+ read_tekram_eeprom (np, NULL) ?
+ "succeeded" : "failed");
+ }
+#endif /* NCR_TEKRAM_EEPROM */
+
+ /*
+ * If scntl3 != 0, we assume BIOS is present.
+ */
+ if (np->rv_scntl3)
+ np->features |= FE_BIOS;
+
+ /*
+ * Divisor to be used for async (timer pre-scaler).
+ */
+ i = np->clock_divn - 1;
+ while (i >= 0) {
+ --i;
+ if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
+ ++i;
+ break;
+ }
+ }
+ np->rv_scntl3 = i+1;
+
+ /*
+ * Minimum synchronous period factor supported by the chip.
+ * Btw, 'period' is in tenths of nanoseconds.
+ */
+
+ period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
+ if (period <= 250) np->minsync = 10;
+ else if (period <= 303) np->minsync = 11;
+ else if (period <= 500) np->minsync = 12;
+ else np->minsync = (period + 40 - 1) / 40;
+
+ /*
+ * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+ */
+
+ if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2)))
+ np->minsync = 25;
+ else if (np->minsync < 12 && !(np->features & FE_ULTRA2))
+ np->minsync = 12;
+
+ /*
+ * Maximum synchronous period factor supported by the chip.
+ */
+
+ period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
+ np->maxsync = period > 2540 ? 254 : period / 10;
+
+ /*
+ * Now, some features available with Symbios compatible boards.
+ * LED support through GPIO0 and DIFF support.
+ */
+
+#ifdef SCSI_NCR_SYMBIOS_COMPAT
+ if (!(np->rv_gpcntl & 0x01))
+ np->features |= FE_LED0;
+#if 0 /* Not safe enough without NVRAM support or user settable option */
+ if (!(INB(nc_gpreg) & 0x08))
+ np->features |= FE_DIFF;
+#endif
+#endif /* SCSI_NCR_SYMBIOS_COMPAT */
+
+ /*
+ * Prepare initial IO registers settings.
+ * Trust BIOS only if we believe we have one and if we want to.
+ */
+#ifdef SCSI_NCR_TRUST_BIOS
+ if (!(np->features & FE_BIOS)) {
+#else
+ if (1) {
+#endif
+ np->rv_dmode = 0;
+ np->rv_dcntl = NOCOM;
+ np->rv_ctest3 = 0;
+ np->rv_ctest4 = MPEE;
+ np->rv_ctest5 = 0;
+ np->rv_stest2 = 0;
+
+ if (np->features & FE_ERL)
+ np->rv_dmode |= ERL; /* Enable Read Line */
+ if (np->features & FE_BOF)
+ np->rv_dmode |= BOF; /* Burst Opcode Fetch */
+ if (np->features & FE_ERMP)
+ np->rv_dmode |= ERMP; /* Enable Read Multiple */
+ if (np->features & FE_CLSE)
+ np->rv_dcntl |= CLSE; /* Cache Line Size Enable */
+ if (np->features & FE_WRIE)
+ np->rv_ctest3 |= WRIE; /* Write and Invalidate */
+ if (np->features & FE_PFEN)
+ np->rv_dcntl |= PFEN; /* Prefetch Enable */
+ if (np->features & FE_DFS)
+ np->rv_ctest5 |= DFS; /* Dma Fifo Size */
+ if (np->features & FE_DIFF)
+ np->rv_stest2 |= 0x20; /* Differential mode */
+ ncr_init_burst(np, np->maxburst); /* Max dwords burst length */
+ } else {
+ np->maxburst =
+ burst_code(np->rv_dmode, np->rv_ctest4, np->rv_ctest5);
+ }
+
+ /*
+ ** Get on-chip SRAM address, if supported
+ */
+ if ((np->features & FE_RAM) && sizeof(struct script) <= 4096) {
+ np->sram_rid = 0x18;
+ np->sram_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &np->sram_rid,
+ 0, ~0, 1, RF_ACTIVE);
+ }
+
+ /*
+ ** Allocate structure for script relocation.
+ */
+ if (np->sram_res != NULL) {
+ np->script = NULL;
+ np->p_script = rman_get_start(np->sram_res);
+ np->bst2 = rman_get_bustag(np->sram_res);
+ np->bsh2 = rman_get_bushandle(np->sram_res);
+ } else if (sizeof (struct script) > PAGE_SIZE) {
+ np->script = (struct script*) vm_page_alloc_contig
+ (round_page(sizeof (struct script)),
+ 0, 0xffffffff, PAGE_SIZE);
+ } else {
+ np->script = (struct script *)
+ malloc (sizeof (struct script), M_DEVBUF, M_WAITOK);
+ }
+
+ /* XXX JGibbs - Use contigmalloc */
+ if (sizeof (struct scripth) > PAGE_SIZE) {
+ np->scripth = (struct scripth*) vm_page_alloc_contig
+ (round_page(sizeof (struct scripth)),
+ 0, 0xffffffff, PAGE_SIZE);
+ } else
+ {
+ np->scripth = (struct scripth *)
+ malloc (sizeof (struct scripth), M_DEVBUF, M_WAITOK);
+ }
+
+#ifdef SCSI_NCR_PCI_CONFIG_FIXUP
+ /*
+ ** If cache line size is enabled, check PCI config space and
+ ** try to fix it up if necessary.
+ */
+#ifdef PCIR_CACHELNSZ /* To be sure that new PCI stuff is present */
+ {
+ u_char cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ u_short command = pci_read_config(dev, PCIR_COMMAND, 2);
+
+ if (!cachelnsz) {
+ cachelnsz = 8;
+ printf("%s: setting PCI cache line size register to %d.\n",
+ ncr_name(np), (int)cachelnsz);
+ pci_write_config(dev, PCIR_CACHELNSZ, cachelnsz, 1);
+ }
+
+ if (!(command & (1<<4))) {
+ command |= (1<<4);
+ printf("%s: setting PCI command write and invalidate.\n",
+ ncr_name(np));
+ pci_write_config(dev, PCIR_COMMAND, command, 2);
+ }
+ }
+#endif /* PCIR_CACHELNSZ */
+
+#endif /* SCSI_NCR_PCI_CONFIG_FIXUP */
+
+ /* Initialize per-target user settings */
+ usrsync = 0;
+ if (SCSI_NCR_DFLT_SYNC) {
+ usrsync = SCSI_NCR_DFLT_SYNC;
+ if (usrsync > np->maxsync)
+ usrsync = np->maxsync;
+ if (usrsync < np->minsync)
+ usrsync = np->minsync;
+ };
+
+ usrwide = (SCSI_NCR_MAX_WIDE);
+ if (usrwide > np->maxwide) usrwide=np->maxwide;
+
+ for (i=0;i<MAX_TARGET;i++) {
+ tcb_p tp = &np->target[i];
+
+ tp->tinfo.user.period = usrsync;
+ tp->tinfo.user.offset = usrsync != 0 ? np->maxoffs : 0;
+ tp->tinfo.user.width = usrwide;
+ tp->tinfo.disc_tag = NCR_CUR_DISCENB
+ | NCR_CUR_TAGENB
+ | NCR_USR_DISCENB
+ | NCR_USR_TAGENB;
+ }
+
+ /*
+ ** Bells and whistles ;-)
+ */
+ if (bootverbose)
+ printf("%s: minsync=%d, maxsync=%d, maxoffs=%d, %d dwords burst, %s dma fifo\n",
+ ncr_name(np), np->minsync, np->maxsync, np->maxoffs,
+ burst_length(np->maxburst),
+ (np->rv_ctest5 & DFS) ? "large" : "normal");
+
+ /*
+ ** Print some complementary information that can be helpfull.
+ */
+ if (bootverbose)
+ printf("%s: %s, %s IRQ driver%s\n",
+ ncr_name(np),
+ np->rv_stest2 & 0x20 ? "differential" : "single-ended",
+ np->rv_dcntl & IRQM ? "totem pole" : "open drain",
+ np->sram_res ? ", using on-chip SRAM" : "");
+
+ /*
+ ** Patch scripts to physical addresses
+ */
+ ncr_script_fill (&script0, &scripth0);
+
+ if (np->script)
+ np->p_script = vtophys(np->script);
+ np->p_scripth = vtophys(np->scripth);
+
+ ncr_script_copy_and_bind (np, (ncrcmd *) &script0,
+ (ncrcmd *) np->script, sizeof(struct script));
+
+ ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0,
+ (ncrcmd *) np->scripth, sizeof(struct scripth));
+
+ /*
+ ** Patch the script for LED support.
+ */
+
+ if (np->features & FE_LED0) {
+ WRITESCRIPT(reselect[0], SCR_REG_REG(gpreg, SCR_OR, 0x01));
+ WRITESCRIPT(reselect1[0], SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+ WRITESCRIPT(reselect2[0], SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+ }
+
+ /*
+ ** init data structure
+ */
+
+ np->jump_tcb.l_cmd = SCR_JUMP;
+ np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
+
+ /*
+ ** Get SCSI addr of host adapter (set by bios?).
+ */
+
+ np->myaddr = INB(nc_scid) & 0x07;
+ if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
+
+#ifdef NCR_DUMP_REG
+ /*
+ ** Log the initial register contents
+ */
+ {
+ int reg;
+ for (reg=0; reg<256; reg+=4) {
+ if (reg%16==0) printf ("reg[%2x]", reg);
+ printf (" %08x", (int)pci_conf_read (config_id, reg));
+ if (reg%16==12) printf ("\n");
+ }
+ }
+#endif /* NCR_DUMP_REG */
+
+ /*
+ ** Reset chip.
+ */
+
+ OUTB (nc_istat, SRST);
+ DELAY (1000);
+ OUTB (nc_istat, 0 );
+
+
+ /*
+ ** Now check the cache handling of the pci chipset.
+ */
+
+ if (ncr_snooptest (np)) {
+ printf ("CACHE INCORRECTLY CONFIGURED.\n");
+ return EINVAL;
+ };
+
+ /*
+ ** Install the interrupt handler.
+ */
+
+ rid = 0;
+ np->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (np->irq_res == NULL) {
+ device_printf(dev,
+ "interruptless mode: reduced performance.\n");
+ } else {
+ bus_setup_intr(dev, np->irq_res, INTR_TYPE_CAM | INTR_ENTROPY,
+ ncr_intr, np, &np->irq_handle);
+ }
+
+ /*
+ ** Create the device queue. We only allow MAX_START-1 concurrent
+ ** transactions so we can be sure to have one element free in our
+ ** start queue to reset to the idle loop.
+ */
+ devq = cam_simq_alloc(MAX_START - 1);
+ if (devq == NULL)
+ return ENOMEM;
+
+ /*
+ ** Now tell the generic SCSI layer
+ ** about our bus.
+ */
+ np->sim = cam_sim_alloc(ncr_action, ncr_poll, "ncr", np, np->unit,
+ 1, MAX_TAGS, devq);
+ if (np->sim == NULL) {
+ cam_simq_free(devq);
+ return ENOMEM;
+ }
+
+
+ if (xpt_bus_register(np->sim, 0) != CAM_SUCCESS) {
+ cam_sim_free(np->sim, /*free_devq*/ TRUE);
+ return ENOMEM;
+ }
+
+ if (xpt_create_path(&np->path, /*periph*/NULL,
+ cam_sim_path(np->sim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_bus_deregister(cam_sim_path(np->sim));
+ cam_sim_free(np->sim, /*free_devq*/TRUE);
+ return ENOMEM;
+ }
+
+ /*
+ ** start the timeout daemon
+ */
+ ncr_timeout (np);
+ np->lasttime=0;
+
+ return 0;
+}
+
+/*==========================================================
+**
+**
+** Process pending device interrupts.
+**
+**
+**==========================================================
+*/
+
+static void
+ncr_intr(vnp)
+ void *vnp;
+{
+ ncb_p np = vnp;
+ int oldspl = splcam();
+
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+
+ if (INB(nc_istat) & (INTF|SIP|DIP)) {
+ /*
+ ** Repeat until no outstanding ints
+ */
+ do {
+ ncr_exception (np);
+ } while (INB(nc_istat) & (INTF|SIP|DIP));
+
+ np->ticks = 100;
+ };
+
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+
+ splx (oldspl);
+}
+
+/*==========================================================
+**
+**
+** Start execution of a SCSI command.
+** This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+static void
+ncr_action (struct cam_sim *sim, union ccb *ccb)
+{
+ ncb_p np;
+
+ np = (ncb_p) cam_sim_softc(sim);
+
+ switch (ccb->ccb_h.func_code) {
+ /* Common cases first */
+ case XPT_SCSI_IO: /* Execute the requested I/O operation */
+ {
+ nccb_p cp;
+ lcb_p lp;
+ tcb_p tp;
+ int oldspl;
+ struct ccb_scsiio *csio;
+ u_int8_t *msgptr;
+ u_int msglen;
+ u_int msglen2;
+ int segments;
+ u_int8_t nego;
+ u_int8_t idmsg;
+ u_int8_t qidx;
+
+ tp = &np->target[ccb->ccb_h.target_id];
+ csio = &ccb->csio;
+
+ oldspl = splcam();
+
+ /*
+ * Last time we need to check if this CCB needs to
+ * be aborted.
+ */
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
+ xpt_done(ccb);
+ splx(oldspl);
+ return;
+ }
+ ccb->ccb_h.status |= CAM_SIM_QUEUED;
+
+ /*---------------------------------------------------
+ **
+ ** Assign an nccb / bind ccb
+ **
+ **----------------------------------------------------
+ */
+ cp = ncr_get_nccb (np, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun);
+ if (cp == NULL) {
+ /* XXX JGibbs - Freeze SIMQ */
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+ };
+
+ cp->ccb = ccb;
+
+ /*---------------------------------------------------
+ **
+ ** timestamp
+ **
+ **----------------------------------------------------
+ */
+ /*
+ ** XXX JGibbs - Isn't this expensive
+ ** enough to be conditionalized??
+ */
+
+ bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
+ cp->phys.header.stamp.start = ticks;
+
+ nego = 0;
+ if (tp->nego_cp == NULL) {
+
+ if (tp->tinfo.current.width
+ != tp->tinfo.goal.width) {
+ tp->nego_cp = cp;
+ nego = NS_WIDE;
+ } else if ((tp->tinfo.current.period
+ != tp->tinfo.goal.period)
+ || (tp->tinfo.current.offset
+ != tp->tinfo.goal.offset)) {
+ tp->nego_cp = cp;
+ nego = NS_SYNC;
+ };
+ };
+
+ /*---------------------------------------------------
+ **
+ ** choose a new tag ...
+ **
+ **----------------------------------------------------
+ */
+ lp = tp->lp[ccb->ccb_h.target_lun];
+
+ if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
+ && (ccb->csio.tag_action != CAM_TAG_ACTION_NONE)
+ && (nego == 0)) {
+ /*
+ ** assign a tag to this nccb
+ */
+ while (!cp->tag) {
+ nccb_p cp2 = lp->next_nccb;
+ lp->lasttag = lp->lasttag % 255 + 1;
+ while (cp2 && cp2->tag != lp->lasttag)
+ cp2 = cp2->next_nccb;
+ if (cp2) continue;
+ cp->tag=lp->lasttag;
+ if (DEBUG_FLAGS & DEBUG_TAGS) {
+ PRINT_ADDR(ccb);
+ printf ("using tag #%d.\n", cp->tag);
+ };
+ };
+ } else {
+ cp->tag=0;
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Build the identify / tag / sdtr message
+ **
+ **----------------------------------------------------
+ */
+ idmsg = MSG_IDENTIFYFLAG | ccb->ccb_h.target_lun;
+ if (tp->tinfo.disc_tag & NCR_CUR_DISCENB)
+ idmsg |= MSG_IDENTIFY_DISCFLAG;
+
+ msgptr = cp->scsi_smsg;
+ msglen = 0;
+ msgptr[msglen++] = idmsg;
+
+ if (cp->tag) {
+ msgptr[msglen++] = ccb->csio.tag_action;
+ msgptr[msglen++] = cp->tag;
+ }
+
+ switch (nego) {
+ case NS_SYNC:
+ msgptr[msglen++] = MSG_EXTENDED;
+ msgptr[msglen++] = MSG_EXT_SDTR_LEN;
+ msgptr[msglen++] = MSG_EXT_SDTR;
+ msgptr[msglen++] = tp->tinfo.goal.period;
+ msgptr[msglen++] = tp->tinfo.goal.offset;;
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(ccb);
+ printf ("sync msgout: ");
+ ncr_show_msg (&cp->scsi_smsg [msglen-5]);
+ printf (".\n");
+ };
+ break;
+ case NS_WIDE:
+ msgptr[msglen++] = MSG_EXTENDED;
+ msgptr[msglen++] = MSG_EXT_WDTR_LEN;
+ msgptr[msglen++] = MSG_EXT_WDTR;
+ msgptr[msglen++] = tp->tinfo.goal.width;
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(ccb);
+ printf ("wide msgout: ");
+ ncr_show_msg (&cp->scsi_smsg [msglen-4]);
+ printf (".\n");
+ };
+ break;
+ };
+
+ /*----------------------------------------------------
+ **
+ ** Build the identify message for getcc.
+ **
+ **----------------------------------------------------
+ */
+
+ cp->scsi_smsg2 [0] = idmsg;
+ msglen2 = 1;
+
+ /*----------------------------------------------------
+ **
+ ** Build the data descriptors
+ **
+ **----------------------------------------------------
+ */
+
+ /* XXX JGibbs - Handle other types of I/O */
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ segments = ncr_scatter(&cp->phys,
+ (vm_offset_t)csio->data_ptr,
+ (vm_size_t)csio->dxfer_len);
+
+ if (segments < 0) {
+ ccb->ccb_h.status = CAM_REQ_TOO_BIG;
+ ncr_free_nccb(np, cp);
+ splx(oldspl);
+ xpt_done(ccb);
+ return;
+ }
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
+ cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
+ } else { /* CAM_DIR_OUT */
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out);
+ cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
+ }
+ } else {
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+ cp->phys.header.goalp = cp->phys.header.savep;
+ }
+
+ cp->phys.header.lastp = cp->phys.header.savep;
+
+
+ /*----------------------------------------------------
+ **
+ ** fill in nccb
+ **
+ **----------------------------------------------------
+ **
+ **
+ ** physical -> virtual backlink
+ ** Generic SCSI command
+ */
+ cp->phys.header.cp = cp;
+ /*
+ ** Startqueue
+ */
+ cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, select);
+ cp->phys.header.launch.l_cmd = SCR_JUMP;
+ /*
+ ** select
+ */
+ cp->phys.select.sel_id = ccb->ccb_h.target_id;
+ cp->phys.select.sel_scntl3 = tp->tinfo.wval;
+ cp->phys.select.sel_sxfer = tp->tinfo.sval;
+ /*
+ ** message
+ */
+ cp->phys.smsg.addr = CCB_PHYS (cp, scsi_smsg);
+ cp->phys.smsg.size = msglen;
+
+ cp->phys.smsg2.addr = CCB_PHYS (cp, scsi_smsg2);
+ cp->phys.smsg2.size = msglen2;
+ /*
+ ** command
+ */
+ /* XXX JGibbs - Support other command types */
+ cp->phys.cmd.addr = vtophys (csio->cdb_io.cdb_bytes);
+ cp->phys.cmd.size = csio->cdb_len;
+ /*
+ ** sense command
+ */
+ cp->phys.scmd.addr = CCB_PHYS (cp, sensecmd);
+ cp->phys.scmd.size = 6;
+ /*
+ ** patch requested size into sense command
+ */
+ cp->sensecmd[0] = 0x03;
+ cp->sensecmd[1] = ccb->ccb_h.target_lun << 5;
+ cp->sensecmd[4] = sizeof(struct scsi_sense_data);
+ cp->sensecmd[4] = csio->sense_len;
+ /*
+ ** sense data
+ */
+ cp->phys.sense.addr = vtophys (&csio->sense_data);
+ cp->phys.sense.size = csio->sense_len;
+ /*
+ ** status
+ */
+ cp->actualquirks = QUIRK_NOMSG;
+ cp->host_status = nego ? HS_NEGOTIATE : HS_BUSY;
+ cp->s_status = SCSI_STATUS_ILLEGAL;
+ cp->parity_status = 0;
+
+ cp->xerr_status = XE_OK;
+ cp->sync_status = tp->tinfo.sval;
+ cp->nego_status = nego;
+ cp->wide_status = tp->tinfo.wval;
+
+ /*----------------------------------------------------
+ **
+ ** Critical region: start this job.
+ **
+ **----------------------------------------------------
+ */
+
+ /*
+ ** reselect pattern and activate this job.
+ */
+
+ cp->jump_nccb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (cp->tag)));
+ cp->tlimit = time_second
+ + ccb->ccb_h.timeout / 1000 + 2;
+ cp->magic = CCB_MAGIC;
+
+ /*
+ ** insert into start queue.
+ */
+
+ qidx = np->squeueput + 1;
+ if (qidx >= MAX_START) qidx=0;
+ np->squeue [qidx ] = NCB_SCRIPT_PHYS (np, idle);
+ np->squeue [np->squeueput] = CCB_PHYS (cp, phys);
+ np->squeueput = qidx;
+
+ if(DEBUG_FLAGS & DEBUG_QUEUE)
+ printf("%s: queuepos=%d tryoffset=%d.\n",
+ ncr_name (np), np->squeueput,
+ (unsigned)(READSCRIPT(startpos[0]) -
+ (NCB_SCRIPTH_PHYS (np, tryloop))));
+
+ /*
+ ** Script processor may be waiting for reselect.
+ ** Wake it up.
+ */
+ OUTB (nc_istat, SIGP);
+
+ /*
+ ** and reenable interrupts
+ */
+ splx (oldspl);
+ break;
+ }
+ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
+ case XPT_EN_LUN: /* Enable LUN as a target */
+ case XPT_TARGET_IO: /* Execute target I/O request */
+ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */
+ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/
+ case XPT_ABORT: /* Abort the specified CCB */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ tcb_p tp;
+ u_int update_type;
+ int s;
+
+ cts = &ccb->cts;
+ update_type = 0;
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
+ update_type |= NCR_TRANS_GOAL;
+ if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
+ update_type |= NCR_TRANS_USER;
+
+ s = splcam();
+ tp = &np->target[ccb->ccb_h.target_id];
+ /* Tag and disc enables */
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
+ if (update_type & NCR_TRANS_GOAL) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ tp->tinfo.disc_tag |= NCR_CUR_DISCENB;
+ else
+ tp->tinfo.disc_tag &= ~NCR_CUR_DISCENB;
+ }
+
+ if (update_type & NCR_TRANS_USER) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ tp->tinfo.disc_tag |= NCR_USR_DISCENB;
+ else
+ tp->tinfo.disc_tag &= ~NCR_USR_DISCENB;
+ }
+
+ }
+
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
+ if (update_type & NCR_TRANS_GOAL) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ tp->tinfo.disc_tag |= NCR_CUR_TAGENB;
+ else
+ tp->tinfo.disc_tag &= ~NCR_CUR_TAGENB;
+ }
+
+ if (update_type & NCR_TRANS_USER) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ tp->tinfo.disc_tag |= NCR_USR_TAGENB;
+ else
+ tp->tinfo.disc_tag &= ~NCR_USR_TAGENB;
+ }
+ }
+
+ /* Filter bus width and sync negotiation settings */
+ if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
+ if (cts->bus_width > np->maxwide)
+ cts->bus_width = np->maxwide;
+ }
+
+ if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
+ || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
+ if (cts->sync_period != 0
+ && (cts->sync_period < np->minsync))
+ cts->sync_period = np->minsync;
+ }
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
+ if (cts->sync_offset == 0)
+ cts->sync_period = 0;
+ if (cts->sync_offset > np->maxoffs)
+ cts->sync_offset = np->maxoffs;
+ }
+ }
+ if ((update_type & NCR_TRANS_USER) != 0) {
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
+ tp->tinfo.user.period = cts->sync_period;
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
+ tp->tinfo.user.offset = cts->sync_offset;
+ if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
+ tp->tinfo.user.width = cts->bus_width;
+ }
+ if ((update_type & NCR_TRANS_GOAL) != 0) {
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
+ tp->tinfo.goal.period = cts->sync_period;
+
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
+ tp->tinfo.goal.offset = cts->sync_offset;
+
+ if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
+ tp->tinfo.goal.width = cts->bus_width;
+ }
+ splx(s);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ /* Get default/user set transfer settings for the target */
+ {
+ struct ccb_trans_settings *cts;
+ struct ncr_transinfo *tinfo;
+ tcb_p tp;
+ int s;
+
+ cts = &ccb->cts;
+ tp = &np->target[ccb->ccb_h.target_id];
+
+ s = splcam();
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ tinfo = &tp->tinfo.current;
+ if (tp->tinfo.disc_tag & NCR_CUR_DISCENB)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_DISC_ENB;
+
+ if (tp->tinfo.disc_tag & NCR_CUR_TAGENB)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_TAG_ENB;
+ } else {
+ tinfo = &tp->tinfo.user;
+ if (tp->tinfo.disc_tag & NCR_USR_DISCENB)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_DISC_ENB;
+
+ if (tp->tinfo.disc_tag & NCR_USR_TAGENB)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_TAG_ENB;
+ }
+
+ cts->sync_period = tinfo->period;
+ cts->sync_offset = tinfo->offset;
+ cts->bus_width = tinfo->width;
+
+ splx(s);
+
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_CALC_GEOMETRY:
+ {
+ struct ccb_calc_geometry *ccg;
+ u_int32_t size_mb;
+ u_int32_t secs_per_cylinder;
+ int extended;
+
+ /* XXX JGibbs - I'm sure the NCR uses a different strategy,
+ * but it should be able to deal with Adaptec
+ * geometry too.
+ */
+ extended = 1;
+ ccg = &ccb->ccg;
+ size_mb = ccg->volume_size
+ / ((1024L * 1024L) / ccg->block_size);
+
+ if (size_mb > 1024 && extended) {
+ ccg->heads = 255;
+ ccg->secs_per_track = 63;
+ } else {
+ ccg->heads = 64;
+ ccg->secs_per_track = 32;
+ }
+ secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+ ccg->cylinders = ccg->volume_size / secs_per_cylinder;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_RESET_BUS: /* Reset the specified SCSI bus */
+ {
+ OUTB (nc_scntl1, CRST);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ DELAY(10000); /* Wait until our interrupt handler sees it */
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_TERM_IO: /* Terminate the I/O process */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_PATH_INQ: /* Path routing inquiry */
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1; /* XXX??? */
+ cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
+ if ((np->features & FE_WIDE) != 0)
+ cpi->hba_inquiry |= PI_WIDE_16;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = 0;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = (np->features & FE_WIDE) ? 15 : 7;
+ cpi->max_lun = MAX_LUN - 1;
+ cpi->initiator_id = np->myaddr;
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 3300;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Symbios", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
+/*==========================================================
+**
+**
+** Complete execution of a SCSI command.
+** Signal completion to the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+void
+ncr_complete (ncb_p np, nccb_p cp)
+{
+ union ccb *ccb;
+ tcb_p tp;
+ lcb_p lp;
+
+ /*
+ ** Sanity check
+ */
+
+ if (!cp || (cp->magic!=CCB_MAGIC) || !cp->ccb) return;
+ cp->magic = 1;
+ cp->tlimit= 0;
+
+ /*
+ ** No Reselect anymore.
+ */
+ cp->jump_nccb.l_cmd = (SCR_JUMP);
+
+ /*
+ ** No starting.
+ */
+ cp->phys.header.launch.l_paddr= NCB_SCRIPT_PHYS (np, idle);
+
+ /*
+ ** timestamp
+ */
+ ncb_profile (np, cp);
+
+ if (DEBUG_FLAGS & DEBUG_TINY)
+ printf ("CCB=%x STAT=%x/%x\n", (int)(intptr_t)cp & 0xfff,
+ cp->host_status,cp->s_status);
+
+ ccb = cp->ccb;
+ cp->ccb = NULL;
+ tp = &np->target[ccb->ccb_h.target_id];
+ lp = tp->lp[ccb->ccb_h.target_lun];
+
+ /*
+ ** We do not queue more than 1 nccb per target
+ ** with negotiation at any time. If this nccb was
+ ** used for negotiation, clear this info in the tcb.
+ */
+
+ if (cp == tp->nego_cp)
+ tp->nego_cp = NULL;
+
+ /*
+ ** Check for parity errors.
+ */
+ /* XXX JGibbs - What about reporting them??? */
+
+ if (cp->parity_status) {
+ PRINT_ADDR(ccb);
+ printf ("%d parity error(s), fallback.\n", cp->parity_status);
+ /*
+ ** fallback to asynch transfer.
+ */
+ tp->tinfo.goal.period = 0;
+ tp->tinfo.goal.offset = 0;
+ };
+
+ /*
+ ** Check for extended errors.
+ */
+
+ if (cp->xerr_status != XE_OK) {
+ PRINT_ADDR(ccb);
+ switch (cp->xerr_status) {
+ case XE_EXTRA_DATA:
+ printf ("extraneous data discarded.\n");
+ break;
+ case XE_BAD_PHASE:
+ printf ("illegal scsi phase (4/5).\n");
+ break;
+ default:
+ printf ("extended error %d.\n", cp->xerr_status);
+ break;
+ };
+ if (cp->host_status==HS_COMPLETE)
+ cp->host_status = HS_FAIL;
+ };
+
+ /*
+ ** Check the status.
+ */
+ if (cp->host_status == HS_COMPLETE) {
+
+ if (cp->s_status == SCSI_STATUS_OK) {
+
+ /*
+ ** All went well.
+ */
+ /* XXX JGibbs - Properly calculate residual */
+
+ tp->bytes += ccb->csio.dxfer_len;
+ tp->transfers ++;
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ } else if ((cp->s_status & SCSI_STATUS_SENSE) != 0) {
+
+ /*
+ * XXX Could be TERMIO too. Should record
+ * original status.
+ */
+ ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+ cp->s_status &= ~SCSI_STATUS_SENSE;
+ if (cp->s_status == SCSI_STATUS_OK) {
+ ccb->ccb_h.status =
+ CAM_AUTOSNS_VALID|CAM_SCSI_STATUS_ERROR;
+ } else {
+ ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+ }
+ } else {
+ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ ccb->csio.scsi_status = cp->s_status;
+ }
+
+
+ } else if (cp->host_status == HS_SEL_TIMEOUT) {
+
+ /*
+ ** Device failed selection
+ */
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+
+ } else if (cp->host_status == HS_TIMEOUT) {
+
+ /*
+ ** No response
+ */
+ ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ } else if (cp->host_status == HS_STALL) {
+ ccb->ccb_h.status = CAM_REQUEUE_REQ;
+ } else {
+
+ /*
+ ** Other protocol messes
+ */
+ PRINT_ADDR(ccb);
+ printf ("COMMAND FAILED (%x %x) @%p.\n",
+ cp->host_status, cp->s_status, cp);
+
+ ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ }
+
+ /*
+ ** Free this nccb
+ */
+ ncr_free_nccb (np, cp);
+
+ /*
+ ** signal completion to generic driver.
+ */
+ xpt_done (ccb);
+}
+
+/*==========================================================
+**
+**
+** Signal all (or one) control block done.
+**
+**
+**==========================================================
+*/
+
+void
+ncr_wakeup (ncb_p np, u_long code)
+{
+ /*
+ ** Starting at the default nccb and following
+ ** the links, complete all jobs with a
+ ** host_status greater than "disconnect".
+ **
+ ** If the "code" parameter is not zero,
+ ** complete all jobs that are not IDLE.
+ */
+
+ nccb_p cp = np->link_nccb;
+ while (cp) {
+ switch (cp->host_status) {
+
+ case HS_IDLE:
+ break;
+
+ case HS_DISCONNECT:
+ if(DEBUG_FLAGS & DEBUG_TINY) printf ("D");
+ /* fall through */
+
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ if (!code) break;
+ cp->host_status = code;
+
+ /* fall through */
+
+ default:
+ ncr_complete (np, cp);
+ break;
+ };
+ cp = cp -> link_nccb;
+ };
+}
+
+static void
+ncr_freeze_devq (ncb_p np, struct cam_path *path)
+{
+ nccb_p cp;
+ int i;
+ int count;
+ int firstskip;
+ /*
+ ** Starting at the first nccb and following
+ ** the links, complete all jobs that match
+ ** the passed in path and are in the start queue.
+ */
+
+ cp = np->link_nccb;
+ count = 0;
+ firstskip = 0;
+ while (cp) {
+ switch (cp->host_status) {
+
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ if ((cp->phys.header.launch.l_paddr
+ == NCB_SCRIPT_PHYS (np, select))
+ && (xpt_path_comp(path, cp->ccb->ccb_h.path) >= 0)) {
+
+ /* Mark for removal from the start queue */
+ for (i = 1; i < MAX_START; i++) {
+ int idx;
+
+ idx = np->squeueput - i;
+
+ if (idx < 0)
+ idx = MAX_START + idx;
+ if (np->squeue[idx]
+ == CCB_PHYS(cp, phys)) {
+ np->squeue[idx] =
+ NCB_SCRIPT_PHYS (np, skip);
+ if (i > firstskip)
+ firstskip = i;
+ break;
+ }
+ }
+ cp->host_status=HS_STALL;
+ ncr_complete (np, cp);
+ count++;
+ }
+ break;
+ default:
+ break;
+ }
+ cp = cp->link_nccb;
+ }
+
+ if (count > 0) {
+ int j;
+ int bidx;
+
+ /* Compress the start queue */
+ j = 0;
+ bidx = np->squeueput;
+ i = np->squeueput - firstskip;
+ if (i < 0)
+ i = MAX_START + i;
+ for (;;) {
+
+ bidx = i - j;
+ if (bidx < 0)
+ bidx = MAX_START + bidx;
+
+ if (np->squeue[i] == NCB_SCRIPT_PHYS (np, skip)) {
+ j++;
+ } else if (j != 0) {
+ np->squeue[bidx] = np->squeue[i];
+ if (np->squeue[bidx]
+ == NCB_SCRIPT_PHYS(np, idle))
+ break;
+ }
+ i = (i + 1) % MAX_START;
+ }
+ np->squeueput = bidx;
+ }
+}
+
+/*==========================================================
+**
+**
+** Start NCR chip.
+**
+**
+**==========================================================
+*/
+
+void
+ncr_init(ncb_p np, char * msg, u_long code)
+{
+ int i;
+
+ /*
+ ** Reset chip.
+ */
+
+ OUTB (nc_istat, SRST);
+ DELAY (1000);
+ OUTB (nc_istat, 0);
+
+ /*
+ ** Message.
+ */
+
+ if (msg) printf ("%s: restart (%s).\n", ncr_name (np), msg);
+
+ /*
+ ** Clear Start Queue
+ */
+
+ for (i=0;i<MAX_START;i++)
+ np -> squeue [i] = NCB_SCRIPT_PHYS (np, idle);
+
+ /*
+ ** Start at first entry.
+ */
+
+ np->squeueput = 0;
+ WRITESCRIPT(startpos[0], NCB_SCRIPTH_PHYS (np, tryloop));
+ WRITESCRIPT(start0 [0], SCR_INT ^ IFFALSE (0));
+
+ /*
+ ** Wakeup all pending jobs.
+ */
+
+ ncr_wakeup (np, code);
+
+ /*
+ ** Init chip.
+ */
+
+ OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */
+ OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */
+ OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */
+ ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */
+ OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */
+ OUTW (nc_respid, 1ul<<np->myaddr);/* id to respond to */
+ OUTB (nc_istat , SIGP ); /* Signal Process */
+ OUTB (nc_dmode , np->rv_dmode); /* XXX modify burstlen ??? */
+ OUTB (nc_dcntl , np->rv_dcntl);
+ OUTB (nc_ctest3, np->rv_ctest3);
+ OUTB (nc_ctest5, np->rv_ctest5);
+ OUTB (nc_ctest4, np->rv_ctest4);/* enable master parity checking */
+ OUTB (nc_stest2, np->rv_stest2|EXT); /* Extended Sreq/Sack filtering */
+ OUTB (nc_stest3, TE ); /* TolerANT enable */
+ OUTB (nc_stime0, 0x0b ); /* HTH = disabled, STO = 0.1 sec. */
+
+ if (bootverbose >= 2) {
+ printf ("\tACTUAL values:SCNTL3:%02x DMODE:%02x DCNTL:%02x\n",
+ np->rv_scntl3, np->rv_dmode, np->rv_dcntl);
+ printf ("\t CTEST3:%02x CTEST4:%02x CTEST5:%02x\n",
+ np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+ }
+
+ /*
+ ** Enable GPIO0 pin for writing if LED support.
+ */
+
+ if (np->features & FE_LED0) {
+ OUTOFFB (nc_gpcntl, 0x01);
+ }
+
+ /*
+ ** Fill in target structure.
+ */
+ for (i=0;i<MAX_TARGET;i++) {
+ tcb_p tp = &np->target[i];
+
+ tp->tinfo.sval = 0;
+ tp->tinfo.wval = np->rv_scntl3;
+
+ tp->tinfo.current.period = 0;
+ tp->tinfo.current.offset = 0;
+ tp->tinfo.current.width = MSG_EXT_WDTR_BUS_8_BIT;
+ }
+
+ /*
+ ** enable ints
+ */
+
+ OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
+ OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
+
+ /*
+ ** Start script processor.
+ */
+
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+
+ /*
+ * Notify the XPT of the event
+ */
+ if (code == HS_RESET)
+ xpt_async(AC_BUS_RESET, np->path, NULL);
+}
+
+static void
+ncr_poll(struct cam_sim *sim)
+{
+ ncr_intr(cam_sim_softc(sim));
+}
+
+
+/*==========================================================
+**
+** Get clock factor and sync divisor for a given
+** synchronous factor period.
+** Returns the clock factor (in sxfer) and scntl3
+** synchronous divisor field.
+**
+**==========================================================
+*/
+
+static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p)
+{
+ u_long clk = np->clock_khz; /* SCSI clock frequency in kHz */
+ int div = np->clock_divn; /* Number of divisors supported */
+ u_long fak; /* Sync factor in sxfer */
+ u_long per; /* Period in tenths of ns */
+ u_long kpc; /* (per * clk) */
+
+ /*
+ ** Compute the synchronous period in tenths of nano-seconds
+ */
+ if (sfac <= 10) per = 250;
+ else if (sfac == 11) per = 303;
+ else if (sfac == 12) per = 500;
+ else per = 40 * sfac;
+
+ /*
+ ** Look for the greatest clock divisor that allows an
+ ** input speed faster than the period.
+ */
+ kpc = per * clk;
+ while (--div >= 0)
+ if (kpc >= (div_10M[div] * 4)) break;
+
+ /*
+ ** Calculate the lowest clock factor that allows an output
+ ** speed not faster than the period.
+ */
+ fak = (kpc - 1) / div_10M[div] + 1;
+
+#if 0 /* You can #if 1 if you think this optimization is usefull */
+
+ per = (fak * div_10M[div]) / clk;
+
+ /*
+ ** Why not to try the immediate lower divisor and to choose
+ ** the one that allows the fastest output speed ?
+ ** We dont want input speed too much greater than output speed.
+ */
+ if (div >= 1 && fak < 6) {
+ u_long fak2, per2;
+ fak2 = (kpc - 1) / div_10M[div-1] + 1;
+ per2 = (fak2 * div_10M[div-1]) / clk;
+ if (per2 < per && fak2 <= 6) {
+ fak = fak2;
+ per = per2;
+ --div;
+ }
+ }
+#endif
+
+ if (fak < 4) fak = 4; /* Should never happen, too bad ... */
+
+ /*
+ ** Compute and return sync parameters for the ncr
+ */
+ *fakp = fak - 4;
+ *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+}
+
+/*==========================================================
+**
+** Switch sync mode for current job and its target
+**
+**==========================================================
+*/
+
+static void
+ncr_setsync(ncb_p np, nccb_p cp, u_char scntl3, u_char sxfer, u_char period)
+{
+ union ccb *ccb;
+ struct ccb_trans_settings neg;
+ tcb_p tp;
+ int div;
+ u_int target = INB (nc_sdid) & 0x0f;
+ u_int period_10ns;
+
+ assert (cp);
+ if (!cp) return;
+
+ ccb = cp->ccb;
+ assert (ccb);
+ if (!ccb) return;
+ assert (target == ccb->ccb_h.target_id);
+
+ tp = &np->target[target];
+
+ if (!scntl3 || !(sxfer & 0x1f))
+ scntl3 = np->rv_scntl3;
+ scntl3 = (scntl3 & 0xf0) | (tp->tinfo.wval & EWS)
+ | (np->rv_scntl3 & 0x07);
+
+ /*
+ ** Deduce the value of controller sync period from scntl3.
+ ** period is in tenths of nano-seconds.
+ */
+
+ div = ((scntl3 >> 4) & 0x7);
+ if ((sxfer & 0x1f) && div)
+ period_10ns =
+ (((sxfer>>5)+4)*div_10M[div-1])/np->clock_khz;
+ else
+ period_10ns = 0;
+
+ tp->tinfo.goal.period = period;
+ tp->tinfo.goal.offset = sxfer & 0x1f;
+ tp->tinfo.current.period = period;
+ tp->tinfo.current.offset = sxfer & 0x1f;
+
+ /*
+ ** Stop there if sync parameters are unchanged
+ */
+ if (tp->tinfo.sval == sxfer && tp->tinfo.wval == scntl3) return;
+ tp->tinfo.sval = sxfer;
+ tp->tinfo.wval = scntl3;
+
+ if (sxfer & 0x1f) {
+ /*
+ ** Disable extended Sreq/Sack filtering
+ */
+ if (period_10ns <= 2000) OUTOFFB (nc_stest2, EXT);
+ }
+
+ /*
+ ** Tell the SCSI layer about the
+ ** new transfer parameters.
+ */
+ neg.sync_period = period;
+ neg.sync_offset = sxfer & 0x1f;
+ neg.valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID;
+ xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path,
+ /*priority*/1);
+ xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
+
+ /*
+ ** set actual value and sync_status
+ */
+ OUTB (nc_sxfer, sxfer);
+ np->sync_st = sxfer;
+ OUTB (nc_scntl3, scntl3);
+ np->wide_st = scntl3;
+
+ /*
+ ** patch ALL nccbs of this target.
+ */
+ for (cp = np->link_nccb; cp; cp = cp->link_nccb) {
+ if (!cp->ccb) continue;
+ if (cp->ccb->ccb_h.target_id != target) continue;
+ cp->sync_status = sxfer;
+ cp->wide_status = scntl3;
+ };
+}
+
+/*==========================================================
+**
+** Switch wide mode for current job and its target
+** SCSI specs say: a SCSI device that accepts a WDTR
+** message shall reset the synchronous agreement to
+** asynchronous mode.
+**
+**==========================================================
+*/
+
+static void ncr_setwide (ncb_p np, nccb_p cp, u_char wide, u_char ack)
+{
+ union ccb *ccb;
+ struct ccb_trans_settings neg;
+ u_int target = INB (nc_sdid) & 0x0f;
+ tcb_p tp;
+ u_char scntl3;
+ u_char sxfer;
+
+ assert (cp);
+ if (!cp) return;
+
+ ccb = cp->ccb;
+ assert (ccb);
+ if (!ccb) return;
+ assert (target == ccb->ccb_h.target_id);
+
+ tp = &np->target[target];
+ tp->tinfo.current.width = wide;
+ tp->tinfo.goal.width = wide;
+ tp->tinfo.current.period = 0;
+ tp->tinfo.current.offset = 0;
+
+ scntl3 = (tp->tinfo.wval & (~EWS)) | (wide ? EWS : 0);
+
+ sxfer = ack ? 0 : tp->tinfo.sval;
+
+ /*
+ ** Stop there if sync/wide parameters are unchanged
+ */
+ if (tp->tinfo.sval == sxfer && tp->tinfo.wval == scntl3) return;
+ tp->tinfo.sval = sxfer;
+ tp->tinfo.wval = scntl3;
+
+ /* Tell the SCSI layer about the new transfer params */
+ neg.bus_width = (scntl3 & EWS) ? MSG_EXT_WDTR_BUS_16_BIT
+ : MSG_EXT_WDTR_BUS_8_BIT;
+ neg.sync_period = 0;
+ neg.sync_offset = 0;
+ neg.valid = CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID;
+ xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path,
+ /*priority*/1);
+ xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
+
+ /*
+ ** set actual value and sync_status
+ */
+ OUTB (nc_sxfer, sxfer);
+ np->sync_st = sxfer;
+ OUTB (nc_scntl3, scntl3);
+ np->wide_st = scntl3;
+
+ /*
+ ** patch ALL nccbs of this target.
+ */
+ for (cp = np->link_nccb; cp; cp = cp->link_nccb) {
+ if (!cp->ccb) continue;
+ if (cp->ccb->ccb_h.target_id != target) continue;
+ cp->sync_status = sxfer;
+ cp->wide_status = scntl3;
+ };
+}
+
+/*==========================================================
+**
+**
+** ncr timeout handler.
+**
+**
+**==========================================================
+**
+** Misused to keep the driver running when
+** interrupts are not configured correctly.
+**
+**----------------------------------------------------------
+*/
+
+static void
+ncr_timeout (void *arg)
+{
+ ncb_p np = arg;
+ time_t thistime = time_second;
+ ticks_t step = np->ticks;
+ u_long count = 0;
+ long signed t;
+ nccb_p cp;
+
+ if (np->lasttime != thistime) {
+ /*
+ ** block ncr interrupts
+ */
+ int oldspl = splcam();
+ np->lasttime = thistime;
+
+ /*----------------------------------------------------
+ **
+ ** handle ncr chip timeouts
+ **
+ ** Assumption:
+ ** We have a chance to arbitrate for the
+ ** SCSI bus at least every 10 seconds.
+ **
+ **----------------------------------------------------
+ */
+
+ t = thistime - np->heartbeat;
+
+ if (t<2) np->latetime=0; else np->latetime++;
+
+ if (np->latetime>2) {
+ /*
+ ** If there are no requests, the script
+ ** processor will sleep on SEL_WAIT_RESEL.
+ ** But we have to check whether it died.
+ ** Let's try to wake it up.
+ */
+ OUTB (nc_istat, SIGP);
+ };
+
+ /*----------------------------------------------------
+ **
+ ** handle nccb timeouts
+ **
+ **----------------------------------------------------
+ */
+
+ for (cp=np->link_nccb; cp; cp=cp->link_nccb) {
+ /*
+ ** look for timed out nccbs.
+ */
+ if (!cp->host_status) continue;
+ count++;
+ if (cp->tlimit > thistime) continue;
+
+ /*
+ ** Disable reselect.
+ ** Remove it from startqueue.
+ */
+ cp->jump_nccb.l_cmd = (SCR_JUMP);
+ if (cp->phys.header.launch.l_paddr ==
+ NCB_SCRIPT_PHYS (np, select)) {
+ printf ("%s: timeout nccb=%p (skip)\n",
+ ncr_name (np), cp);
+ cp->phys.header.launch.l_paddr
+ = NCB_SCRIPT_PHYS (np, skip);
+ };
+
+ switch (cp->host_status) {
+
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ /* fall through */
+ case HS_DISCONNECT:
+ cp->host_status=HS_TIMEOUT;
+ };
+ cp->tag = 0;
+
+ /*
+ ** wakeup this nccb.
+ */
+ ncr_complete (np, cp);
+ };
+ splx (oldspl);
+ }
+
+ np->timeout_ch =
+ timeout (ncr_timeout, (caddr_t) np, step ? step : 1);
+
+ if (INB(nc_istat) & (INTF|SIP|DIP)) {
+
+ /*
+ ** Process pending interrupts.
+ */
+
+ int oldspl = splcam();
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("{");
+ ncr_exception (np);
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("}");
+ splx (oldspl);
+ };
+}
+
+/*==========================================================
+**
+** log message for real hard errors
+**
+** "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)."
+** " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf."
+**
+** exception register:
+** ds: dstat
+** si: sist
+**
+** SCSI bus lines:
+** so: control lines as driver by NCR.
+** si: control lines as seen by NCR.
+** sd: scsi data lines as seen by NCR.
+**
+** wide/fastmode:
+** sxfer: (see the manual)
+** scntl3: (see the manual)
+**
+** current script command:
+** dsp: script address (relative to start of script).
+** dbc: first word of script command.
+**
+** First 16 register of the chip:
+** r0..rf
+**
+**==========================================================
+*/
+
+static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
+{
+ u_int32_t dsp;
+ int script_ofs;
+ int script_size;
+ char *script_name;
+ u_char *script_base;
+ int i;
+
+ dsp = INL (nc_dsp);
+
+ if (np->p_script < dsp &&
+ dsp <= np->p_script + sizeof(struct script)) {
+ script_ofs = dsp - np->p_script;
+ script_size = sizeof(struct script);
+ script_base = (u_char *) np->script;
+ script_name = "script";
+ }
+ else if (np->p_scripth < dsp &&
+ dsp <= np->p_scripth + sizeof(struct scripth)) {
+ script_ofs = dsp - np->p_scripth;
+ script_size = sizeof(struct scripth);
+ script_base = (u_char *) np->scripth;
+ script_name = "scripth";
+ } else {
+ script_ofs = dsp;
+ script_size = 0;
+ script_base = 0;
+ script_name = "mem";
+ }
+
+ printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
+ ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
+ (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
+ (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
+ (unsigned)INL (nc_dbc));
+
+ if (((script_ofs & 3) == 0) &&
+ (unsigned)script_ofs < script_size) {
+ printf ("%s: script cmd = %08x\n", ncr_name(np),
+ (int)READSCRIPT_OFF(script_base, script_ofs));
+ }
+
+ printf ("%s: regdump:", ncr_name(np));
+ for (i=0; i<16;i++)
+ printf (" %02x", (unsigned)INB_OFF(i));
+ printf (".\n");
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler.
+**
+**
+**==========================================================
+*/
+
+void ncr_exception (ncb_p np)
+{
+ u_char istat, dstat;
+ u_short sist;
+
+ /*
+ ** interrupt on the fly ?
+ */
+ while ((istat = INB (nc_istat)) & INTF) {
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+ OUTB (nc_istat, INTF);
+ np->profile.num_fly++;
+ ncr_wakeup (np, 0);
+ };
+ if (!(istat & (SIP|DIP))) {
+ return;
+ }
+
+ /*
+ ** Steinbach's Guideline for Systems Programming:
+ ** Never test for an error condition you don't know how to handle.
+ */
+
+ sist = (istat & SIP) ? INW (nc_sist) : 0;
+ dstat = (istat & DIP) ? INB (nc_dstat) : 0;
+ np->profile.num_int++;
+
+ if (DEBUG_FLAGS & DEBUG_TINY)
+ printf ("<%d|%x:%x|%x:%x>",
+ INB(nc_scr0),
+ dstat,sist,
+ (unsigned)INL(nc_dsp),
+ (unsigned)INL(nc_dbc));
+ if ((dstat==DFE) && (sist==PAR)) return;
+
+/*==========================================================
+**
+** First the normal cases.
+**
+**==========================================================
+*/
+ /*-------------------------------------------
+ ** SCSI reset
+ **-------------------------------------------
+ */
+
+ if (sist & RST) {
+ ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
+ return;
+ };
+
+ /*-------------------------------------------
+ ** selection timeout
+ **
+ ** IID excluded from dstat mask!
+ ** (chip bug)
+ **-------------------------------------------
+ */
+
+ if ((sist & STO) &&
+ !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR))) {
+ ncr_int_sto (np);
+ return;
+ };
+
+ /*-------------------------------------------
+ ** Phase mismatch.
+ **-------------------------------------------
+ */
+
+ if ((sist & MA) &&
+ !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ ncr_int_ma (np, dstat);
+ return;
+ };
+
+ /*----------------------------------------
+ ** move command with length 0
+ **----------------------------------------
+ */
+
+ if ((dstat & IID) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR)) &&
+ ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
+ /*
+ ** Target wants more data than available.
+ ** The "no_data" script will do it.
+ */
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+ return;
+ };
+
+ /*-------------------------------------------
+ ** Programmed interrupt
+ **-------------------------------------------
+ */
+
+ if ((dstat & SIR) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|IID)) &&
+ (INB(nc_dsps) <= SIR_MAX)) {
+ ncr_int_sir (np);
+ return;
+ };
+
+ /*========================================
+ ** log message for real hard errors
+ **========================================
+ */
+
+ ncr_log_hard_error(np, sist, dstat);
+
+ /*========================================
+ ** do the register dump
+ **========================================
+ */
+
+ if (time_second - np->regtime > 10) {
+ int i;
+ np->regtime = time_second;
+ for (i=0; i<sizeof(np->regdump); i++)
+ ((volatile char*)&np->regdump)[i] = INB_OFF(i);
+ np->regdump.nc_dstat = dstat;
+ np->regdump.nc_sist = sist;
+ };
+
+
+ /*----------------------------------------
+ ** clean up the dma fifo
+ **----------------------------------------
+ */
+
+ if ( (INB(nc_sstat0) & (ILF|ORF|OLF) ) ||
+ (INB(nc_sstat1) & (FF3210) ) ||
+ (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) || /* wide .. */
+ !(dstat & DFE)) {
+ printf ("%s: have to clear fifos.\n", ncr_name (np));
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+ OUTB (nc_ctest3, np->rv_ctest3 | CLF);
+ /* clear dma fifo */
+ }
+
+ /*----------------------------------------
+ ** handshake timeout
+ **----------------------------------------
+ */
+
+ if (sist & HTH) {
+ printf ("%s: handshake timeout\n", ncr_name(np));
+ OUTB (nc_scntl1, CRST);
+ DELAY (1000);
+ OUTB (nc_scntl1, 0x00);
+ OUTB (nc_scr0, HS_FAIL);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ return;
+ }
+
+ /*----------------------------------------
+ ** unexpected disconnect
+ **----------------------------------------
+ */
+
+ if ((sist & UDC) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ OUTB (nc_scr0, HS_UNEXPECTED);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ return;
+ };
+
+ /*----------------------------------------
+ ** cannot disconnect
+ **----------------------------------------
+ */
+
+ if ((dstat & IID) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR)) &&
+ ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
+ /*
+ ** Unexpected data cycle while waiting for disconnect.
+ */
+ if (INB(nc_sstat2) & LDSC) {
+ /*
+ ** It's an early reconnect.
+ ** Let's continue ...
+ */
+ OUTB (nc_dcntl, np->rv_dcntl | STD);
+ /*
+ ** info message
+ */
+ printf ("%s: INFO: LDSC while IID.\n",
+ ncr_name (np));
+ return;
+ };
+ printf ("%s: target %d doesn't release the bus.\n",
+ ncr_name (np), INB (nc_sdid)&0x0f);
+ /*
+ ** return without restarting the NCR.
+ ** timeout will do the real work.
+ */
+ return;
+ };
+
+ /*----------------------------------------
+ ** single step
+ **----------------------------------------
+ */
+
+ if ((dstat & SSI) &&
+ !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
+ !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
+ OUTB (nc_dcntl, np->rv_dcntl | STD);
+ return;
+ };
+
+/*
+** @RECOVER@ HTH, SGE, ABRT.
+**
+** We should try to recover from these interrupts.
+** They may occur if there are problems with synch transfers, or
+** if targets are switched on or off while the driver is running.
+*/
+
+ if (sist & SGE) {
+ /* clear scsi offsets */
+ OUTB (nc_ctest3, np->rv_ctest3 | CLF);
+ }
+
+ /*
+ ** Freeze controller to be able to read the messages.
+ */
+
+ if (DEBUG_FLAGS & DEBUG_FREEZE) {
+ int i;
+ unsigned char val;
+ for (i=0; i<0x60; i++) {
+ switch (i%16) {
+
+ case 0:
+ printf ("%s: reg[%d0]: ",
+ ncr_name(np),i/16);
+ break;
+ case 4:
+ case 8:
+ case 12:
+ printf (" ");
+ break;
+ };
+ val = bus_space_read_1(np->bst, np->bsh, i);
+ printf (" %x%x", val/16, val%16);
+ if (i%16==15) printf (".\n");
+ };
+
+ untimeout (ncr_timeout, (caddr_t) np, np->timeout_ch);
+
+ printf ("%s: halted!\n", ncr_name(np));
+ /*
+ ** don't restart controller ...
+ */
+ OUTB (nc_istat, SRST);
+ return;
+ };
+
+#ifdef NCR_FREEZE
+ /*
+ ** Freeze system to be able to read the messages.
+ */
+ printf ("ncr: fatal error: system halted - press reset to reboot ...");
+ (void) splhigh();
+ for (;;);
+#endif
+
+ /*
+ ** sorry, have to kill ALL jobs ...
+ */
+
+ ncr_init (np, "fatal error", HS_FAIL);
+}
+
+/*==========================================================
+**
+** ncr chip exception handler for selection timeout
+**
+**==========================================================
+**
+** There seems to be a bug in the 53c810.
+** Although a STO-Interrupt is pending,
+** it continues executing script commands.
+** But it will fail and interrupt (IID) on
+** the next instruction where it's looking
+** for a valid phase.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_int_sto (ncb_p np)
+{
+ u_long dsa, scratcha, diff;
+ nccb_p cp;
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
+
+ /*
+ ** look for nccb and set the status.
+ */
+
+ dsa = INL (nc_dsa);
+ cp = np->link_nccb;
+ while (cp && (CCB_PHYS (cp, phys) != dsa))
+ cp = cp->link_nccb;
+
+ if (cp) {
+ cp-> host_status = HS_SEL_TIMEOUT;
+ ncr_complete (np, cp);
+ };
+
+ /*
+ ** repair start queue
+ */
+
+ scratcha = INL (nc_scratcha);
+ diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop);
+
+/* assert ((diff <= MAX_START * 20) && !(diff % 20));*/
+
+ if ((diff <= MAX_START * 20) && !(diff % 20)) {
+ WRITESCRIPT(startpos[0], scratcha);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+ return;
+ };
+ ncr_init (np, "selection timeout", HS_FAIL);
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler for phase errors.
+**
+**
+**==========================================================
+**
+** We have to construct a new transfer descriptor,
+** to transfer the rest of the current block.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_int_ma (ncb_p np, u_char dstat)
+{
+ u_int32_t dbc;
+ u_int32_t rest;
+ u_int32_t dsa;
+ u_int32_t dsp;
+ u_int32_t nxtdsp;
+ volatile void *vdsp_base;
+ size_t vdsp_off;
+ u_int32_t oadr, olen;
+ u_int32_t *tblp, *newcmd;
+ u_char cmd, sbcl, ss0, ss2, ctest5;
+ u_short delta;
+ nccb_p cp;
+
+ dsp = INL (nc_dsp);
+ dsa = INL (nc_dsa);
+ dbc = INL (nc_dbc);
+ ss0 = INB (nc_sstat0);
+ ss2 = INB (nc_sstat2);
+ sbcl= INB (nc_sbcl);
+
+ cmd = dbc >> 24;
+ rest= dbc & 0xffffff;
+
+ ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+ if (ctest5 & DFS)
+ delta=(((ctest5<<8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+ else
+ delta=(INB (nc_dfifo) - rest) & 0x7f;
+
+
+ /*
+ ** The data in the dma fifo has not been transfered to
+ ** the target -> add the amount to the rest
+ ** and clear the data.
+ ** Check the sstat2 register in case of wide transfer.
+ */
+
+ if (!(dstat & DFE)) rest += delta;
+ if (ss0 & OLF) rest++;
+ if (ss0 & ORF) rest++;
+ if (INB(nc_scntl3) & EWS) {
+ if (ss2 & OLF1) rest++;
+ if (ss2 & ORF1) rest++;
+ };
+ OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+
+ /*
+ ** locate matching cp
+ */
+ cp = np->link_nccb;
+ while (cp && (CCB_PHYS (cp, phys) != dsa))
+ cp = cp->link_nccb;
+
+ if (!cp) {
+ printf ("%s: SCSI phase error fixup: CCB already dequeued (%p)\n",
+ ncr_name (np), (void *) np->header.cp);
+ return;
+ }
+ if (cp != np->header.cp) {
+ printf ("%s: SCSI phase error fixup: CCB address mismatch "
+ "(%p != %p) np->nccb = %p\n",
+ ncr_name (np), (void *)cp, (void *)np->header.cp,
+ (void *)np->link_nccb);
+/* return;*/
+ }
+
+ /*
+ ** find the interrupted script command,
+ ** and the address at which to continue.
+ */
+
+ if (dsp == vtophys (&cp->patch[2])) {
+ vdsp_base = cp;
+ vdsp_off = offsetof(struct nccb, patch[0]);
+ nxtdsp = READSCRIPT_OFF(vdsp_base, vdsp_off + 3*4);
+ } else if (dsp == vtophys (&cp->patch[6])) {
+ vdsp_base = cp;
+ vdsp_off = offsetof(struct nccb, patch[4]);
+ nxtdsp = READSCRIPT_OFF(vdsp_base, vdsp_off + 3*4);
+ } else if (dsp > np->p_script &&
+ dsp <= np->p_script + sizeof(struct script)) {
+ vdsp_base = np->script;
+ vdsp_off = dsp - np->p_script - 8;
+ nxtdsp = dsp;
+ } else {
+ vdsp_base = np->scripth;
+ vdsp_off = dsp - np->p_scripth - 8;
+ nxtdsp = dsp;
+ };
+
+ /*
+ ** log the information
+ */
+ if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) {
+ printf ("P%x%x ",cmd&7, sbcl&7);
+ printf ("RL=%d D=%d SS0=%x ",
+ (unsigned) rest, (unsigned) delta, ss0);
+ };
+ if (DEBUG_FLAGS & DEBUG_PHASE) {
+ printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
+ cp, np->header.cp,
+ dsp,
+ nxtdsp, (volatile char*)vdsp_base+vdsp_off, cmd);
+ };
+
+ /*
+ ** get old startaddress and old length.
+ */
+
+ oadr = READSCRIPT_OFF(vdsp_base, vdsp_off + 1*4);
+
+ if (cmd & 0x10) { /* Table indirect */
+ tblp = (u_int32_t *) ((char*) &cp->phys + oadr);
+ olen = tblp[0];
+ oadr = tblp[1];
+ } else {
+ tblp = (u_int32_t *) 0;
+ olen = READSCRIPT_OFF(vdsp_base, vdsp_off) & 0xffffff;
+ };
+
+ if (DEBUG_FLAGS & DEBUG_PHASE) {
+ printf ("OCMD=%x\nTBLP=%p OLEN=%lx OADR=%lx\n",
+ (unsigned) (READSCRIPT_OFF(vdsp_base, vdsp_off) >> 24),
+ (void *) tblp,
+ (u_long) olen,
+ (u_long) oadr);
+ };
+
+ /*
+ ** if old phase not dataphase, leave here.
+ */
+
+ if (cmd != (READSCRIPT_OFF(vdsp_base, vdsp_off) >> 24)) {
+ PRINT_ADDR(cp->ccb);
+ printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+ (unsigned)cmd,
+ (unsigned)READSCRIPT_OFF(vdsp_base, vdsp_off) >> 24);
+
+ return;
+ }
+ if (cmd & 0x06) {
+ PRINT_ADDR(cp->ccb);
+ printf ("phase change %x-%x %d@%08x resid=%d.\n",
+ cmd&7, sbcl&7, (unsigned)olen,
+ (unsigned)oadr, (unsigned)rest);
+
+ OUTB (nc_dcntl, np->rv_dcntl | STD);
+ return;
+ };
+
+ /*
+ ** choose the correct patch area.
+ ** if savep points to one, choose the other.
+ */
+
+ newcmd = cp->patch;
+ if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4;
+
+ /*
+ ** fillin the commands
+ */
+
+ newcmd[0] = ((cmd & 0x0f) << 24) | rest;
+ newcmd[1] = oadr + olen - rest;
+ newcmd[2] = SCR_JUMP;
+ newcmd[3] = nxtdsp;
+
+ if (DEBUG_FLAGS & DEBUG_PHASE) {
+ PRINT_ADDR(cp->ccb);
+ printf ("newcmd[%d] %x %x %x %x.\n",
+ (int)(newcmd - cp->patch),
+ (unsigned)newcmd[0],
+ (unsigned)newcmd[1],
+ (unsigned)newcmd[2],
+ (unsigned)newcmd[3]);
+ }
+ /*
+ ** fake the return address (to the patch).
+ ** and restart script processor at dispatcher.
+ */
+ np->profile.num_break++;
+ OUTL (nc_temp, vtophys (newcmd));
+ if ((cmd & 7) == 0)
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ else
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
+}
+
+/*==========================================================
+**
+**
+** ncr chip exception handler for programmed interrupts.
+**
+**
+**==========================================================
+*/
+
+static int ncr_show_msg (u_char * msg)
+{
+ u_char i;
+ printf ("%x",*msg);
+ if (*msg==MSG_EXTENDED) {
+ for (i=1;i<8;i++) {
+ if (i-1>msg[1]) break;
+ printf ("-%x",msg[i]);
+ };
+ return (i+1);
+ } else if ((*msg & 0xf0) == 0x20) {
+ printf ("-%x",msg[1]);
+ return (2);
+ };
+ return (1);
+}
+
+void ncr_int_sir (ncb_p np)
+{
+ u_char scntl3;
+ u_char chg, ofs, per, fak, wide;
+ u_char num = INB (nc_dsps);
+ nccb_p cp=0;
+ u_long dsa;
+ u_int target = INB (nc_sdid) & 0x0f;
+ tcb_p tp = &np->target[target];
+ int i;
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
+
+ switch (num) {
+ case SIR_SENSE_RESTART:
+ case SIR_STALL_RESTART:
+ break;
+
+ default:
+ /*
+ ** lookup the nccb
+ */
+ dsa = INL (nc_dsa);
+ cp = np->link_nccb;
+ while (cp && (CCB_PHYS (cp, phys) != dsa))
+ cp = cp->link_nccb;
+
+ assert (cp);
+ if (!cp)
+ goto out;
+ assert (cp == np->header.cp);
+ if (cp != np->header.cp)
+ goto out;
+ }
+
+ switch (num) {
+
+/*--------------------------------------------------------------------
+**
+** Processing of interrupted getcc selects
+**
+**--------------------------------------------------------------------
+*/
+
+ case SIR_SENSE_RESTART:
+ /*------------------------------------------
+ ** Script processor is idle.
+ ** Look for interrupted "check cond"
+ **------------------------------------------
+ */
+
+ if (DEBUG_FLAGS & DEBUG_RESTART)
+ printf ("%s: int#%d",ncr_name (np),num);
+ cp = (nccb_p) 0;
+ for (i=0; i<MAX_TARGET; i++) {
+ if (DEBUG_FLAGS & DEBUG_RESTART) printf (" t%d", i);
+ tp = &np->target[i];
+ if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
+ cp = tp->hold_cp;
+ if (!cp) continue;
+ if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
+ if ((cp->host_status==HS_BUSY) &&
+ (cp->s_status==SCSI_STATUS_CHECK_COND))
+ break;
+ if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)");
+ tp->hold_cp = cp = (nccb_p) 0;
+ };
+
+ if (cp) {
+ if (DEBUG_FLAGS & DEBUG_RESTART)
+ printf ("+ restart job ..\n");
+ OUTL (nc_dsa, CCB_PHYS (cp, phys));
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc));
+ return;
+ };
+
+ /*
+ ** no job, resume normal processing
+ */
+ if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
+ WRITESCRIPT(start0[0], SCR_INT ^ IFFALSE (0));
+ break;
+
+ case SIR_SENSE_FAILED:
+ /*-------------------------------------------
+ ** While trying to select for
+ ** getting the condition code,
+ ** a target reselected us.
+ **-------------------------------------------
+ */
+ if (DEBUG_FLAGS & DEBUG_RESTART) {
+ PRINT_ADDR(cp->ccb);
+ printf ("in getcc reselect by t%d.\n",
+ INB(nc_ssid) & 0x0f);
+ }
+
+ /*
+ ** Mark this job
+ */
+ cp->host_status = HS_BUSY;
+ cp->s_status = SCSI_STATUS_CHECK_COND;
+ np->target[cp->ccb->ccb_h.target_id].hold_cp = cp;
+
+ /*
+ ** And patch code to restart it.
+ */
+ WRITESCRIPT(start0[0], SCR_INT);
+ break;
+
+/*-----------------------------------------------------------------------------
+**
+** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
+**
+** We try to negotiate sync and wide transfer only after
+** a successfull inquire command. We look at byte 7 of the
+** inquire data to determine the capabilities if the target.
+**
+** When we try to negotiate, we append the negotiation message
+** to the identify and (maybe) simple tag message.
+** The host status field is set to HS_NEGOTIATE to mark this
+** situation.
+**
+** If the target doesn't answer this message immidiately
+** (as required by the standard), the SIR_NEGO_FAIL interrupt
+** will be raised eventually.
+** The handler removes the HS_NEGOTIATE status, and sets the
+** negotiated value to the default (async / nowide).
+**
+** If we receive a matching answer immediately, we check it
+** for validity, and set the values.
+**
+** If we receive a Reject message immediately, we assume the
+** negotiation has failed, and fall back to standard values.
+**
+** If we receive a negotiation message while not in HS_NEGOTIATE
+** state, it's a target initiated negotiation. We prepare a
+** (hopefully) valid answer, set our parameters, and send back
+** this answer to the target.
+**
+** If the target doesn't fetch the answer (no message out phase),
+** we assume the negotiation has failed, and fall back to default
+** settings.
+**
+** When we set the values, we adjust them in all nccbs belonging
+** to this target, in the controller's register, and in the "phys"
+** field of the controller's struct ncb.
+**
+** Possible cases: hs sir msg_in value send goto
+** We try try to negotiate:
+** -> target doesnt't msgin NEG FAIL noop defa. - dispatch
+** -> target rejected our msg NEG FAIL reject defa. - dispatch
+** -> target answered (ok) NEG SYNC sdtr set - clrack
+** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad
+** -> target answered (ok) NEG WIDE wdtr set - clrack
+** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad
+** -> any other msgin NEG FAIL noop defa. - dispatch
+**
+** Target tries to negotiate:
+** -> incoming message --- SYNC sdtr set SDTR -
+** -> incoming message --- WIDE wdtr set WDTR -
+** We sent our answer:
+** -> target doesn't msgout --- PROTO ? defa. - dispatch
+**
+**-----------------------------------------------------------------------------
+*/
+
+ case SIR_NEGO_FAILED:
+ /*-------------------------------------------------------
+ **
+ ** Negotiation failed.
+ ** Target doesn't send an answer message,
+ ** or target rejected our message.
+ **
+ ** Remove negotiation request.
+ **
+ **-------------------------------------------------------
+ */
+ OUTB (HS_PRT, HS_BUSY);
+
+ /* fall through */
+
+ case SIR_NEGO_PROTO:
+ /*-------------------------------------------------------
+ **
+ ** Negotiation failed.
+ ** Target doesn't fetch the answer message.
+ **
+ **-------------------------------------------------------
+ */
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("negotiation failed sir=%x status=%x.\n",
+ num, cp->nego_status);
+ };
+
+ /*
+ ** any error in negotiation:
+ ** fall back to default mode.
+ */
+ switch (cp->nego_status) {
+
+ case NS_SYNC:
+ ncr_setsync (np, cp, 0, 0xe0, 0);
+ break;
+
+ case NS_WIDE:
+ ncr_setwide (np, cp, 0, 0);
+ break;
+
+ };
+ np->msgin [0] = MSG_NOOP;
+ np->msgout[0] = MSG_NOOP;
+ cp->nego_status = 0;
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ break;
+
+ case SIR_NEGO_SYNC:
+ /*
+ ** Synchronous request message received.
+ */
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("sync msgin: ");
+ (void) ncr_show_msg (np->msgin);
+ printf (".\n");
+ };
+
+ /*
+ ** get requested values.
+ */
+
+ chg = 0;
+ per = np->msgin[3];
+ ofs = np->msgin[4];
+ if (ofs==0) per=255;
+
+ /*
+ ** check values against driver limits.
+ */
+ if (per < np->minsync)
+ {chg = 1; per = np->minsync;}
+ if (per < tp->tinfo.user.period)
+ {chg = 1; per = tp->tinfo.user.period;}
+ if (ofs > tp->tinfo.user.offset)
+ {chg = 1; ofs = tp->tinfo.user.offset;}
+
+ /*
+ ** Check against controller limits.
+ */
+
+ fak = 7;
+ scntl3 = 0;
+ if (ofs != 0) {
+ ncr_getsync(np, per, &fak, &scntl3);
+ if (fak > 7) {
+ chg = 1;
+ ofs = 0;
+ }
+ }
+ if (ofs == 0) {
+ fak = 7;
+ per = 0;
+ scntl3 = 0;
+ }
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+ per, scntl3, ofs, fak, chg);
+ }
+
+ if (INB (HS_PRT) == HS_NEGOTIATE) {
+ OUTB (HS_PRT, HS_BUSY);
+ switch (cp->nego_status) {
+
+ case NS_SYNC:
+ /*
+ ** This was an answer message
+ */
+ if (chg) {
+ /*
+ ** Answer wasn't acceptable.
+ */
+ ncr_setsync (np, cp, 0, 0xe0, 0);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+ } else {
+ /*
+ ** Answer is ok.
+ */
+ ncr_setsync (np,cp,scntl3,(fak<<5)|ofs, per);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+ };
+ return;
+
+ case NS_WIDE:
+ ncr_setwide (np, cp, 0, 0);
+ break;
+ };
+ };
+
+ /*
+ ** It was a request. Set value and
+ ** prepare an answer message
+ */
+
+ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs, per);
+
+ np->msgout[0] = MSG_EXTENDED;
+ np->msgout[1] = 3;
+ np->msgout[2] = MSG_EXT_SDTR;
+ np->msgout[3] = per;
+ np->msgout[4] = ofs;
+
+ cp->nego_status = NS_SYNC;
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("sync msgout: ");
+ (void) ncr_show_msg (np->msgout);
+ printf (".\n");
+ }
+
+ if (!ofs) {
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+ return;
+ }
+ np->msgin [0] = MSG_NOOP;
+
+ break;
+
+ case SIR_NEGO_WIDE:
+ /*
+ ** Wide request message received.
+ */
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("wide msgin: ");
+ (void) ncr_show_msg (np->msgin);
+ printf (".\n");
+ };
+
+ /*
+ ** get requested values.
+ */
+
+ chg = 0;
+ wide = np->msgin[3];
+
+ /*
+ ** check values against driver limits.
+ */
+
+ if (wide > tp->tinfo.user.width)
+ {chg = 1; wide = tp->tinfo.user.width;}
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("wide: wide=%d chg=%d.\n", wide, chg);
+ }
+
+ if (INB (HS_PRT) == HS_NEGOTIATE) {
+ OUTB (HS_PRT, HS_BUSY);
+ switch (cp->nego_status) {
+
+ case NS_WIDE:
+ /*
+ ** This was an answer message
+ */
+ if (chg) {
+ /*
+ ** Answer wasn't acceptable.
+ */
+ ncr_setwide (np, cp, 0, 1);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+ } else {
+ /*
+ ** Answer is ok.
+ */
+ ncr_setwide (np, cp, wide, 1);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+ };
+ return;
+
+ case NS_SYNC:
+ ncr_setsync (np, cp, 0, 0xe0, 0);
+ break;
+ };
+ };
+
+ /*
+ ** It was a request, set value and
+ ** prepare an answer message
+ */
+
+ ncr_setwide (np, cp, wide, 1);
+
+ np->msgout[0] = MSG_EXTENDED;
+ np->msgout[1] = 2;
+ np->msgout[2] = MSG_EXT_WDTR;
+ np->msgout[3] = wide;
+
+ np->msgin [0] = MSG_NOOP;
+
+ cp->nego_status = NS_WIDE;
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->ccb);
+ printf ("wide msgout: ");
+ (void) ncr_show_msg (np->msgout);
+ printf (".\n");
+ }
+ break;
+
+/*--------------------------------------------------------------------
+**
+** Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+ case SIR_REJECT_RECEIVED:
+ /*-----------------------------------------------
+ **
+ ** We received a MSG_MESSAGE_REJECT message.
+ **
+ **-----------------------------------------------
+ */
+
+ PRINT_ADDR(cp->ccb);
+ printf ("MSG_MESSAGE_REJECT received (%x:%x).\n",
+ (unsigned)np->lastmsg, np->msgout[0]);
+ break;
+
+ case SIR_REJECT_SENT:
+ /*-----------------------------------------------
+ **
+ ** We received an unknown message
+ **
+ **-----------------------------------------------
+ */
+
+ PRINT_ADDR(cp->ccb);
+ printf ("MSG_MESSAGE_REJECT sent for ");
+ (void) ncr_show_msg (np->msgin);
+ printf (".\n");
+ break;
+
+/*--------------------------------------------------------------------
+**
+** Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+ case SIR_IGN_RESIDUE:
+ /*-----------------------------------------------
+ **
+ ** We received an IGNORE RESIDUE message,
+ ** which couldn't be handled by the script.
+ **
+ **-----------------------------------------------
+ */
+
+ PRINT_ADDR(cp->ccb);
+ printf ("MSG_IGN_WIDE_RESIDUE received, but not yet implemented.\n");
+ break;
+
+ case SIR_MISSING_SAVE:
+ /*-----------------------------------------------
+ **
+ ** We received an DISCONNECT message,
+ ** but the datapointer wasn't saved before.
+ **
+ **-----------------------------------------------
+ */
+
+ PRINT_ADDR(cp->ccb);
+ printf ("MSG_DISCONNECT received, but datapointer not saved:\n"
+ "\tdata=%x save=%x goal=%x.\n",
+ (unsigned) INL (nc_temp),
+ (unsigned) np->header.savep,
+ (unsigned) np->header.goalp);
+ break;
+
+/*--------------------------------------------------------------------
+**
+** Processing of a "SCSI_STATUS_QUEUE_FULL" status.
+**
+** XXX JGibbs - We should do the same thing for BUSY status.
+**
+** The current command has been rejected,
+** because there are too many in the command queue.
+** We have started too many commands for that target.
+**
+**--------------------------------------------------------------------
+*/
+ case SIR_STALL_QUEUE:
+ cp->xerr_status = XE_OK;
+ cp->host_status = HS_COMPLETE;
+ cp->s_status = SCSI_STATUS_QUEUE_FULL;
+ ncr_freeze_devq(np, cp->ccb->ccb_h.path);
+ ncr_complete(np, cp);
+
+ /* FALL THROUGH */
+
+ case SIR_STALL_RESTART:
+ /*-----------------------------------------------
+ **
+ ** Enable selecting again,
+ ** if NO disconnected jobs.
+ **
+ **-----------------------------------------------
+ */
+ /*
+ ** Look for a disconnected job.
+ */
+ cp = np->link_nccb;
+ while (cp && cp->host_status != HS_DISCONNECT)
+ cp = cp->link_nccb;
+
+ /*
+ ** if there is one, ...
+ */
+ if (cp) {
+ /*
+ ** wait for reselection
+ */
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect));
+ return;
+ };
+
+ /*
+ ** else remove the interrupt.
+ */
+
+ printf ("%s: queue empty.\n", ncr_name (np));
+ WRITESCRIPT(start1[0], SCR_INT ^ IFFALSE (0));
+ break;
+ };
+
+out:
+ OUTB (nc_dcntl, np->rv_dcntl | STD);
+}
+
+/*==========================================================
+**
+**
+** Aquire a control block
+**
+**
+**==========================================================
+*/
+
+static nccb_p ncr_get_nccb
+ (ncb_p np, u_long target, u_long lun)
+{
+ lcb_p lp;
+ int s;
+ nccb_p cp = NULL;
+
+ /* Keep our timeout handler out */
+ s = splsoftclock();
+
+ /*
+ ** Lun structure available ?
+ */
+
+ lp = np->target[target].lp[lun];
+ if (lp) {
+ cp = lp->next_nccb;
+
+ /*
+ ** Look for free CCB
+ */
+
+ while (cp && cp->magic) {
+ cp = cp->next_nccb;
+ }
+ }
+
+ /*
+ ** if nothing available, create one.
+ */
+
+ if (cp == NULL)
+ cp = ncr_alloc_nccb(np, target, lun);
+
+ if (cp != NULL) {
+ if (cp->magic) {
+ printf("%s: Bogus free cp found\n", ncr_name(np));
+ splx(s);
+ return (NULL);
+ }
+ cp->magic = 1;
+ }
+ splx(s);
+ return (cp);
+}
+
+/*==========================================================
+**
+**
+** Release one control block
+**
+**
+**==========================================================
+*/
+
+void ncr_free_nccb (ncb_p np, nccb_p cp)
+{
+ /*
+ ** sanity
+ */
+
+ assert (cp != NULL);
+
+ cp -> host_status = HS_IDLE;
+ cp -> magic = 0;
+}
+
+/*==========================================================
+**
+**
+** Allocation of resources for Targets/Luns/Tags.
+**
+**
+**==========================================================
+*/
+
+static nccb_p
+ncr_alloc_nccb (ncb_p np, u_long target, u_long lun)
+{
+ tcb_p tp;
+ lcb_p lp;
+ nccb_p cp;
+
+ assert (np != NULL);
+
+ if (target>=MAX_TARGET) return(NULL);
+ if (lun >=MAX_LUN ) return(NULL);
+
+ tp=&np->target[target];
+
+ if (!tp->jump_tcb.l_cmd) {
+
+ /*
+ ** initialize it.
+ */
+ tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
+ tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
+
+ tp->getscr[0] =
+ (np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
+ tp->getscr[1] = vtophys (&tp->tinfo.sval);
+ tp->getscr[2] = rman_get_start(np->reg_res) + offsetof (struct ncr_reg, nc_sxfer);
+ tp->getscr[3] =
+ (np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
+ tp->getscr[4] = vtophys (&tp->tinfo.wval);
+ tp->getscr[5] = rman_get_start(np->reg_res) + offsetof (struct ncr_reg, nc_scntl3);
+
+ assert (((offsetof(struct ncr_reg, nc_sxfer) ^
+ (offsetof(struct tcb ,tinfo)
+ + offsetof(struct ncr_target_tinfo, sval))) & 3) == 0);
+ assert (((offsetof(struct ncr_reg, nc_scntl3) ^
+ (offsetof(struct tcb, tinfo)
+ + offsetof(struct ncr_target_tinfo, wval))) &3) == 0);
+
+ tp->call_lun.l_cmd = (SCR_CALL);
+ tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun);
+
+ tp->jump_lcb.l_cmd = (SCR_JUMP);
+ tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
+ np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
+ }
+
+ /*
+ ** Logic unit control block
+ */
+ lp = tp->lp[lun];
+ if (!lp) {
+ /*
+ ** Allocate a lcb
+ */
+ lp = (lcb_p) malloc (sizeof (struct lcb), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (!lp) return(NULL);
+
+ /*
+ ** Initialize it
+ */
+ lp->jump_lcb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (lun)));
+ lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
+
+ lp->call_tag.l_cmd = (SCR_CALL);
+ lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag);
+
+ lp->jump_nccb.l_cmd = (SCR_JUMP);
+ lp->jump_nccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag);
+
+ lp->actlink = 1;
+
+ /*
+ ** Chain into LUN list
+ */
+ tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb);
+ tp->lp[lun] = lp;
+
+ }
+
+ /*
+ ** Allocate a nccb
+ */
+ cp = (nccb_p) malloc (sizeof (struct nccb), M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (!cp)
+ return (NULL);
+
+ if (DEBUG_FLAGS & DEBUG_ALLOC) {
+ printf ("new nccb @%p.\n", cp);
+ }
+
+ /*
+ ** Fill in physical addresses
+ */
+
+ cp->p_nccb = vtophys (cp);
+
+ /*
+ ** Chain into reselect list
+ */
+ cp->jump_nccb.l_cmd = SCR_JUMP;
+ cp->jump_nccb.l_paddr = lp->jump_nccb.l_paddr;
+ lp->jump_nccb.l_paddr = CCB_PHYS (cp, jump_nccb);
+ cp->call_tmp.l_cmd = SCR_CALL;
+ cp->call_tmp.l_paddr = NCB_SCRIPT_PHYS (np, resel_tmp);
+
+ /*
+ ** Chain into wakeup list
+ */
+ cp->link_nccb = np->link_nccb;
+ np->link_nccb = cp;
+
+ /*
+ ** Chain into CCB list
+ */
+ cp->next_nccb = lp->next_nccb;
+ lp->next_nccb = cp;
+
+ return (cp);
+}
+
+/*==========================================================
+**
+**
+** Build Scatter Gather Block
+**
+**
+**==========================================================
+**
+** The transfer area may be scattered among
+** several non adjacent physical pages.
+**
+** We may use MAX_SCATTER blocks.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_scatter
+ (struct dsb* phys, vm_offset_t vaddr, vm_size_t datalen)
+{
+ u_long paddr, pnext;
+
+ u_short segment = 0;
+ u_long segsize, segaddr;
+ u_long size, csize = 0;
+ u_long chunk = MAX_SIZE;
+ int free;
+
+ bzero (&phys->data, sizeof (phys->data));
+ if (!datalen) return (0);
+
+ paddr = vtophys (vaddr);
+
+ /*
+ ** insert extra break points at a distance of chunk.
+ ** We try to reduce the number of interrupts caused
+ ** by unexpected phase changes due to disconnects.
+ ** A typical harddisk may disconnect before ANY block.
+ ** If we wanted to avoid unexpected phase changes at all
+ ** we had to use a break point every 512 bytes.
+ ** Of course the number of scatter/gather blocks is
+ ** limited.
+ */
+
+ free = MAX_SCATTER - 1;
+
+ if (vaddr & PAGE_MASK) free -= datalen / PAGE_SIZE;
+
+ if (free>1)
+ while ((chunk * free >= 2 * datalen) && (chunk>=1024))
+ chunk /= 2;
+
+ if(DEBUG_FLAGS & DEBUG_SCATTER)
+ printf("ncr?:\tscattering virtual=%p size=%d chunk=%d.\n",
+ (void *) vaddr, (unsigned) datalen, (unsigned) chunk);
+
+ /*
+ ** Build data descriptors.
+ */
+ while (datalen && (segment < MAX_SCATTER)) {
+
+ /*
+ ** this segment is empty
+ */
+ segsize = 0;
+ segaddr = paddr;
+ pnext = paddr;
+
+ if (!csize) csize = chunk;
+
+ while ((datalen) && (paddr == pnext) && (csize)) {
+
+ /*
+ ** continue this segment
+ */
+ pnext = (paddr & (~PAGE_MASK)) + PAGE_SIZE;
+
+ /*
+ ** Compute max size
+ */
+
+ size = pnext - paddr; /* page size */
+ if (size > datalen) size = datalen; /* data size */
+ if (size > csize ) size = csize ; /* chunksize */
+
+ segsize += size;
+ vaddr += size;
+ csize -= size;
+ datalen -= size;
+ paddr = vtophys (vaddr);
+ };
+
+ if(DEBUG_FLAGS & DEBUG_SCATTER)
+ printf ("\tseg #%d addr=%x size=%d (rest=%d).\n",
+ segment,
+ (unsigned) segaddr,
+ (unsigned) segsize,
+ (unsigned) datalen);
+
+ phys->data[segment].addr = segaddr;
+ phys->data[segment].size = segsize;
+ segment++;
+ }
+
+ if (datalen) {
+ printf("ncr?: scatter/gather failed (residue=%d).\n",
+ (unsigned) datalen);
+ return (-1);
+ };
+
+ return (segment);
+}
+
+/*==========================================================
+**
+**
+** Test the pci bus snoop logic :-(
+**
+** Has to be called with interrupts disabled.
+**
+**
+**==========================================================
+*/
+
+#ifndef NCR_IOMAPPED
+static int ncr_regtest (struct ncb* np)
+{
+ register volatile u_int32_t data;
+ /*
+ ** ncr registers may NOT be cached.
+ ** write 0xffffffff to a read only register area,
+ ** and try to read it back.
+ */
+ data = 0xffffffff;
+ OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data);
+ data = INL_OFF(offsetof(struct ncr_reg, nc_dstat));
+#if 1
+ if (data == 0xffffffff) {
+#else
+ if ((data & 0xe2f0fffd) != 0x02000080) {
+#endif
+ printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+ (unsigned) data);
+ return (0x10);
+ };
+ return (0);
+}
+#endif
+
+static int ncr_snooptest (struct ncb* np)
+{
+ u_int32_t ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+ int i, err=0;
+#ifndef NCR_IOMAPPED
+ err |= ncr_regtest (np);
+ if (err) return (err);
+#endif
+ /*
+ ** init
+ */
+ pc = NCB_SCRIPTH_PHYS (np, snooptest);
+ host_wr = 1;
+ ncr_wr = 2;
+ /*
+ ** Set memory and register.
+ */
+ ncr_cache = host_wr;
+ OUTL (nc_temp, ncr_wr);
+ /*
+ ** Start script (exchange values)
+ */
+ OUTL (nc_dsp, pc);
+ /*
+ ** Wait 'til done (with timeout)
+ */
+ for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
+ if (INB(nc_istat) & (INTF|SIP|DIP))
+ break;
+ /*
+ ** Save termination position.
+ */
+ pc = INL (nc_dsp);
+ /*
+ ** Read memory and register.
+ */
+ host_rd = ncr_cache;
+ ncr_rd = INL (nc_scratcha);
+ ncr_bk = INL (nc_temp);
+ /*
+ ** Reset ncr chip
+ */
+ OUTB (nc_istat, SRST);
+ DELAY (1000);
+ OUTB (nc_istat, 0 );
+ /*
+ ** check for timeout
+ */
+ if (i>=NCR_SNOOP_TIMEOUT) {
+ printf ("CACHE TEST FAILED: timeout.\n");
+ return (0x20);
+ };
+ /*
+ ** Check termination position.
+ */
+ if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
+ printf ("CACHE TEST FAILED: script execution failed.\n");
+ printf ("start=%08lx, pc=%08lx, end=%08lx\n",
+ (u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc,
+ (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
+ return (0x40);
+ };
+ /*
+ ** Show results.
+ */
+ if (host_wr != ncr_rd) {
+ printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
+ (int) host_wr, (int) ncr_rd);
+ err |= 1;
+ };
+ if (host_rd != ncr_wr) {
+ printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
+ (int) ncr_wr, (int) host_rd);
+ err |= 2;
+ };
+ if (ncr_bk != ncr_wr) {
+ printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
+ (int) ncr_wr, (int) ncr_bk);
+ err |= 4;
+ };
+ return (err);
+}
+
+/*==========================================================
+**
+**
+** Profiling the drivers and targets performance.
+**
+**
+**==========================================================
+*/
+
+/*
+** Compute the difference in milliseconds.
+**/
+
+static int ncr_delta (int *from, int *to)
+{
+ if (!from) return (-1);
+ if (!to) return (-2);
+ return ((to - from) * 1000 / hz);
+}
+
+#define PROFILE cp->phys.header.stamp
+static void ncb_profile (ncb_p np, nccb_p cp)
+{
+ int co, da, st, en, di, se, post,work,disc;
+ u_long diff;
+
+ PROFILE.end = ticks;
+
+ st = ncr_delta (&PROFILE.start,&PROFILE.status);
+ if (st<0) return; /* status not reached */
+
+ da = ncr_delta (&PROFILE.start,&PROFILE.data);
+ if (da<0) return; /* No data transfer phase */
+
+ co = ncr_delta (&PROFILE.start,&PROFILE.command);
+ if (co<0) return; /* command not executed */
+
+ en = ncr_delta (&PROFILE.start,&PROFILE.end),
+ di = ncr_delta (&PROFILE.start,&PROFILE.disconnect),
+ se = ncr_delta (&PROFILE.start,&PROFILE.select);
+ post = en - st;
+
+ /*
+ ** @PROFILE@ Disconnect time invalid if multiple disconnects
+ */
+
+ if (di>=0) disc = se-di; else disc = 0;
+
+ work = (st - co) - disc;
+
+ diff = (np->disc_phys - np->disc_ref) & 0xff;
+ np->disc_ref += diff;
+
+ np->profile.num_trans += 1;
+ if (cp->ccb)
+ np->profile.num_bytes += cp->ccb->csio.dxfer_len;
+ np->profile.num_disc += diff;
+ np->profile.ms_setup += co;
+ np->profile.ms_data += work;
+ np->profile.ms_disc += disc;
+ np->profile.ms_post += post;
+}
+#undef PROFILE
+
+/*==========================================================
+**
+** Determine the ncr's clock frequency.
+** This is essential for the negotiation
+** of the synchronous transfer rate.
+**
+**==========================================================
+**
+** Note: we have to return the correct value.
+** THERE IS NO SAVE DEFAULT VALUE.
+**
+** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+** 53C860 and 53C875 rev. 1 support fast20 transfers but
+** do not have a clock doubler and so are provided with a
+** 80 MHz clock. All other fast20 boards incorporate a doubler
+** and so should be delivered with a 40 MHz clock.
+** The future fast40 chips (895/895) use a 40 Mhz base clock
+** and provide a clock quadrupler (160 Mhz). The code below
+** tries to deal as cleverly as possible with all this stuff.
+**
+**----------------------------------------------------------
+*/
+
+/*
+ * Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+ if (np->multiplier < 2) {
+ OUTB(nc_scntl3, scntl3);
+ return;
+ }
+
+ if (bootverbose >= 2)
+ printf ("%s: enabling clock multiplier\n", ncr_name(np));
+
+ OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
+ if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
+ int i = 20;
+ while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+ DELAY(20);
+ if (!i)
+ printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+ } else /* Wait 20 micro-seconds for doubler */
+ DELAY(20);
+ OUTB(nc_stest3, HSC); /* Halt the scsi clock */
+ OUTB(nc_scntl3, scntl3);
+ OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
+ OUTB(nc_stest3, 0x00); /* Restart scsi clock */
+}
+
+/*
+ * calculate NCR SCSI clock frequency (in KHz)
+ */
+static unsigned
+ncrgetfreq (ncb_p np, int gen)
+{
+ int ms = 0;
+ /*
+ * Measure GEN timer delay in order
+ * to calculate SCSI clock frequency
+ *
+ * This code will never execute too
+ * many loop iterations (if DELAY is
+ * reasonably correct). It could get
+ * too low a delay (too high a freq.)
+ * if the CPU is slow executing the
+ * loop for some reason (an NMI, for
+ * example). For this reason we will
+ * if multiple measurements are to be
+ * performed trust the higher delay
+ * (lower frequency returned).
+ */
+ OUTB (nc_stest1, 0); /* make sure clock doubler is OFF */
+ OUTW (nc_sien , 0); /* mask all scsi interrupts */
+ (void) INW (nc_sist); /* clear pending scsi interrupt */
+ OUTB (nc_dien , 0); /* mask all dma interrupts */
+ (void) INW (nc_sist); /* another one, just to be sure :) */
+ OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */
+ OUTB (nc_stime1, 0); /* disable general purpose timer */
+ OUTB (nc_stime1, gen); /* set to nominal delay of (1<<gen) * 125us */
+ while (!(INW(nc_sist) & GEN) && ms++ < 1000)
+ DELAY(1000); /* count ms */
+ OUTB (nc_stime1, 0); /* disable general purpose timer */
+ OUTB (nc_scntl3, 0);
+ /*
+ * Set prescaler to divide by whatever "0" means.
+ * "0" ought to choose divide by 2, but appears
+ * to set divide by 3.5 mode in my 53c810 ...
+ */
+ OUTB (nc_scntl3, 0);
+
+ if (bootverbose >= 2)
+ printf ("\tDelay (GEN=%d): %u msec\n", gen, ms);
+ /*
+ * adjust for prescaler, and convert into KHz
+ */
+ return ms ? ((1 << gen) * 4440) / ms : 0;
+}
+
+static void ncr_getclock (ncb_p np, u_char multiplier)
+{
+ unsigned char scntl3;
+ unsigned char stest1;
+ scntl3 = INB(nc_scntl3);
+ stest1 = INB(nc_stest1);
+
+ np->multiplier = 1;
+
+ if (multiplier > 1) {
+ np->multiplier = multiplier;
+ np->clock_khz = 40000 * multiplier;
+ } else {
+ if ((scntl3 & 7) == 0) {
+ unsigned f1, f2;
+ /* throw away first result */
+ (void) ncrgetfreq (np, 11);
+ f1 = ncrgetfreq (np, 11);
+ f2 = ncrgetfreq (np, 11);
+
+ if (bootverbose >= 2)
+ printf ("\tNCR clock is %uKHz, %uKHz\n", f1, f2);
+ if (f1 > f2) f1 = f2; /* trust lower result */
+ if (f1 > 45000) {
+ scntl3 = 5; /* >45Mhz: assume 80MHz */
+ } else {
+ scntl3 = 3; /* <45Mhz: assume 40MHz */
+ }
+ }
+ else if ((scntl3 & 7) == 5)
+ np->clock_khz = 80000; /* Probably a 875 rev. 1 ? */
+ }
+}
+
+/*=========================================================================*/
+
+#ifdef NCR_TEKRAM_EEPROM
+
+struct tekram_eeprom_dev {
+ u_char devmode;
+#define TKR_PARCHK 0x01
+#define TKR_TRYSYNC 0x02
+#define TKR_ENDISC 0x04
+#define TKR_STARTUNIT 0x08
+#define TKR_USETAGS 0x10
+#define TKR_TRYWIDE 0x20
+ u_char syncparam; /* max. sync transfer rate (table ?) */
+ u_char filler1;
+ u_char filler2;
+};
+
+
+struct tekram_eeprom {
+ struct tekram_eeprom_dev
+ dev[16];
+ u_char adaptid;
+ u_char adaptmode;
+#define TKR_ADPT_GT2DRV 0x01
+#define TKR_ADPT_GT1GB 0x02
+#define TKR_ADPT_RSTBUS 0x04
+#define TKR_ADPT_ACTNEG 0x08
+#define TKR_ADPT_NOSEEK 0x10
+#define TKR_ADPT_MORLUN 0x20
+ u_char delay; /* unit ? ( table ??? ) */
+ u_char tags; /* use 4 times as many ... */
+ u_char filler[60];
+};
+
+static void
+tekram_write_bit (ncb_p np, int bit)
+{
+ u_char val = 0x10 + ((bit & 1) << 1);
+
+ DELAY(10);
+ OUTB (nc_gpreg, val);
+ DELAY(10);
+ OUTB (nc_gpreg, val | 0x04);
+ DELAY(10);
+ OUTB (nc_gpreg, val);
+ DELAY(10);
+}
+
+static int
+tekram_read_bit (ncb_p np)
+{
+ OUTB (nc_gpreg, 0x10);
+ DELAY(10);
+ OUTB (nc_gpreg, 0x14);
+ DELAY(10);
+ return INB (nc_gpreg) & 1;
+}
+
+static u_short
+read_tekram_eeprom_reg (ncb_p np, int reg)
+{
+ int bit;
+ u_short result = 0;
+ int cmd = 0x80 | reg;
+
+ OUTB (nc_gpreg, 0x10);
+
+ tekram_write_bit (np, 1);
+ for (bit = 7; bit >= 0; bit--)
+ {
+ tekram_write_bit (np, cmd >> bit);
+ }
+
+ for (bit = 0; bit < 16; bit++)
+ {
+ result <<= 1;
+ result |= tekram_read_bit (np);
+ }
+
+ OUTB (nc_gpreg, 0x00);
+ return result;
+}
+
+static int
+read_tekram_eeprom(ncb_p np, struct tekram_eeprom *buffer)
+{
+ u_short *p = (u_short *) buffer;
+ u_short sum = 0;
+ int i;
+
+ if (INB (nc_gpcntl) != 0x09)
+ {
+ return 0;
+ }
+ for (i = 0; i < 64; i++)
+ {
+ u_short val;
+if((i&0x0f) == 0) printf ("%02x:", i*2);
+ val = read_tekram_eeprom_reg (np, i);
+ if (p)
+ *p++ = val;
+ sum += val;
+if((i&0x01) == 0x00) printf (" ");
+ printf ("%02x%02x", val & 0xff, (val >> 8) & 0xff);
+if((i&0x0f) == 0x0f) printf ("\n");
+ }
+printf ("Sum = %04x\n", sum);
+ return sum == 0x1234;
+}
+#endif /* NCR_TEKRAM_EEPROM */
+
+static device_method_t ncr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ncr_probe),
+ DEVMETHOD(device_attach, ncr_attach),
+
+ { 0, 0 }
+};
+
+static driver_t ncr_driver = {
+ "ncr",
+ ncr_methods,
+ sizeof(struct ncb),
+};
+
+static devclass_t ncr_devclass;
+
+DRIVER_MODULE(if_ncr, pci, ncr_driver, ncr_devclass, 0, 0);
+
+/*=========================================================================*/
+#endif /* _KERNEL */
diff --git a/sys/pci/ncrreg.h b/sys/pci/ncrreg.h
new file mode 100644
index 0000000..fcc7212
--- /dev/null
+++ b/sys/pci/ncrreg.h
@@ -0,0 +1,573 @@
+/**************************************************************************
+**
+** $FreeBSD$
+**
+** Device driver for the NCR 53C810 PCI-SCSI-Controller.
+**
+** 386bsd / FreeBSD / NetBSD
+**
+**-------------------------------------------------------------------------
+**
+** Written for 386bsd and FreeBSD by
+** wolf@cologne.de Wolfgang Stanglmeier
+** se@mi.Uni-Koeln.de Stefan Esser
+**
+** Ported to NetBSD by
+** mycroft@gnu.ai.mit.edu
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier. 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. 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 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.
+**
+***************************************************************************
+*/
+
+#ifndef __NCR_REG_H__
+#define __NCR_REG_H__
+
+/*-----------------------------------------------------------------
+**
+** The ncr 53c810 register structure.
+**
+**-----------------------------------------------------------------
+*/
+
+struct ncr_reg {
+/*00*/ u_char nc_scntl0; /* full arb., ena parity, par->ATN */
+
+/*01*/ u_char nc_scntl1; /* no reset */
+ #define ISCON 0x10 /* connected to scsi */
+ #define CRST 0x08 /* force reset */
+
+/*02*/ u_char nc_scntl2; /* no disconnect expected */
+ #define SDU 0x80 /* cmd: disconnect will raise error */
+ #define CHM 0x40 /* sta: chained mode */
+ #define WSS 0x08 /* sta: wide scsi send [W]*/
+ #define WSR 0x01 /* sta: wide scsi received [W]*/
+
+/*03*/ u_char nc_scntl3; /* cnf system clock dependent */
+ #define EWS 0x08 /* cmd: enable wide scsi [W]*/
+
+/*04*/ u_char nc_scid; /* cnf host adapter scsi address */
+ #define RRE 0x40 /* r/w:e enable response to resel. */
+ #define SRE 0x20 /* r/w:e enable response to select */
+
+/*05*/ u_char nc_sxfer; /* ### Sync speed and count */
+
+/*06*/ u_char nc_sdid; /* ### Destination-ID */
+
+/*07*/ u_char nc_gpreg; /* ??? IO-Pins */
+
+/*08*/ u_char nc_sfbr; /* ### First byte in phase */
+
+/*09*/ u_char nc_socl;
+ #define CREQ 0x80 /* r/w: SCSI-REQ */
+ #define CACK 0x40 /* r/w: SCSI-ACK */
+ #define CBSY 0x20 /* r/w: SCSI-BSY */
+ #define CSEL 0x10 /* r/w: SCSI-SEL */
+ #define CATN 0x08 /* r/w: SCSI-ATN */
+ #define CMSG 0x04 /* r/w: SCSI-MSG */
+ #define CC_D 0x02 /* r/w: SCSI-C_D */
+ #define CI_O 0x01 /* r/w: SCSI-I_O */
+
+/*0a*/ u_char nc_ssid;
+
+/*0b*/ u_char nc_sbcl;
+
+/*0c*/ u_char nc_dstat;
+ #define DFE 0x80 /* sta: dma fifo empty */
+ #define MDPE 0x40 /* int: master data parity error */
+ #define BF 0x20 /* int: script: bus fault */
+ #define ABRT 0x10 /* int: script: command aborted */
+ #define SSI 0x08 /* int: script: single step */
+ #define SIR 0x04 /* int: script: interrupt instruct. */
+ #define IID 0x01 /* int: script: illegal instruct. */
+
+/*0d*/ u_char nc_sstat0;
+ #define ILF 0x80 /* sta: data in SIDL register lsb */
+ #define ORF 0x40 /* sta: data in SODR register lsb */
+ #define OLF 0x20 /* sta: data in SODL register lsb */
+ #define AIP 0x10 /* sta: arbitration in progress */
+ #define LOA 0x08 /* sta: arbitration lost */
+ #define WOA 0x04 /* sta: arbitration won */
+ #define IRST 0x02 /* sta: scsi reset signal */
+ #define SDP 0x01 /* sta: scsi parity signal */
+
+/*0e*/ u_char nc_sstat1;
+ #define FF3210 0xf0 /* sta: bytes in the scsi fifo */
+
+/*0f*/ u_char nc_sstat2;
+ #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/
+ #define ORF1 0x40 /* sta: data in SODR register msb[W]*/
+ #define OLF1 0x20 /* sta: data in SODL register msb[W]*/
+ #define LDSC 0x02 /* sta: disconnect & reconnect */
+
+/*10*/ u_int32_t nc_dsa; /* --> Base page */
+
+/*14*/ u_char nc_istat; /* --> Main Command and status */
+ #define CABRT 0x80 /* cmd: abort current operation */
+ #define SRST 0x40 /* mod: reset chip */
+ #define SIGP 0x20 /* r/w: message from host to ncr */
+ #define SEM 0x10 /* r/w: message between host + ncr */
+ #define CON 0x08 /* sta: connected to scsi */
+ #define INTF 0x04 /* sta: int on the fly (reset by wr)*/
+ #define SIP 0x02 /* sta: scsi-interrupt */
+ #define DIP 0x01 /* sta: host/script interrupt */
+
+/*15*/ u_char nc_15_;
+/*16*/ u_char nc_16_;
+/*17*/ u_char nc_17_;
+
+/*18*/ u_char nc_ctest0;
+/*19*/ u_char nc_ctest1;
+
+/*1a*/ u_char nc_ctest2;
+ #define CSIGP 0x40
+
+/*1b*/ u_char nc_ctest3;
+ #define FLF 0x08 /* cmd: flush dma fifo */
+ #define CLF 0x04 /* cmd: clear dma fifo */
+ #define FM 0x02 /* mod: fetch pin mode */
+ #define WRIE 0x01 /* mod: write and invalidate enable */
+
+/*1c*/ u_int32_t nc_temp; /* ### Temporary stack */
+
+/*20*/ u_char nc_dfifo;
+/*21*/ u_char nc_ctest4;
+ #define BDIS 0x80 /* mod: burst disable */
+ #define MPEE 0x08 /* mod: master parity error enable */
+
+/*22*/ u_char nc_ctest5;
+ #define DFS 0x20 /* mod: dma fifo size */
+/*23*/ u_char nc_ctest6;
+
+/*24*/ u_int32_t nc_dbc; /* ### Byte count and command */
+/*28*/ u_int32_t nc_dnad; /* ### Next command register */
+/*2c*/ u_int32_t nc_dsp; /* --> Script Pointer */
+/*30*/ u_int32_t nc_dsps; /* --> Script pointer save/opcode#2 */
+/*34*/ u_int32_t nc_scratcha; /* ??? Temporary register a */
+
+/*38*/ u_char nc_dmode;
+ #define BL_2 0x80 /* mod: burst length shift value +2 */
+ #define BL_1 0x40 /* mod: burst length shift value +1 */
+ #define ERL 0x08 /* mod: enable read line */
+ #define ERMP 0x04 /* mod: enable read multiple */
+ #define BOF 0x02 /* mod: burst op code fetch */
+
+/*39*/ u_char nc_dien;
+/*3a*/ u_char nc_dwt;
+
+/*3b*/ u_char nc_dcntl; /* --> Script execution control */
+ #define CLSE 0x80 /* mod: cache line size enable */
+ #define PFF 0x40 /* cmd: pre-fetch flush */
+ #define PFEN 0x20 /* mod: pre-fetch enable */
+ #define SSM 0x10 /* mod: single step mode */
+ #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */
+ #define STD 0x04 /* cmd: start dma mode */
+ #define IRQD 0x02 /* mod: irq disable */
+ #define NOCOM 0x01 /* cmd: protect sfbr while reselect */
+
+/*3c*/ u_int32_t nc_adder;
+
+/*40*/ u_short nc_sien; /* -->: interrupt enable */
+/*42*/ u_short nc_sist; /* <--: interrupt status */
+ #define STO 0x0400/* sta: timeout (select) */
+ #define GEN 0x0200/* sta: timeout (general) */
+ #define HTH 0x0100/* sta: timeout (handshake) */
+ #define MA 0x80 /* sta: phase mismatch */
+ #define CMP 0x40 /* sta: arbitration complete */
+ #define SEL 0x20 /* sta: selected by another device */
+ #define RSL 0x10 /* sta: reselected by another device*/
+ #define SGE 0x08 /* sta: gross error (over/underflow)*/
+ #define UDC 0x04 /* sta: unexpected disconnect */
+ #define RST 0x02 /* sta: scsi bus reset detected */
+ #define PAR 0x01 /* sta: scsi parity error */
+
+/*44*/ u_char nc_slpar;
+/*45*/ u_char nc_swide;
+/*46*/ u_char nc_macntl;
+/*47*/ u_char nc_gpcntl;
+/*48*/ u_char nc_stime0; /* cmd: timeout for select&handshake*/
+/*49*/ u_char nc_stime1; /* cmd: timeout user defined */
+/*4a*/ u_short nc_respid; /* sta: Reselect-IDs */
+
+/*4c*/ u_char nc_stest0;
+
+/*4d*/ u_char nc_stest1;
+ #define DBLEN 0x08 /* clock doubler running */
+ #define DBLSEL 0x04 /* clock doubler selected */
+
+/*4e*/ u_char nc_stest2;
+ #define ROF 0x40 /* reset scsi offset (after gross error!) */
+ #define EXT 0x02 /* extended filtering */
+
+/*4f*/ u_char nc_stest3;
+ #define TE 0x80 /* c: tolerAnt enable */
+ #define HSC 0x20 /* c: Halt SCSI Clock */
+ #define CSF 0x02 /* c: clear scsi fifo */
+
+/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */
+/*52*/ u_char nc_stest4;
+ #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */
+ #define SMODE_HVD 0x40 /* High Voltage Differential */
+ #define SMODE_SE 0x80 /* Single Ended */
+ #define SMODE_LVD 0xc0 /* Low Voltage Differential */
+ #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */
+
+/*53*/ u_char nc_53_;
+/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */
+/*56*/ u_short nc_56_;
+/*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */
+/*5a*/ u_short nc_5a_;
+/*5c*/ u_char nc_scr0; /* Working register B */
+/*5d*/ u_char nc_scr1; /* */
+/*5e*/ u_char nc_scr2; /* */
+/*5f*/ u_char nc_scr3; /* */
+/*60*/
+};
+
+/*-----------------------------------------------------------
+**
+** Utility macros for the script.
+**
+**-----------------------------------------------------------
+*/
+
+#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
+#define REG(r) REGJ (nc_, r)
+
+#ifndef TARGET_MODE
+#define TARGET_MODE 0
+#endif
+
+typedef u_int32_t ncrcmd;
+
+/*-----------------------------------------------------------
+**
+** SCSI phases
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_DATA_OUT 0x00000000
+#define SCR_DATA_IN 0x01000000
+#define SCR_COMMAND 0x02000000
+#define SCR_STATUS 0x03000000
+#define SCR_ILG_OUT 0x04000000
+#define SCR_ILG_IN 0x05000000
+#define SCR_MSG_OUT 0x06000000
+#define SCR_MSG_IN 0x07000000
+
+/*-----------------------------------------------------------
+**
+** Data transfer via SCSI.
+**
+**-----------------------------------------------------------
+**
+** MOVE_ABS (LEN)
+** <<start address>>
+**
+** MOVE_IND (LEN)
+** <<dnad_offset>>
+**
+** MOVE_TBL
+** <<dnad_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul))
+
+struct scr_tblmove {
+ u_int32_t size;
+ u_int32_t addr;
+};
+
+/*-----------------------------------------------------------
+**
+** Selection
+**
+**-----------------------------------------------------------
+**
+** SEL_ABS | SCR_ID (0..7) [ | REL_JMP]
+** <<alternate_address>>
+**
+** SEL_TBL | << dnad_offset>> [ | REL_JMP]
+** <<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SEL_ABS 0x40000000
+#define SCR_SEL_ABS_ATN 0x41000000
+#define SCR_SEL_TBL 0x42000000
+#define SCR_SEL_TBL_ATN 0x43000000
+
+struct scr_tblsel {
+ u_char sel_0;
+ u_char sel_sxfer;
+ u_char sel_id;
+ u_char sel_scntl3;
+};
+
+#define SCR_JMP_REL 0x04000000
+#define SCR_ID(id) (((u_int32_t)(id)) << 16)
+
+/*-----------------------------------------------------------
+**
+** Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+** WAIT_DISC
+** dummy: <<alternate_address>>
+**
+** WAIT_RESEL
+** <<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_WAIT_DISC 0x48000000
+#define SCR_WAIT_RESEL 0x50000000
+
+/*-----------------------------------------------------------
+**
+** Bit Set / Reset
+**
+**-----------------------------------------------------------
+**
+** SET (flags {|.. })
+**
+** CLR (flags {|.. })
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SET(f) (0x58000000 | (f))
+#define SCR_CLR(f) (0x60000000 | (f))
+
+#define SCR_CARRY 0x00000400
+#define SCR_TRG 0x00000200
+#define SCR_ACK 0x00000040
+#define SCR_ATN 0x00000008
+
+
+/*-----------------------------------------------------------
+**
+** Memory to memory move
+**
+**-----------------------------------------------------------
+**
+** COPY (bytecount)
+** << source_address >>
+** << destination_address >>
+**
+** SCR_COPY sets the NO FLUSH option by default.
+** SCR_COPY_F does not set this option.
+**
+** For chips which do not support this option,
+** ncr_copy_and_bind() will remove this bit.
+**-----------------------------------------------------------
+*/
+
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
+
+
+/*-----------------------------------------------------------
+**
+** Register move and binary operations
+**
+**-----------------------------------------------------------
+**
+** SFBR_REG (reg, op, data) reg = SFBR op data
+** << 0 >>
+**
+** REG_SFBR (reg, op, data) SFBR = reg op data
+** << 0 >>
+**
+** REG_REG (reg, op, data) reg = reg op data
+** << 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_REG_OFS(ofs) ((ofs) << 16ul)
+
+#define SCR_SFBR_REG(reg,op,data) \
+ (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+#define SCR_REG_SFBR(reg,op,data) \
+ (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+#define SCR_REG_REG(reg,op,data) \
+ (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+
+#define SCR_LOAD 0x00000000
+#define SCR_SHL 0x01000000
+#define SCR_OR 0x02000000
+#define SCR_XOR 0x03000000
+#define SCR_AND 0x04000000
+#define SCR_SHR 0x05000000
+#define SCR_ADD 0x06000000
+#define SCR_ADDC 0x07000000
+
+/*-----------------------------------------------------------
+**
+** FROM_REG (reg) reg = SFBR
+** << 0 >>
+**
+** TO_REG (reg) SFBR = reg
+** << 0 >>
+**
+** LOAD_REG (reg, data) reg = <data>
+** << 0 >>
+**
+** LOAD_SFBR(data) SFBR = <data>
+** << 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_FROM_REG(reg) \
+ SCR_REG_SFBR(reg,SCR_OR,0)
+
+#define SCR_TO_REG(reg) \
+ SCR_SFBR_REG(reg,SCR_OR,0)
+
+#define SCR_LOAD_REG(reg,data) \
+ SCR_REG_REG(reg,SCR_LOAD,data)
+
+#define SCR_LOAD_SFBR(data) \
+ (SCR_REG_SFBR (gpreg, SCR_LOAD, data))
+
+/*-----------------------------------------------------------
+**
+** Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+** JUMP [ | IFTRUE/IFFALSE ( ... ) ]
+** <<address>>
+**
+** JUMPR [ | IFTRUE/IFFALSE ( ... ) ]
+** <<distance>>
+**
+** CALL [ | IFTRUE/IFFALSE ( ... ) ]
+** <<address>>
+**
+** CALLR [ | IFTRUE/IFFALSE ( ... ) ]
+** <<distance>>
+**
+** RETURN [ | IFTRUE/IFFALSE ( ... ) ]
+** <<dummy>>
+**
+** INT [ | IFTRUE/IFFALSE ( ... ) ]
+** <<ident>>
+**
+** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ]
+** <<ident>>
+**
+** Conditions:
+** WHEN (phase)
+** IF (phase)
+** CARRY
+** DATA (data, mask)
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_NO_OP 0x80000000
+#define SCR_JUMP 0x80080000
+#define SCR_JUMPR 0x80880000
+#define SCR_CALL 0x88080000
+#define SCR_CALLR 0x88880000
+#define SCR_RETURN 0x90080000
+#define SCR_INT 0x98080000
+#define SCR_INT_FLY 0x98180000
+
+#define IFFALSE(arg) (0x00080000 | (arg))
+#define IFTRUE(arg) (0x00000000 | (arg))
+
+#define WHEN(phase) (0x00030000 | (phase))
+#define IF(phase) (0x00020000 | (phase))
+
+#define DATA(D) (0x00040000 | ((D) & 0xff))
+#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
+
+#define CARRYSET (0x00200000)
+
+/*-----------------------------------------------------------
+**
+** SCSI constants.
+**
+**-----------------------------------------------------------
+*/
+
+/*
+** Messages
+*/
+#define M_X_MODIFY_DP (0x00)
+
+/*
+** Status
+*/
+#define SCSI_STATUS_ILLEGAL (0xff)
+#define SCSI_STATUS_SENSE (0x80)
+
+/*
+** Bits defining chip features.
+** For now only some of them are used, since we explicitely
+** deal with PCI device id and revision id.
+*/
+#define FE_LED0 (1<<0)
+#define FE_WIDE (1<<1)
+#define FE_ULTRA (1<<2)
+#define FE_ULTRA2 (1<<3)
+#define FE_DBLR (1<<4)
+#define FE_QUAD (1<<5)
+#define FE_ERL (1<<6)
+#define FE_CLSE (1<<7)
+#define FE_WRIE (1<<8)
+#define FE_ERMP (1<<9)
+#define FE_BOF (1<<10)
+#define FE_DFS (1<<11)
+#define FE_PFEN (1<<12)
+#define FE_LDSTR (1<<13)
+#define FE_RAM (1<<14)
+#define FE_CLK80 (1<<15)
+#define FE_DIFF (1<<16)
+#define FE_BIOS (1<<17)
+#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
+#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
+#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
+
+#endif /*__NCR_REG_H__*/
diff --git a/sys/pci/ohci_pci.c b/sys/pci/ohci_pci.c
new file mode 100644
index 0000000..3b6f6b9
--- /dev/null
+++ b/sys/pci/ohci_pci.c
@@ -0,0 +1,322 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@carlstedt.se) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * USB Open Host Controller driver.
+ *
+ * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf
+ */
+
+/* The low level controller code for OHCI has been split into
+ * PCI probes and OHCI specific code. This was done to facilitate the
+ * sharing of code between *BSD's
+ */
+
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dev/usb/ohcireg.h>
+#include <dev/usb/ohcivar.h>
+
+#define PCI_OHCI_DEVICEID_ALADDIN_V 0x523710b9
+static const char *ohci_device_aladdin_v = "AcerLabs M5237 (Aladdin-V) USB controller";
+
+#define PCI_OHCI_DEVICEID_AMD756 0x740c1022
+static const char *ohci_device_amd756 = "AMD-756 USB Controller";
+
+#define PCI_OHCI_DEVICEID_AMD766 0x74141022
+static const char *ohci_device_amd766 = "AMD-766 USB Controller";
+
+#define PCI_OHCI_DEVICEID_FIRELINK 0xc8611045
+static const char *ohci_device_firelink = "OPTi 82C861 (FireLink) USB controller";
+
+#define PCI_OHCI_DEVICEID_NEC 0x00351033
+static const char *ohci_device_nec = "NEC uPD 9210 USB controller";
+
+#define PCI_OHCI_DEVICEID_USB0670 0x06701095
+static const char *ohci_device_usb0670 = "CMD Tech 670 (USB0670) USB controller";
+
+#define PCI_OHCI_DEVICEID_USB0673 0x06731095
+static const char *ohci_device_usb0673 = "CMD Tech 673 (USB0673) USB controller";
+
+#define PCI_OHCI_DEVICEID_SIS5571 0x70011039
+static const char *ohci_device_sis5571 = "SiS 5571 USB controller";
+
+#define PCI_OHCI_DEVICEID_KEYLARGO 0x0019106b
+static const char *ohci_device_keylargo = "Apple KeyLargo USB controller";
+
+static const char *ohci_device_generic = "OHCI (generic) USB controller";
+
+#define PCI_OHCI_BASE_REG 0x10
+
+
+static int ohci_pci_attach(device_t self);
+static int ohci_pci_detach(device_t self);
+
+static const char *
+ohci_pci_match(device_t self)
+{
+ u_int32_t device_id = pci_get_devid(self);
+
+ switch (device_id) {
+ case PCI_OHCI_DEVICEID_ALADDIN_V:
+ return (ohci_device_aladdin_v);
+ case PCI_OHCI_DEVICEID_AMD756:
+ return (ohci_device_amd756);
+ case PCI_OHCI_DEVICEID_AMD766:
+ return (ohci_device_amd766);
+ case PCI_OHCI_DEVICEID_USB0670:
+ return (ohci_device_usb0670);
+ case PCI_OHCI_DEVICEID_USB0673:
+ return (ohci_device_usb0673);
+ case PCI_OHCI_DEVICEID_FIRELINK:
+ return (ohci_device_firelink);
+ case PCI_OHCI_DEVICEID_NEC:
+ return (ohci_device_nec);
+ case PCI_OHCI_DEVICEID_SIS5571:
+ return (ohci_device_sis5571);
+ case PCI_OHCI_DEVICEID_KEYLARGO:
+ return (ohci_device_keylargo);
+ default:
+ if (pci_get_class(self) == PCIC_SERIALBUS
+ && pci_get_subclass(self) == PCIS_SERIALBUS_USB
+ && pci_get_progif(self) == PCI_INTERFACE_OHCI) {
+ return (ohci_device_generic);
+ }
+ }
+
+ return NULL; /* dunno */
+}
+
+static int
+ohci_pci_probe(device_t self)
+{
+ const char *desc = ohci_pci_match(self);
+
+ if (desc) {
+ device_set_desc(self, desc);
+ return 0;
+ } else {
+ return ENXIO;
+ }
+}
+
+static int
+ohci_pci_attach(device_t self)
+{
+ ohci_softc_t *sc = device_get_softc(self);
+ int err;
+ int rid;
+
+ /* XXX where does it say so in the spec? */
+ sc->sc_bus.usbrev = USBREV_1_0;
+
+ rid = PCI_CBMEM;
+ sc->io_res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->io_res) {
+ device_printf(self, "Could not map memory\n");
+ return ENXIO;
+ }
+ sc->iot = rman_get_bustag(sc->io_res);
+ sc->ioh = rman_get_bushandle(sc->io_res);
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(self, "Could not allocate irq\n");
+ ohci_pci_detach(self);
+ return ENXIO;
+ }
+ sc->sc_bus.bdev = device_add_child(self, "usb", -1);
+ if (!sc->sc_bus.bdev) {
+ device_printf(self, "Could not add USB device\n");
+ ohci_pci_detach(self);
+ return ENOMEM;
+ }
+ device_set_ivars(sc->sc_bus.bdev, sc);
+
+ switch (pci_get_devid(self)) {
+ case PCI_OHCI_DEVICEID_ALADDIN_V:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_aladdin_v);
+ sprintf(sc->sc_vendor, "AcerLabs");
+ break;
+ case PCI_OHCI_DEVICEID_AMD756:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_amd756);
+ sprintf(sc->sc_vendor, "AMD");
+ break;
+ case PCI_OHCI_DEVICEID_AMD766:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_amd766);
+ sprintf(sc->sc_vendor, "AMD");
+ break;
+ case PCI_OHCI_DEVICEID_FIRELINK:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_firelink);
+ sprintf(sc->sc_vendor, "OPTi");
+ break;
+ case PCI_OHCI_DEVICEID_NEC:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_nec);
+ sprintf(sc->sc_vendor, "NEC");
+ break;
+ case PCI_OHCI_DEVICEID_USB0670:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_usb0670);
+ sprintf(sc->sc_vendor, "CMDTECH");
+ break;
+ case PCI_OHCI_DEVICEID_USB0673:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_usb0673);
+ sprintf(sc->sc_vendor, "CMDTECH");
+ break;
+ case PCI_OHCI_DEVICEID_SIS5571:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_sis5571);
+ sprintf(sc->sc_vendor, "SiS");
+ break;
+ case PCI_OHCI_DEVICEID_KEYLARGO:
+ device_set_desc(sc->sc_bus.bdev, ohci_device_keylargo);
+ sprintf(sc->sc_vendor, "Apple");
+ break;
+ default:
+ if (bootverbose)
+ device_printf(self, "(New OHCI DeviceId=0x%08x)\n",
+ pci_get_devid(self));
+ device_set_desc(sc->sc_bus.bdev, ohci_device_generic);
+ sprintf(sc->sc_vendor, "(unknown)");
+ }
+
+ err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
+ (driver_intr_t *) ohci_intr, sc, &sc->ih);
+ if (err) {
+ device_printf(self, "Could not setup irq, %d\n", err);
+ sc->ih = NULL;
+ ohci_pci_detach(self);
+ return ENXIO;
+ }
+ err = ohci_init(sc);
+ if (!err)
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+
+ if (err) {
+ device_printf(self, "USB init failed\n");
+ ohci_pci_detach(self);
+ return EIO;
+ }
+ return 0;
+}
+
+static int
+ohci_pci_detach(device_t self)
+{
+ ohci_softc_t *sc = device_get_softc(self);
+
+ /*
+ * XXX this code is not yet fit to be used as detach for the OHCI
+ * controller
+ */
+
+ /*
+ * disable interrupts that might have been switched on in ohci_init
+ */
+ if (sc->iot && sc->ioh)
+ bus_space_write_4(sc->iot, sc->ioh,
+ OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+
+ if (sc->irq_res && sc->ih) {
+ int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
+
+ if (err)
+ /* XXX or should we panic? */
+ device_printf(self, "Could not tear down irq, %d\n",
+ err);
+ sc->ih = NULL;
+ }
+ if (sc->sc_bus.bdev) {
+ device_delete_child(self, sc->sc_bus.bdev);
+ sc->sc_bus.bdev = NULL;
+ }
+ if (sc->irq_res) {
+ bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
+ sc->irq_res = NULL;
+ }
+ if (sc->io_res) {
+ bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, sc->io_res);
+ sc->io_res = NULL;
+ sc->iot = 0;
+ sc->ioh = 0;
+ }
+ return 0;
+}
+
+static device_method_t ohci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ohci_pci_probe),
+ DEVMETHOD(device_attach, ohci_pci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0}
+};
+
+static driver_t ohci_driver = {
+ "ohci",
+ ohci_methods,
+ sizeof(ohci_softc_t),
+};
+
+static devclass_t ohci_devclass;
+
+DRIVER_MODULE(ohci, pci, ohci_driver, ohci_devclass, 0, 0);
diff --git a/sys/pci/simos.c b/sys/pci/simos.c
new file mode 100644
index 0000000..7944d5e
--- /dev/null
+++ b/sys/pci/simos.c
@@ -0,0 +1,350 @@
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <machine/clock.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <sys/kernel.h>
+
+#include <pci/simos.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#ifndef COMPAT_OLDPCI
+#error "The simos device requires the old pci compatibility shims"
+#endif
+
+#include <machine/alpha_cpu.h>
+
+struct simos_softc {
+ int sc_unit;
+ SimOS_SCSI* sc_regs;
+
+ /*
+ * SimOS only supports one pending command.
+ */
+ struct cam_sim *sc_sim;
+ struct cam_path *sc_path;
+ struct ccb_scsiio *sc_pending;
+};
+
+struct simos_softc* simosp[10];
+
+static u_long simos_unit;
+
+static const char *simos_probe(pcici_t tag, pcidi_t type);
+static void simos_attach(pcici_t config_d, int unit);
+static void simos_action(struct cam_sim *sim, union ccb *ccb);
+static void simos_poll(struct cam_sim *sim);
+
+struct pci_device simos_driver = {
+ "simos",
+ simos_probe,
+ simos_attach,
+ &simos_unit,
+ NULL
+};
+COMPAT_PCI_DRIVER (simos, simos_driver);
+
+static const char *
+simos_probe(pcici_t tag, pcidi_t type)
+{
+ switch (type) {
+ case 0x1291|(0x1291<<16):
+ return "SimOS SCSI";
+ default:
+ return NULL;
+ }
+
+}
+
+static void
+simos_attach(pcici_t config_id, int unit)
+{
+ struct simos_softc* sc;
+ struct cam_devq *devq;
+
+ sc = malloc(sizeof(struct simos_softc), M_DEVBUF, M_WAITOK | M_ZERO);
+ simosp[unit] = sc;
+
+ sc->sc_unit = unit;
+ sc->sc_regs = (SimOS_SCSI*) SIMOS_SCSI_ADDR;
+ sc->sc_pending = 0;
+
+ devq = cam_simq_alloc(/*maxopenings*/1);
+ if (devq == NULL)
+ return;
+
+ sc->sc_sim = cam_sim_alloc(simos_action, simos_poll, "simos", sc, unit,
+ /*untagged*/1, /*tagged*/0, devq);
+ if (sc->sc_sim == NULL) {
+ cam_simq_free(devq);
+ return;
+ }
+
+ if (xpt_bus_register(sc->sc_sim, /*bus*/0) != CAM_SUCCESS) {
+ cam_sim_free(sc->sc_sim, /*free_devq*/TRUE);
+ return;
+ }
+
+ if (xpt_create_path(&sc->sc_path, /*periph*/NULL,
+ cam_sim_path(sc->sc_sim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_bus_deregister(cam_sim_path(sc->sc_sim));
+ cam_sim_free(sc->sc_sim, /*free_devq*/TRUE);
+ return;
+ }
+
+ alpha_register_pci_scsi(config_id->bus, config_id->slot, sc->sc_sim);
+
+ return;
+}
+
+static void
+simos_start(struct simos_softc* sc, struct ccb_scsiio *csio)
+{
+ struct scsi_generic *cmd;
+ int cmdlen;
+ caddr_t data;
+ int datalen;
+ int s;
+ u_int8_t* p;
+ int i, count, target;
+ vm_offset_t va;
+ vm_size_t size;
+
+ cmd = (struct scsi_generic *) &csio->cdb_io.cdb_bytes;
+ cmdlen = csio->cdb_len;
+ data = csio->data_ptr;
+ datalen = csio->dxfer_len;
+
+ /*
+ * Simos doesn't understand some commands
+ */
+ if (cmd->opcode == START_STOP || cmd->opcode == PREVENT_ALLOW
+ || cmd->opcode == SYNCHRONIZE_CACHE) {
+ csio->ccb_h.status = CAM_REQ_CMP;
+ xpt_done((union ccb *) csio);
+ return;
+ }
+
+ if (sc->sc_pending) {
+ /*
+ * Don't think this can happen.
+ */
+ printf("simos_start: can't start command while one is pending\n");
+ csio->ccb_h.status = CAM_BUSY;
+ xpt_done((union ccb *) csio);
+ return;
+ }
+
+ s = splcam();
+
+ csio->ccb_h.status |= CAM_SIM_QUEUED;
+ sc->sc_pending = csio;
+
+ target = csio->ccb_h.target_id;
+
+ /*
+ * Copy the command into SimOS' buffer
+ */
+ p = (u_int8_t*) cmd;
+ count = cmdlen;
+ for (i = 0; i < count; i++)
+ sc->sc_regs->cmd[i] = *p++;
+ sc->sc_regs->length = count;
+ sc->sc_regs->target = target;
+ sc->sc_regs->lun = csio->ccb_h.target_lun;
+
+ /*
+ * Setup the segment descriptors.
+ */
+ va = (vm_offset_t) data;
+ size = datalen;
+ i = 0;
+ while (size > 0) {
+ vm_size_t len = PAGE_SIZE - (va & PAGE_MASK);
+ if (len > size)
+ len = size;
+ sc->sc_regs->sgMap[i].pAddr = vtophys(va);
+ sc->sc_regs->sgMap[i].len = len;
+ size -= len;
+ va += len;
+ i++;
+ }
+ sc->sc_regs->sgLen = i;
+
+ /*
+ * Start the i/o.
+ */
+ alpha_wmb();
+ sc->sc_regs->startIO = 1;
+ alpha_wmb();
+
+ splx(s);
+}
+
+static void
+simos_done(struct simos_softc* sc)
+{
+ struct ccb_scsiio* csio = sc->sc_pending;
+ int s, done;
+
+ /*
+ * Spurious interrupt caused by my bogus interrupt broadcasting.
+ */
+ if (!csio)
+ return;
+
+ sc->sc_pending = 0;
+
+ done = sc->sc_regs->done[csio->ccb_h.target_id];
+ if (!done)
+ return;
+
+ s = splcam();
+
+ if (done >> 16)
+ /* Error detected */
+ csio->ccb_h.status = CAM_CMD_TIMEOUT;
+ else
+ csio->ccb_h.status = CAM_REQ_CMP;
+
+ /*
+ * Ack the interrupt to clear it.
+ */
+ sc->sc_regs->done[csio->ccb_h.target_id] = 1;
+ alpha_wmb();
+
+ xpt_done((union ccb *) csio);
+
+ splx(s);
+}
+
+static void
+simos_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct simos_softc* sc = (struct simos_softc *)sim->softc;
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_SCSI_IO:
+ {
+ struct ccb_scsiio *csio;
+
+ csio = &ccb->csio;
+ simos_start(sc, csio);
+ break;
+ }
+
+ case XPT_CALC_GEOMETRY:
+ {
+ struct ccb_calc_geometry *ccg;
+ u_int32_t size_mb;
+ u_int32_t secs_per_cylinder;
+
+ ccg = &ccb->ccg;
+ size_mb = ccg->volume_size
+ / ((1024L * 1024L) / ccg->block_size);
+
+ ccg->heads = 64;
+ ccg->secs_per_track = 32;
+
+ secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+ ccg->cylinders = ccg->volume_size / secs_per_cylinder;
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ case XPT_RESET_BUS:
+ {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1; /* XXX??? */
+ cpi->max_target = 2;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 7;
+ cpi->bus_id = sim->bus_id;
+ cpi->base_transfer_speed = 3300;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "SimOS", HBA_IDLEN);
+ strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
+ cpi->unit_number = sim->unit_number;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
+static void
+simos_poll(struct cam_sim *sim)
+{
+ simos_done(cam_sim_softc(sim));
+}
+
+void
+simos_intr(int unit)
+{
+ /* XXX bogus */
+ struct simos_softc* sc = simosp[unit];
+
+ simos_done(sc);
+}
diff --git a/sys/pci/simos.h b/sys/pci/simos.h
new file mode 100644
index 0000000..e703074
--- /dev/null
+++ b/sys/pci/simos.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (C) 1998 by the Board of Trustees
+ * of Leland Stanford Junior University.
+ * Copyright (C) 1998 Digital Equipment Corporation
+ *
+ * This file is part of the SimOS distribution.
+ * See LICENSE file for terms of the license.
+ *
+ */
+
+
+
+
+#ifndef _SIMOS_SCSI_H
+#define _SIMOS_SCSI_H
+
+#define SIMOS_SCSI_ADDR 0xfffffcc500000000
+#define SIMOS_SCSI_ADDR_32 0xffffffffa5000000
+#define SIMOS_SCSI_MAXDMA_LEN 128
+#define SIMOS_SCSI_MAXTARG 16
+#define SIMOS_SCSI_MAXLUN 16
+
+#define SIMOS_SCSI_REGS ((struct SimOS_SCSI *)SIMOS_SCSI_ADDR)
+#define SIMOS_SCSI_REGS_32 ((struct SimOS_SCSI *)SIMOS_SCSI_ADDR_32)
+
+typedef unsigned long SCSIReg;
+
+
+typedef struct SimOS_SCSI {
+ SCSIReg startIO; /* write-only */
+ SCSIReg done[SIMOS_SCSI_MAXTARG]; /* read-write (write=ack) */
+
+ SCSIReg target; /* data fields */
+ SCSIReg lun;
+ SCSIReg cmd[12];
+ SCSIReg length;
+ SCSIReg sgLen;
+ struct {
+ SCSIReg pAddr;
+ SCSIReg len;
+ } sgMap[SIMOS_SCSI_MAXDMA_LEN];
+
+
+} SimOS_SCSI;
+
+#endif
diff --git a/sys/pci/ti_fw.h b/sys/pci/ti_fw.h
new file mode 100644
index 0000000..89f5c9f
--- /dev/null
+++ b/sys/pci/ti_fw.h
@@ -0,0 +1,4593 @@
+/*
+ * Firmware for Alteon Tigon 1 chip.
+ * Generated by genfw.c
+ *
+ * $FreeBSD$
+ */
+static int tigonFwReleaseMajor = 0xc;
+static int tigonFwReleaseMinor = 0x4;
+static int tigonFwReleaseFix = 0xb;
+static u_int32_t tigonFwStartAddr = 0x00004000;
+static u_int32_t tigonFwTextAddr = 0x00004000;
+static int tigonFwTextLen = 0x11140;
+static u_int32_t tigonFwRodataAddr = 0x00015140;
+static int tigonFwRodataLen = 0xac0;
+static u_int32_t tigonFwDataAddr = 0x00015c20;
+static int tigonFwDataLen = 0x170;
+static u_int32_t tigonFwSbssAddr = 0x00015d90;
+static int tigonFwSbssLen = 0x38;
+static u_int32_t tigonFwBssAddr = 0x00015dd0;
+static int tigonFwBssLen = 0x2080;
+static u_int32_t tigonFwText[] = {
+0x10000003,
+0x0, 0xd, 0xd, 0x3c1d0001,
+0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
+0xc00100c, 0x0, 0xd, 0x27bdffd8,
+0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
+0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
+0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
+0x0, 0x3c040001, 0x248451a4, 0x24050001,
+0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
+0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
+0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
+0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
+0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
+0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
+0x370821, 0xa02083b0, 0x3c010001, 0x370821,
+0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
+0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
+0x418c0, 0x24840001, 0x771021, 0xac40727c,
+0x771021, 0xac407280, 0x2e31021, 0xa445727c,
+0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
+0x3405c000, 0x418c0, 0x24840001, 0x771021,
+0xac40737c, 0x771021, 0xac407380, 0x2e31021,
+0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
+0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
+0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f420218, 0x30420002, 0x10400009, 0x0,
+0x8f420220, 0x3c030002, 0x34630004, 0x431025,
+0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
+0x8f420220, 0x3c030002, 0x34630006, 0x431025,
+0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
+0x8f420218, 0x30420010, 0x1040000a, 0x0,
+0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
+0x3c03000a, 0x34630004, 0x431025, 0x800108a,
+0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
+0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
+0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
+0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
+0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
+0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
+0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
+0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
+0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
+0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
+0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
+0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
+0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
+0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
+0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
+0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
+0x26e40030, 0xc002488, 0x24050400, 0x27440080,
+0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
+0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
+0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
+0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
+0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
+0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
+0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
+0x641821, 0x90635c20, 0x2e41021, 0x24840001,
+0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
+0x8f820040, 0x2e41821, 0x24840001, 0x21702,
+0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
+0x96e2046a, 0x30420003, 0x14400009, 0x0,
+0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
+0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
+0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
+0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
+0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
+0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
+0x0, 0x3c020001, 0x2442e168, 0x800111d,
+0x21100, 0x3c020001, 0x2442d35c, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0x3c010001,
+0xac221238, 0x3c020001, 0x2442f680, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0x3c010001,
+0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
+0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
+0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
+0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
+0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
+0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
+0x50400001, 0x27683000, 0x8f820128, 0x11020004,
+0x0, 0x8f820124, 0x15020007, 0x1021,
+0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
+0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xace40000,
+0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
+0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
+0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
+0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x800118a, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
+0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f000, 0x8001223, 0x0,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80011f1, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8001207, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+0x24020001, 0xac820004, 0x14c0001b, 0x0,
+0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
+0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
+0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
+0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
+0x8ee20160, 0x3021, 0x3821, 0xafa00010,
+0xc002403, 0xafa00014, 0x8001238, 0x0,
+0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
+0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
+0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
+0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
+0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
+0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
+0x2442a390, 0x451024, 0x21082, 0xaee304c8,
+0x3c030800, 0x431025, 0x3c010001, 0xac221220,
+0x3c020001, 0x2442add4, 0x451024, 0x21082,
+0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
+0x3821, 0x24050011, 0xafa00010, 0xc002403,
+0xafa00014, 0x8001268, 0x0, 0x3c020001,
+0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
+0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
+0x30420010, 0x14400009, 0x0, 0x96e2047a,
+0x30420010, 0x10400112, 0x0, 0x96e2046a,
+0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
+0x30420010, 0x14400102, 0x3c020700, 0x34423000,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x80012d4,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+0x800136d, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x800133b, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001351, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
+0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
+0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
+0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
+0xc004500, 0x0, 0xc002318, 0x0,
+0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
+0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
+0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
+0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
+0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
+0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
+0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
+0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
+0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
+0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
+0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x800140c,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8001422,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+0x80014a5, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8001473, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001489, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
+0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
+0x0, 0x8f820040, 0x30420001, 0x14400008,
+0x0, 0x8f430104, 0x24020001, 0x10620004,
+0x0, 0x8f420264, 0x10400006, 0x0,
+0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
+0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
+0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
+0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
+0xaee2726c, 0xc004064, 0x0, 0xc004440,
+0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
+0x0, 0x0, 0x0, 0x2402002c,
+0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
+0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
+0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
+0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
+0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
+0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
+0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
+0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
+0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
+0x431025, 0xaee20000, 0x8f420218, 0x30420100,
+0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
+0x104000c2, 0x0, 0x3c030001, 0x771821,
+0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
+0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
+0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
+0x431024, 0x1040000d, 0x0, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
+0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
+0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
+0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
+0x0, 0x3c030001, 0x771821, 0x8c6383d4,
+0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
+0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
+0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
+0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
+0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
+0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
+0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
+0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
+0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+0x0, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x800158a, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
+0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
+0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
+0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
+0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
+0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
+0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
+0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
+0x34a50900, 0x80015cc, 0x0, 0x8f820104,
+0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
+0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
+0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
+0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
+0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
+0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x8001621, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8001637, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+0x24020001, 0xac820004, 0x5600000b, 0x24100001,
+0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
+0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
+0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
+0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
+0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
+0x1040006d, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
+0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8001697, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x80016ad, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
+0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
+0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
+0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
+0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
+0x0, 0xaee04e24, 0x8f820040, 0x30420001,
+0x14400008, 0x0, 0x8f430104, 0x24020001,
+0x10620004, 0x0, 0x8f420264, 0x10400006,
+0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
+0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
+0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
+0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
+0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
+0x104002aa, 0x0, 0x3c020001, 0x571021,
+0x904283e0, 0x144002a5, 0x0, 0x8f420080,
+0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
+0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
+0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
+0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
+0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
+0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
+0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
+0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
+0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
+0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
+0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
+0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
+0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8001775,
+0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
+0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
+0xac620018, 0xac60001c, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x800175f, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001775, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
+0x571021, 0x904283b0, 0x1040010b, 0x0,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
+0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x8021, 0x24420001,
+0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
+0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x80017e0,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
+0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+0x0, 0x316300ff, 0x24020001, 0x14620077,
+0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+0x5821, 0x240d0008, 0x240c0011, 0x24080012,
+0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10470007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800184c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800185f,
+0x0, 0x8ee24e30, 0x24420001, 0x50470003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+0x0, 0x316300ff, 0x24020001, 0x14620003,
+0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
+0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
+0x800197c, 0x0, 0x3c040001, 0x248452bc,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
+0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
+0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020007, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80018e1, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
+0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f000, 0x800197c, 0x0, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x800195e,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x8001948,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x800195e,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
+0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
+0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
+0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
+0xc002403, 0x0, 0x8ee201ac, 0x8021,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
+0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
+0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
+0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
+0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
+0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
+0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
+0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
+0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
+0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8001a02, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
+0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8001a6e, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
+0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+0x24020001, 0x10620022, 0x0, 0x3c040001,
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
+0x8001aad, 0x0, 0x3c040001, 0x248452b0,
+0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+0xc002403, 0x34a5f010, 0x8001aad, 0x0,
+0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
+0x8ee204d4, 0x30420001, 0x10400055, 0x0,
+0x8f420218, 0x30420080, 0x10400029, 0x0,
+0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
+0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
+0x2407ffff, 0x2021, 0x461024, 0x1444000d,
+0x671824, 0x1465000b, 0x0, 0x8ee27b80,
+0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
+0x461024, 0x14440003, 0x671824, 0x1065000b,
+0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
+0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
+0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
+0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
+0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
+0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
+0x24060000, 0x2407ffff, 0x2021, 0x461024,
+0x1444000d, 0x671824, 0x1465000b, 0x0,
+0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
+0x2021, 0x461024, 0x14440003, 0x671824,
+0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
+0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
+0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
+0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
+0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
+0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
+0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
+0x0, 0x8f420218, 0x30420080, 0x10400009,
+0x0, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
+0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
+0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
+0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
+0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
+0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
+0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
+0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
+0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
+0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
+0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
+0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
+0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
+0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
+0x0, 0x32c20002, 0x1440000c, 0x3c050003,
+0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
+0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
+0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
+0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
+0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
+0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
+0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
+0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
+0x0, 0x80022ed, 0xaf960064, 0x93a20020,
+0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
+0x3c010001, 0x220821, 0x8c225418, 0x400008,
+0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
+0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
+0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
+0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
+0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
+0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
+0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
+0x21200, 0x22502, 0x24020001, 0x10820005,
+0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
+0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
+0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
+0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
+0x8f840054, 0x41442, 0x41c82, 0x431021,
+0x41cc2, 0x431023, 0x41d02, 0x431021,
+0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
+0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
+0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
+0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
+0x1040000a, 0x971021, 0x97430212, 0xa443727e,
+0x8f430214, 0x971021, 0xac437280, 0x2e41821,
+0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
+0x97420212, 0x14620006, 0x2e41021, 0x971021,
+0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
+0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
+0x2021, 0x410c0, 0x2e21021, 0x9442737c,
+0x30424000, 0x54400005, 0x803021, 0x24840001,
+0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
+0x618c0, 0x610c0, 0x571821, 0x8c63737c,
+0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
+0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
+0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
+0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+0x771021, 0x2e31821, 0xac447380, 0x34028000,
+0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
+0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
+0x510c0, 0x9443737e, 0x97420212, 0x14620006,
+0x510c0, 0x971021, 0x8c437380, 0x8f420214,
+0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
+0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
+0x1040fff0, 0x971021, 0x520c0, 0x971021,
+0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
+0x971021, 0x8c437380, 0x8f420214, 0x10620053,
+0x3c020800, 0x2021, 0x410c0, 0x2e21021,
+0x9442737c, 0x30424000, 0x54400005, 0x803021,
+0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
+0x4c10023, 0x618c0, 0x910c0, 0x571821,
+0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
+0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
+0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
+0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
+0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
+0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
+0x370821, 0xac2283b4, 0x3c030001, 0x771821,
+0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
+0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+0x771021, 0x2e31821, 0xac447380, 0x34028000,
+0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
+0x2021, 0x428c0, 0x2e51021, 0x9442777c,
+0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
+0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
+0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
+0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
+0x621825, 0xaf830228, 0x3c020800, 0x34421000,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8001cf5, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8001d61, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
+0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+0x10620022, 0x0, 0x3c040001, 0x24845390,
+0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
+0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
+0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
+0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
+0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
+0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
+0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
+0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
+0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
+0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
+0x1221004, 0x21027, 0x621824, 0xaf830228,
+0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
+0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
+0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
+0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
+0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
+0xb71021, 0x9443727e, 0x97420212, 0x14620019,
+0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
+0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
+0x720c0, 0x971021, 0x9443737e, 0xb71021,
+0xa443727e, 0x971021, 0x8c437380, 0xb71021,
+0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
+0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
+0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
+0x720c0, 0x2e41021, 0x9442737c, 0x4021,
+0x30428000, 0x14400025, 0xe02821, 0x605021,
+0x340bc000, 0x971021, 0x9443737e, 0x97420212,
+0x54620015, 0xe02821, 0x971021, 0x8c437380,
+0x8f420214, 0x54620010, 0xe02821, 0x11000006,
+0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
+0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
+0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
+0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
+0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
+0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
+0x14400025, 0x2021, 0x720c0, 0x971021,
+0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
+0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
+0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
+0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
+0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
+0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
+0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
+0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
+0x3c020800, 0x2021, 0x428c0, 0xb71021,
+0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
+0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
+0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
+0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
+0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
+0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
+0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
+0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
+0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
+0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
+0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
+0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
+0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
+0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8001ee8,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
+0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+0x0, 0x316300ff, 0x24020001, 0x54620078,
+0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
+0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10480007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8001f54,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
+0x0, 0x8ee24e30, 0x24420001, 0x50480003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+0x0, 0x316300ff, 0x24020001, 0x10620022,
+0x0, 0x3c040001, 0x24845390, 0xafa00010,
+0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+0xc002403, 0x34a5f011, 0x8001f93, 0x0,
+0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
+0x8001f93, 0x0, 0x3c040001, 0x248453a8,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
+0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
+0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
+0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
+0x21200, 0x21d02, 0x24020001, 0x10620005,
+0x24020002, 0x1062000d, 0x0, 0x8001fb7,
+0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
+0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
+0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
+0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
+0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
+0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
+0x22502, 0x24020001, 0x10820005, 0x24020002,
+0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
+0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
+0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
+0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
+0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
+0x21d02, 0x24020001, 0x10620005, 0x24020002,
+0x1062000e, 0x0, 0x8002011, 0xafa00010,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
+0x571021, 0x904283b2, 0x3c010001, 0x370821,
+0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
+0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
+0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
+0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
+0x27840208, 0x27450200, 0xc00249a, 0x24060008,
+0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
+0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
+0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
+0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
+0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
+0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
+0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
+0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
+0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
+0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+0x27450200, 0x24060008, 0xaee20068, 0x24020006,
+0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
+0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
+0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
+0x30420008, 0x10400004, 0x0, 0xaee30108,
+0x8002061, 0x2021, 0xaee40108, 0x2021,
+0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
+0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
+0x0, 0x8f820040, 0x2e41821, 0x24840001,
+0x21702, 0x24420030, 0xa062009c, 0x2e41021,
+0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
+0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
+0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
+0x24660020, 0xc2102b, 0x50400001, 0x27662800,
+0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
+0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
+0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
+0xac680018, 0xac60001c, 0xac640000, 0xac650004,
+0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
+0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
+0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
+0x0, 0x80022e8, 0x0, 0x3c020900,
+0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
+0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002119, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x800212c, 0x0, 0x8ee24e30, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x3821, 0x24420001, 0xaee201a4, 0x8002198,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002185, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8002198, 0x0, 0x8ee24e30, 0x24420001,
+0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+0x10620022, 0x0, 0x3c040001, 0x24845390,
+0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
+0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
+0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
+0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
+0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
+0x8f820220, 0x30420008, 0x14400002, 0x24020001,
+0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
+0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
+0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
+0x3c030700, 0x34631000, 0x431025, 0xafa20018,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
+0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
+0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
+0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8002247, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x800225d, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
+0x0, 0x8f830120, 0x27623800, 0x24660020,
+0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+0x0, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
+0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
+0xac620008, 0x24020008, 0xa462000e, 0x24020011,
+0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x80022ae, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020012,
+0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
+0x0, 0x3c040001, 0x248453fc, 0xafa00010,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
+0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
+0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
+0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
+0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
+0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
+0x8f820064, 0x14400005, 0x0, 0x8f43022c,
+0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
+0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
+0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
+0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
+0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
+0x24840001, 0x3021, 0x1071026, 0x30420001,
+0x10400002, 0x81842, 0x6a1826, 0x604021,
+0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
+0x25290001, 0x125102b, 0x1440fff0, 0x0,
+0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
+0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
+0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
+0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
+0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
+0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
+0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
+0x10400004, 0x0, 0x8f82011c, 0x34420004,
+0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
+0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
+0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
+0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
+0x3c020400, 0x10620029, 0x43102b, 0x14400008,
+0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
+0x10620011, 0x0, 0x8002374, 0x0,
+0x10620008, 0x3c024000, 0x1462001c, 0x0,
+0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
+0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
+0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
+0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
+0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
+0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
+0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
+0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
+0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
+0x8021, 0x43102b, 0x14400008, 0x3c042000,
+0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
+0x0, 0x80023e0, 0x0, 0x10640003,
+0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
+0x441024, 0x10400006, 0x0, 0x8ee20194,
+0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
+0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
+0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
+0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
+0x3c020001, 0x3442f000, 0x621024, 0x50400001,
+0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
+0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
+0x8f820124, 0x27633000, 0x43102b, 0x10400005,
+0x276237e0, 0xaf820124, 0x80023ca, 0x0,
+0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
+0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
+0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
+0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
+0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
+0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
+0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
+0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
+0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
+0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
+0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
+0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
+0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
+0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
+0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
+0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
+0x62182b, 0x10600005, 0x0, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
+0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
+0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
+0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
+0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
+0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
+0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
+0x800244e, 0x0, 0x24a40008, 0xc002488,
+0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
+0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
+0x45102b, 0x10400005, 0x0, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
+0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
+0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
+0x45102b, 0xac720010, 0xac730014, 0xac740018,
+0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
+0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
+0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
+0x24840004, 0x3e00008, 0x0, 0x10c00007,
+0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
+0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
+0x0, 0x10c00007, 0x0, 0x8ca20000,
+0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
+0x24840004, 0x3e00008, 0x0, 0x3e00008,
+0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
+0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
+0x8ee304fc, 0x21100, 0x626021, 0x95870008,
+0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
+0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
+0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
+0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
+0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
+0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
+0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
+0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
+0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
+0x10400149, 0x0, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
+0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
+0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
+0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
+0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
+0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+0x0, 0x8002516, 0x0, 0x14a00005,
+0x0, 0x8f820108, 0x24420020, 0xaf820108,
+0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x800252c, 0x0, 0x8ee24e28,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
+0x3641821, 0x24420010, 0x43102b, 0x14400073,
+0x0, 0x8ee27264, 0x24480010, 0x3641021,
+0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
+0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
+0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
+0x0, 0x8f820104, 0x14c20007, 0x2563000c,
+0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
+0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
+0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
+0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
+0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
+0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
+0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+0x0, 0x800258a, 0x0, 0x14a00005,
+0x0, 0x8f820108, 0x24420020, 0xaf820108,
+0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
+0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
+0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
+0x27662800, 0x8f820108, 0x10c20004, 0x0,
+0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
+0x4821, 0x24420001, 0xaee201a8, 0x800260d,
+0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
+0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
+0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
+0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
+0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
+0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
+0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
+0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
+0x10a20005, 0x0, 0x80025f7, 0x0,
+0x14a00005, 0x0, 0x8f820108, 0x24420020,
+0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x800260d, 0x0,
+0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x24020005, 0xac820000, 0x24020001, 0xac820004,
+0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
+0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
+0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
+0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
+0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
+0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
+0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
+0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
+0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
+0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x8002661, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8002677, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x15200009, 0x3c050004,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
+0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
+0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
+0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
+0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
+0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
+0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
+0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
+0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
+0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
+0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
+0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
+0x14e20007, 0x0, 0x8ee201b4, 0x4821,
+0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
+0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
+0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
+0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
+0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
+0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
+0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
+0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
+0x10620016, 0x28620003, 0x10400005, 0x24020001,
+0x10620008, 0x0, 0x8002703, 0x0,
+0x24020003, 0x10620017, 0x0, 0x8002703,
+0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
+0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
+0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
+0x8ee500e4, 0x401821, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaee400e0,
+0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
+0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
+0x96e2045a, 0x30420010, 0x10400149, 0x0,
+0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
+0x0, 0x8f820104, 0x14a20006, 0x2402000c,
+0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
+0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
+0x24060005, 0xa482000e, 0xac860018, 0xac830008,
+0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
+0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x8002758,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x800276e,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
+0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
+0x43102b, 0x14400073, 0x0, 0x8ee27264,
+0x24480010, 0x3641021, 0x102102b, 0x14400002,
+0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
+0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
+0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
+0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
+0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
+0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
+0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
+0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
+0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
+0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x80027cc,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
+0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
+0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
+0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
+0x10c20004, 0x0, 0x8f820104, 0x14c20007,
+0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
+0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
+0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
+0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
+0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
+0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
+0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x8002839, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x800284f, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x1520000a, 0x34028100,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
+0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
+0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
+0x8f830100, 0x27623000, 0x24640020, 0x82102b,
+0x50400001, 0x27642800, 0x8f820108, 0x10820004,
+0x0, 0x8f820104, 0x14820007, 0x24050005,
+0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
+0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
+0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
+0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x80028a0,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
+0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
+0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
+0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
+0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
+0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
+0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
+0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
+0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
+0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
+0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
+0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
+0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
+0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
+0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
+0x34460400, 0x31420200, 0x1040001f, 0x0,
+0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
+0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
+0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
+0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
+0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
+0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
+0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
+0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
+0x44102a, 0x10400015, 0x0, 0x8f8200d8,
+0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
+0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
+0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
+0x10400006, 0x0, 0x8ee201b8, 0x24420001,
+0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
+0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
+0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
+0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
+0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
+0x0, 0x8f820104, 0x10a2002f, 0x24020015,
+0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
+0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
+0x771821, 0x8c6383dc, 0xac860010, 0x431025,
+0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
+0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e21821, 0x24020015, 0xac620000, 0x24020001,
+0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
+0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
+0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
+0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x80029a9, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x1540000a, 0x24020001,
+0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
+0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
+0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
+0x370821, 0xac2083d8, 0x3c010001, 0x370821,
+0xac2083dc, 0x21100, 0x431021, 0xac44000c,
+0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
+0x24420007, 0x451024, 0x24630007, 0xaee27258,
+0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
+0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
+0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
+0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
+0x0, 0x8f830100, 0x27623000, 0x24640020,
+0x82102b, 0x14400002, 0x5021, 0x27642800,
+0x8f820108, 0x10820004, 0x0, 0x8f820104,
+0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
+0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
+0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
+0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x8002a30,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
+0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
+0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
+0x8002a72, 0x0, 0x8ee27264, 0x451021,
+0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
+0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
+0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
+0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
+0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
+0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
+0x0, 0x8f820060, 0x2403fff7, 0x431024,
+0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
+0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
+0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
+0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
+0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
+0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
+0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
+0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
+0x8f830108, 0x21140, 0x621821, 0xaf830108,
+0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
+0x104000c1, 0x31080, 0x3c010001, 0x220821,
+0x8c225770, 0x400008, 0x0, 0x8ee204f0,
+0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
+0x43102b, 0x144000be, 0x0, 0x8ee304e4,
+0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
+0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x8002afc,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
+0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
+0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
+0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
+0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
+0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee20504,
+0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
+0x21080, 0x571021, 0x8c440508, 0x24020003,
+0x1462000f, 0x0, 0x3c020001, 0x571021,
+0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
+0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
+0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
+0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
+0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
+0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
+0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
+0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
+0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
+0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
+0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
+0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
+0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
+0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
+0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
+0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
+0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
+0x400008, 0x0, 0x9663000e, 0x8ee2725c,
+0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
+0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
+0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
+0x82202b, 0x148003b9, 0x0, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
+0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8002be8,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
+0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
+0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
+0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
+0x240c0001, 0x8002f19, 0x0, 0x966c001c,
+0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
+0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
+0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
+0x641821, 0x9476000a, 0x14400003, 0x32c20002,
+0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
+0x96e2045a, 0x30420002, 0x10400047, 0x0,
+0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
+0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
+0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
+0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
+0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
+0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
+0x94440012, 0x94450014, 0x2038021, 0x2048021,
+0x2058021, 0x94430016, 0x94440018, 0x9445001a,
+0x2038021, 0x2048021, 0x2058021, 0x9443001c,
+0x9444001e, 0x94420020, 0x2038021, 0x2048021,
+0x2028021, 0x101c02, 0x3202ffff, 0x628021,
+0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
+0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
+0x37e1021, 0x24630018, 0x62182b, 0x14600009,
+0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
+0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
+0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
+0x101027, 0xa4620018, 0x96e2045a, 0x8821,
+0x30420008, 0x14400063, 0xa021, 0x8e63001c,
+0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
+0x37e1821, 0x24420022, 0x43102b, 0x14400035,
+0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
+0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
+0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
+0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
+0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
+0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
+0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
+0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
+0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
+0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
+0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
+0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
+0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
+0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
+0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
+0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
+0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
+0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
+0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
+0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
+0x2238821, 0x2248821, 0x2228821, 0x111c02,
+0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
+0x628821, 0x32c20001, 0x104000b2, 0x0,
+0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
+0x10400008, 0x0, 0x92e27b98, 0x14400005,
+0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
+0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
+0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
+0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
+0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
+0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
+0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
+0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
+0x2058021, 0x2038021, 0x2028021, 0x94e20000,
+0x94e30002, 0x2048021, 0x2028021, 0x2038021,
+0x101c02, 0x3202ffff, 0x628021, 0x101c02,
+0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
+0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
+0x96620016, 0x542021, 0x41402, 0x3083ffff,
+0x432021, 0x852023, 0x41402, 0x822021,
+0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
+0x24430017, 0x37e1021, 0x62102b, 0x50400001,
+0x6b1821, 0x90630000, 0x24020011, 0x14620031,
+0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
+0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
+0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
+0x220821, 0x94220028, 0x822021, 0x41c02,
+0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
+0x41027, 0x92e27b98, 0x14400002, 0x41027,
+0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
+0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
+0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
+0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
+0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
+0x24420032, 0x43102b, 0x14400018, 0x0,
+0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
+0x3c01ffff, 0x220821, 0x94220032, 0x822021,
+0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
+0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
+0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
+0x822021, 0x41c02, 0x3082ffff, 0x622021,
+0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
+0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
+0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
+0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
+0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
+0x62102b, 0x14400003, 0x602021, 0x6b1821,
+0x602021, 0x8c620000, 0x24630004, 0xae420000,
+0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
+0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
+0x24630002, 0x37e1021, 0x62102b, 0x50400001,
+0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
+0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
+0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
+0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
+0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
+0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
+0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
+0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
+0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
+0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
+0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
+0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
+0x4821, 0x5021, 0x8f8200f0, 0x24480008,
+0x27621800, 0x102102b, 0x50400001, 0x27681000,
+0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
+0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
+0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
+0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
+0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
+0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
+0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
+0x401821, 0x1021, 0xa32821, 0xa3382b,
+0x822021, 0x872021, 0x8ee204fc, 0xc93021,
+0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
+0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
+0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
+0x106c0008, 0x0, 0x8002e3f, 0x0,
+0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
+0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
+0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
+0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
+0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
+0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
+0x27621800, 0xe2102b, 0x50400001, 0x27671000,
+0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
+0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
+0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
+0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
+0x16000007, 0x0, 0x8ee20088, 0x24420001,
+0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
+0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
+0x401821, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0x161142, 0x30430003,
+0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
+0x10400005, 0x240c0001, 0x106c0008, 0x0,
+0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
+0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
+0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
+0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
+0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
+0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
+0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
+0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
+0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
+0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
+0x8f42023c, 0x82202b, 0x148000b0, 0x0,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002ef1, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
+0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
+0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
+0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
+0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
+0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
+0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
+0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
+0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
+0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
+0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
+0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
+0x21080, 0x571021, 0x146c000f, 0x8c440508,
+0x3c020001, 0x571021, 0x904283b1, 0x10400014,
+0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
+0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
+0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
+0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
+0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
+0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
+0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
+0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
+0x27633000, 0x43102b, 0x14400002, 0x27622800,
+0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
+0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
+0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
+0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
+0x52843, 0x10a0000d, 0x3021, 0x3c030001,
+0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
+0x50400001, 0x872021, 0x94820000, 0x24840002,
+0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
+0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
+0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
+0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
+0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
+0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
+0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
+0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
+0xe22023, 0x2c821000, 0x50400001, 0x24841000,
+0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
+0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
+0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
+0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
+0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
+0x904283c0, 0x1040000b, 0x0, 0x3c140001,
+0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
+0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
+0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
+0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
+0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
+0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
+0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
+0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
+0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
+0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
+0x2409821, 0x3c020080, 0x621024, 0x1040000a,
+0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
+0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
+0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
+0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
+0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
+0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
+0xc3102b, 0x14400007, 0x0, 0x106b0011,
+0x0, 0x106a0015, 0x0, 0x8003049,
+0x42042, 0x10650023, 0xa3102b, 0x14400005,
+0x0, 0x10690019, 0x0, 0x8003049,
+0x42042, 0x10680021, 0x0, 0x8003049,
+0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
+0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
+0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
+0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
+0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
+0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
+0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
+0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
+0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
+0x1087047c, 0x0, 0x800300e, 0x0,
+0x3c020001, 0x571021, 0x904283b2, 0x14400084,
+0x24020001, 0x3c030001, 0x771821, 0x906383b3,
+0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
+0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
+0x96430004, 0x3402ffff, 0x10620075, 0x0,
+0x92e204d8, 0x14400072, 0x0, 0x3c020001,
+0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
+0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
+0x18400016, 0x2821, 0x96660000, 0x520c0,
+0x971021, 0x9442777e, 0x14460009, 0x971021,
+0x94437780, 0x96620002, 0x14620005, 0x971021,
+0x94437782, 0x96620004, 0x50620008, 0x24070001,
+0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
+0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
+0x10400440, 0x0, 0x80030d5, 0x0,
+0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
+0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
+0x14400434, 0xb71021, 0x9443727e, 0x96620000,
+0x1462000b, 0x418c0, 0xb71021, 0x94437280,
+0x96620002, 0x14620006, 0x418c0, 0xb71021,
+0x94437282, 0x96620004, 0x10620035, 0x418c0,
+0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
+0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
+0xb71021, 0x9442737e, 0x80030b7, 0x3021,
+0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
+0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
+0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
+0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
+0x420c0, 0xb71021, 0x94437382, 0x96620004,
+0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
+0x10400400, 0x0, 0x80030d5, 0x0,
+0x97430202, 0x96420000, 0x146203fa, 0x0,
+0x97430204, 0x96420002, 0x146203f6, 0x0,
+0x97430206, 0x96420004, 0x146203f2, 0x0,
+0x92420000, 0x3a030001, 0x30420001, 0x431024,
+0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
+0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
+0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
+0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96620002, 0x14620005,
+0x971021, 0x94437782, 0x96620004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x144003af, 0xb71021, 0x9443727e,
+0x96620000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96620002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96620004, 0x10620027,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
+0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
+0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1602021, 0xb71021, 0x94437380, 0x96620002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x1040037b, 0x0, 0x800314f,
+0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
+0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f003, 0x80034cc, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
+0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
+0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
+0x96e20468, 0x54102b, 0x10400003, 0x0,
+0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
+0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
+0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
+0x0, 0x93a20027, 0x10400014, 0x0,
+0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
+0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
+0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
+0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
+0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
+0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
+0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
+0x10400019, 0x0, 0x9642000c, 0x340f8100,
+0x144f0015, 0x0, 0x3c020001, 0x571021,
+0x904283c0, 0x14400010, 0x0, 0x9642000e,
+0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
+0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
+0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
+0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
+0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
+0x3641021, 0x262102b, 0x10400005, 0x28aa021,
+0x2641023, 0x3621823, 0x3c020020, 0x439823,
+0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
+0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
+0x603821, 0xae130018, 0x8f880120, 0x24e20007,
+0x443824, 0x27623800, 0x25090020, 0x122102b,
+0x50400001, 0x27693000, 0x8f820128, 0x11220004,
+0x0, 0x8f820124, 0x15220007, 0x1401821,
+0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
+0x1021, 0xad130008, 0xa507000e, 0xad160018,
+0xad06001c, 0xa3302b, 0xa32823, 0x822023,
+0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
+0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
+0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x1456001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10550007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8003239, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x800324c, 0x0, 0x8ee24e30, 0x24420001,
+0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
+0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
+0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
+0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
+0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
+0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
+0xae440008, 0x96020016, 0x8003470, 0xa642000e,
+0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
+0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
+0x8f880120, 0x27623800, 0x25090020, 0x122102b,
+0x14400002, 0x306affff, 0x27693000, 0x8f820128,
+0x11220004, 0x0, 0x8f820124, 0x15220007,
+0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
+0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
+0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
+0xad100008, 0xad040018, 0x52940, 0xa01821,
+0x1021, 0xe33821, 0xe3202b, 0xc23021,
+0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
+0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x0, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+0x10620005, 0x0, 0x80032b7, 0x0,
+0x14600005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400010, 0xac800000, 0x80032ca, 0x0,
+0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0xac960000,
+0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
+0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
+0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
+0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
+0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
+0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+0x8f430240, 0x43102b, 0x14400176, 0xa021,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800333c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800334f,
+0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
+0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
+0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
+0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
+0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
+0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
+0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
+0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x0, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+0x10620005, 0x0, 0x80033a7, 0x0,
+0x14600005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400010, 0xac800000, 0x80033ba, 0x0,
+0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
+0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
+0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
+0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
+0xa021, 0x960c000a, 0x183102b, 0x54400001,
+0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
+0x25090020, 0x122102b, 0x50400001, 0x27693000,
+0x8f820128, 0x11220004, 0x0, 0x8f820124,
+0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
+0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
+0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
+0x24040004, 0xad100008, 0xad040018, 0x52940,
+0xa01821, 0x1021, 0xe33821, 0xe3202b,
+0xc23021, 0xc43021, 0xad060000, 0xad070004,
+0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
+0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800341c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800342f,
+0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac960000, 0xac9e0004, 0x1620001d, 0x0,
+0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
+0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
+0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
+0xae430004, 0xae440008, 0x96020016, 0xa642000e,
+0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
+0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
+0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
+0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
+0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
+0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
+0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
+0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
+0x0, 0x3c010001, 0x370821, 0xac3483c4,
+0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
+0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
+0x0, 0x3c020001, 0x571021, 0x8c4283cc,
+0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
+0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
+0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
+0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
+0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
+0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
+0x14400017, 0x24020003, 0x15e20015, 0x0,
+0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
+0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
+0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
+0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
+0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
+0xa821, 0xafb00030, 0x8021, 0xafbf004c,
+0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
+0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
+0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
+0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
+0x571021, 0x904283c0, 0x1040000b, 0x0,
+0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
+0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
+0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
+0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
+0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+0x10400058, 0x2408821, 0x3c020080, 0x621024,
+0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
+0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+0x10660021, 0xc3102b, 0x14400007, 0x0,
+0x106b0011, 0x0, 0x106a0015, 0x0,
+0x8003592, 0x42042, 0x10650023, 0xa3102b,
+0x14400005, 0x0, 0x10690019, 0x0,
+0x8003592, 0x42042, 0x10680021, 0x0,
+0x8003592, 0x42042, 0x8ee20034, 0x24420001,
+0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
+0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
+0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
+0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+0x8003592, 0x42042, 0x8ee20030, 0x24420001,
+0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
+0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+0x42042, 0x108702b7, 0x0, 0x8003557,
+0x0, 0x3c020001, 0x571021, 0x904283b2,
+0x14400084, 0x24020001, 0x3c030001, 0x771821,
+0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
+0x0, 0x92e204d8, 0x14400072, 0x0,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96220002, 0x14620005,
+0x971021, 0x94437782, 0x96220004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x1040027b, 0x0, 0x800361e,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
+0x96220000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96220002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96220004, 0x10620035,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
+0x828c0, 0xb71021, 0x9442737e, 0x8003600,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
+0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1002021, 0xb71021, 0x94437380, 0x96220002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x1040023b, 0x0, 0x800361e,
+0x0, 0x97430202, 0x96420000, 0x14620235,
+0x0, 0x97430204, 0x96420002, 0x14620231,
+0x0, 0x97430206, 0x96420004, 0x1462022d,
+0x0, 0x92420000, 0x3a030001, 0x30420001,
+0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
+0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
+0x24140002, 0x3c020001, 0x571021, 0x904283b2,
+0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
+0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+0x28420005, 0x10400020, 0x3821, 0x3c020001,
+0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+0x96260000, 0x520c0, 0x971021, 0x9442777e,
+0x14460009, 0x971021, 0x94437780, 0x96220002,
+0x14620005, 0x971021, 0x94437782, 0x96220004,
+0x50620008, 0x24070001, 0x3c020001, 0x571021,
+0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
+0x800384a, 0x0, 0x2402021, 0xc0022fe,
+0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
+0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
+0xb71021, 0x94437280, 0x96220002, 0x14620006,
+0x418c0, 0xb71021, 0x94437282, 0x96220004,
+0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
+0x96270000, 0x828c0, 0xb71021, 0x9442737e,
+0x8003685, 0x3021, 0x420c0, 0x2e41021,
+0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
+0x14600010, 0x828c0, 0xb71021, 0x9442737e,
+0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
+0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
+0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
+0x24060001, 0x30c200ff, 0x104001b6, 0x0,
+0x8003698, 0x24140003, 0x24140001, 0x8f420260,
+0x53102b, 0x10400049, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f003, 0x8003850, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
+0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
+0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
+0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
+0x53102b, 0x54400001, 0x3c158000, 0x12600131,
+0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x304207ff, 0x10620108, 0x0,
+0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
+0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
+0x21140, 0x24425248, 0x2e28021, 0x24630001,
+0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
+0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
+0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
+0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
+0x21140, 0x24420e20, 0x2e28021, 0x24630001,
+0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
+0x34028100, 0x9643000c, 0x14620014, 0x0,
+0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
+0x0, 0x9642000e, 0xa6020016, 0x8e420008,
+0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
+0xae430008, 0xae440004, 0x9602000e, 0x26310004,
+0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
+0x2605021, 0x73102b, 0x10400002, 0x2606821,
+0x605021, 0x2d42003d, 0x1040002a, 0x3821,
+0x9623000c, 0x24020800, 0x54620027, 0xae110018,
+0x3c020001, 0x571021, 0x904283c0, 0x54400022,
+0xae110018, 0x26220017, 0x182102b, 0x10400013,
+0x0, 0x3c02fff5, 0x511021, 0x90421017,
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+0x621825, 0x10600013, 0x26220010, 0x182102b,
+0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
+0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+0x621825, 0x50600004, 0xae110018, 0x96270010,
+0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
+0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
+0x1403821, 0x8f830120, 0x27623800, 0x24660020,
+0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
+0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
+0x8e050004, 0xac620018, 0x1751025, 0x491025,
+0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
+0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x14620020, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
+0x24020040, 0x24630001, 0x10620007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80037a9, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x15200018, 0x3c050006,
+0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
+0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
+0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
+0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
+0xa642000c, 0xae430000, 0xae440004, 0xae450008,
+0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
+0x0, 0x9602000e, 0xa613000a, 0x34420004,
+0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
+0x80037f6, 0x9821, 0x9604000a, 0x93102b,
+0x10400002, 0x2601821, 0x801821, 0x24020001,
+0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
+0x9604000a, 0x2248821, 0x191102b, 0x10400003,
+0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
+0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
+0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
+0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
+0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
+0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x14620006, 0x0, 0x8ee201c4,
+0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
+0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
+0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
+0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0x24020002,
+0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
+0x14400017, 0x24020003, 0x16820015, 0x0,
+0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
+0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
+0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
+0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
+0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
+0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
+0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
+0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
+0x571021, 0x904283c0, 0x1040000b, 0x0,
+0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
+0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
+0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
+0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
+0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+0x10400058, 0x2408021, 0x3c020080, 0x621024,
+0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
+0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+0x10660021, 0xc3102b, 0x14400007, 0x0,
+0x106b0011, 0x0, 0x106a0015, 0x0,
+0x8003916, 0x42042, 0x10650023, 0xa3102b,
+0x14400005, 0x0, 0x10690019, 0x0,
+0x8003916, 0x42042, 0x10680021, 0x0,
+0x8003916, 0x42042, 0x8ee20034, 0x24420001,
+0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
+0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
+0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
+0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+0x8003916, 0x42042, 0x8ee20030, 0x24420001,
+0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
+0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+0x42042, 0x1087033e, 0x0, 0x80038db,
+0x0, 0x3c020001, 0x571021, 0x904283b2,
+0x14400084, 0x24020001, 0x3c030001, 0x771821,
+0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
+0x0, 0x92e204d8, 0x14400072, 0x0,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96020002, 0x14620005,
+0x971021, 0x94437782, 0x96020004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x10400302, 0x0, 0x80039a2,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
+0x96020000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96020002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96020004, 0x10620035,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
+0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
+0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1a02021, 0xb71021, 0x94437380, 0x96020002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
+0x0, 0x97430202, 0x96420000, 0x146202bc,
+0x0, 0x97430204, 0x96420002, 0x146202b8,
+0x0, 0x97430206, 0x96420004, 0x146202b4,
+0x0, 0x92420000, 0x3a230001, 0x30420001,
+0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
+0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
+0x24150002, 0x3c020001, 0x571021, 0x904283b2,
+0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
+0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+0x28420005, 0x10400020, 0x3821, 0x3c020001,
+0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+0x96060000, 0x520c0, 0x971021, 0x9442777e,
+0x14460009, 0x971021, 0x94437780, 0x96020002,
+0x14620005, 0x971021, 0x94437782, 0x96020004,
+0x50620008, 0x24070001, 0x3c020001, 0x571021,
+0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
+0x8003c55, 0x0, 0x2402021, 0xc0022fe,
+0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+0x9442727c, 0x30424000, 0x14400271, 0xb71021,
+0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
+0xb71021, 0x94437280, 0x96020002, 0x14620006,
+0x418c0, 0xb71021, 0x94437282, 0x96020004,
+0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
+0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
+0x8003a09, 0x3021, 0x420c0, 0x2e41021,
+0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
+0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
+0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
+0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
+0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
+0x24060001, 0x30c200ff, 0x1040023d, 0x0,
+0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
+0x53102b, 0x10400036, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
+0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
+0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
+0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
+0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x304207ff, 0x1062019e, 0x0,
+0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
+0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
+0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
+0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
+0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
+0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
+0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
+0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
+0x9643000c, 0x14620015, 0x0, 0x3c020001,
+0x571021, 0x904283c0, 0x14400010, 0x0,
+0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
+0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
+0xae440004, 0x9622000e, 0x26100004, 0x24180001,
+0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
+0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
+0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
+0x10400005, 0x26a9821, 0x2041023, 0x3621823,
+0x3c020020, 0x438023, 0x26620007, 0x9623000a,
+0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
+0x10400002, 0x3206021, 0x606021, 0x1801821,
+0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
+0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
+0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
+0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
+0x14400035, 0x5821, 0x94c3000c, 0x24020800,
+0x54620032, 0xae260018, 0x3c020001, 0x571021,
+0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
+0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
+0x461021, 0x90421017, 0x38430006, 0x2c630001,
+0x38420011, 0x2c420001, 0x621825, 0x10600014,
+0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
+0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
+0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
+0x38420011, 0x2c420001, 0x621825, 0x10600005,
+0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
+0x1601821, 0x24620007, 0x2418fff8, 0x585824,
+0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
+0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
+0x571021, 0x904283c0, 0x2102b, 0x216c0,
+0x15600002, 0xafa20044, 0x1805821, 0x30820001,
+0x10400007, 0x4021, 0x90880000, 0x24840001,
+0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
+0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
+0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
+0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
+0x8f2021, 0x90820000, 0x21200, 0x1024021,
+0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
+0x624021, 0x3108ffff, 0x1402821, 0x11400011,
+0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
+0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
+0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
+0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
+0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
+0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
+0x27623800, 0x25230020, 0x62102b, 0x14400002,
+0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
+0x0, 0x8f820124, 0x14620007, 0x1402821,
+0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
+0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
+0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
+0xad280018, 0x8fb80044, 0x2021, 0x2961025,
+0x581025, 0xad22001c, 0xe5102b, 0xe53823,
+0xc43023, 0xc23023, 0xad260000, 0xad270004,
+0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
+0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
+0x14400003, 0x24020011, 0x15020024, 0x0,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462000f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
+0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
+0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8003bb4,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
+0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
+0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
+0x8e230004, 0x2203021, 0x1603821, 0xc002403,
+0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
+0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
+0xae430000, 0xae440004, 0xae450008, 0x96220016,
+0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
+0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
+0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
+0x9821, 0x9624000a, 0x83102b, 0x54400001,
+0x801821, 0x24020001, 0xa623000a, 0x3c010001,
+0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
+0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
+0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
+0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
+0x370821, 0xac3383c4, 0x3c010001, 0x370821,
+0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
+0x93a2002f, 0x10400008, 0x0, 0x3c020001,
+0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
+0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
+0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
+0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0x24020002, 0xaee400c0,
+0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
+0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
+0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
+0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
+0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
+0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
+0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
+0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
+0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
+0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
+0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
+0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
+0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
+0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
+0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
+0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
+0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
+0x804821, 0x69102a, 0x54400001, 0x604821,
+0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
+0x50400001, 0x27682800, 0x8f820108, 0x11020004,
+0x0, 0x8f820104, 0x15020007, 0x1021,
+0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
+0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
+0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xace40000,
+0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
+0x24020002, 0xace20018, 0x31940, 0x24630e20,
+0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
+0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
+0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
+0x24020001, 0xac620004, 0x1480000e, 0x24030040,
+0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
+0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
+0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
+0x0, 0x8ee20500, 0x24420001, 0x50430003,
+0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
+0x8ee20500, 0x21080, 0x571021, 0xac490508,
+0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
+0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
+0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
+0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
+0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
+0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
+0x431023, 0x2443ffff, 0x804821, 0x69102a,
+0x54400001, 0x604821, 0x8f870100, 0x27623000,
+0x24e80020, 0x102102b, 0x50400001, 0x27682800,
+0x8f820108, 0x11020004, 0x0, 0x8f820104,
+0x15020007, 0x1021, 0x8ee201a8, 0x2021,
+0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
+0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
+0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
+0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
+0x31940, 0x24635248, 0x2e31021, 0xace20008,
+0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
+0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
+0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
+0x24020003, 0xac620000, 0x24020001, 0xac620004,
+0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
+0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
+0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
+0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
+0x24420001, 0x50430003, 0x1021, 0x8ee20500,
+0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
+0x571021, 0xac490508, 0x8ee2523c, 0x491021,
+0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
+0x14620005, 0x0, 0x8f820060, 0x2403feff,
+0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
+0x8f860128, 0x24020040, 0x24630001, 0x50620003,
+0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
+0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
+0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
+0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
+0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
+0x8f830128, 0x21140, 0x621821, 0xaf830128,
+0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
+0x10400008, 0x31080, 0x3c010001, 0x220821,
+0x8c2258f0, 0x400008, 0x0, 0x24020001,
+0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
+0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
+0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
+0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
+0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
+0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
+0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
+0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
+0x220821, 0x8c225948, 0x400008, 0x0,
+0x8f420218, 0x30420100, 0x10400007, 0x0,
+0x95830016, 0x95820018, 0x621823, 0x31402,
+0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
+0x3044ffff, 0x436824, 0x3c030800, 0x431824,
+0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
+0x24425248, 0x41140, 0x24420e20, 0x2e25821,
+0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
+0x95840016, 0x8003ec0, 0x0, 0x8d690018,
+0x4021, 0x952a0000, 0x25290002, 0x95270000,
+0x25290002, 0x95260000, 0x25290002, 0x95250000,
+0x25290002, 0x95240000, 0x25290002, 0x95230000,
+0x25290002, 0x95220000, 0x25290002, 0x1475021,
+0x1465021, 0x1455021, 0x1445021, 0x1435021,
+0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
+0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
+0x314effff, 0x30420002, 0x10400044, 0x5021,
+0x25220014, 0x222102b, 0x10400014, 0x1201821,
+0x2405000a, 0x2021, 0x223102b, 0x54400001,
+0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
+0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
+0x622021, 0x41402, 0x3083ffff, 0x431021,
+0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
+0x25290002, 0x95280000, 0x25290002, 0x95270000,
+0x25290002, 0x95260000, 0x25290002, 0x95250000,
+0x25290002, 0x95230000, 0x25290002, 0x95220000,
+0x25290002, 0x95240000, 0x25290002, 0x1485021,
+0x1475021, 0x1465021, 0x1455021, 0x1435021,
+0x1425021, 0x95220000, 0x95230002, 0x1445021,
+0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
+0x625021, 0xa1c02, 0x3142ffff, 0x625021,
+0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
+0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
+0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
+0x96e2046a, 0x2821, 0x30420008, 0x14400056,
+0x3021, 0x8d630018, 0x24620024, 0x222102b,
+0x10400034, 0x24690010, 0x229102b, 0x54400001,
+0x1324821, 0x95250000, 0x24690014, 0x229102b,
+0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
+0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
+0x24130001, 0x9821, 0xa03021, 0x229102b,
+0x54400001, 0x1324821, 0x91220001, 0x25290002,
+0xa22821, 0x229102b, 0x54400001, 0x1324821,
+0x25290002, 0x229102b, 0x54400001, 0x1324821,
+0x95220000, 0x25290002, 0xa22821, 0x229102b,
+0x54400001, 0x1324821, 0x95220000, 0x25290002,
+0xa22821, 0x229102b, 0x54400001, 0x1324821,
+0x95220000, 0x25290002, 0xa22821, 0x229102b,
+0x54400001, 0x1324821, 0x95220000, 0x8003e99,
+0xa22821, 0x94650010, 0x94620014, 0x24690016,
+0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
+0x24130001, 0x9821, 0xa03021, 0x91230001,
+0x25290004, 0x95220000, 0x25290002, 0x95240000,
+0x25290002, 0xa32821, 0xa22821, 0x95220000,
+0x95230002, 0xa42821, 0xa22821, 0xa32821,
+0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
+0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
+0x1040001e, 0x2021, 0x95820016, 0x4e2023,
+0x41402, 0x822021, 0x326200ff, 0x50400002,
+0x862021, 0x852021, 0x41402, 0x822021,
+0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
+0x24430017, 0x223102b, 0x54400001, 0x721821,
+0x90620000, 0x38430011, 0x2c630001, 0x38420006,
+0x2c420001, 0x621825, 0x10600004, 0x0,
+0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
+0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
+0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
+0x122102b, 0x50400001, 0x27693000, 0x8f820128,
+0x11220004, 0x0, 0x8f820124, 0x15220007,
+0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
+0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
+0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
+0xad0a0018, 0x52940, 0xa01821, 0x1021,
+0xe33821, 0xe3202b, 0xc23021, 0xc43021,
+0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
+0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
+0x2c630002, 0x39420011, 0x2c420001, 0x621825,
+0x10600024, 0x0, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
+0x0, 0x8003f2e, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
+0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8003f3a, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
+0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x1600000d, 0x0,
+0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
+0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
+0xc002403, 0x34a50001, 0x8004057, 0x0,
+0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
+0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
+0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
+0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
+0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
+0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
+0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
+0x144000d5, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
+0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8003fc6, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
+0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020001, 0xac950000,
+0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
+0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
+0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10540007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8004030,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400011, 0xac800000, 0x8004044,
+0x0, 0x8ee24e30, 0x24420001, 0x50540003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020001, 0xac950000, 0xac820004, 0x1600000b,
+0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
+0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
+0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
+0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
+0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
+0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
+0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
+0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
+0xc00249a, 0xafb00010, 0x2021, 0x24100001,
+0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
+0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
+0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
+0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
+0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
+0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
+0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
+0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
+0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
+0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
+0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
+0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
+0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
+0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
+0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
+0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
+0xc00429b, 0x0, 0x3c020100, 0x2021024,
+0x10400007, 0x0, 0x8ee20218, 0x24420001,
+0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
+0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
+0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
+0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
+0x2003021, 0x431024, 0xaee20000, 0x8f820220,
+0x3821, 0x3c030300, 0x481024, 0x431025,
+0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
+0x8004296, 0x0, 0x2111024, 0x1040001f,
+0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
+0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
+0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
+0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
+0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
+0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x8004295, 0x511025, 0x2021024,
+0x10400142, 0x0, 0x8ee2022c, 0x24420001,
+0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
+0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
+0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
+0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
+0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
+0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
+0xc21024, 0x1043000d, 0x0, 0x8f820054,
+0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
+0x821023, 0x2c420051, 0x10400004, 0x0,
+0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
+0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
+0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
+0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
+0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
+0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
+0x8f850120, 0x8f840124, 0x8004145, 0x6021,
+0x27623800, 0x82102b, 0x50400001, 0x27643000,
+0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
+0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
+0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
+0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
+0x318200ff, 0x14400065, 0x0, 0x3c020001,
+0x571021, 0x904283c0, 0x14400060, 0x0,
+0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
+0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
+0x10620009, 0x0, 0x8004187, 0x0,
+0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
+0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
+0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
+0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
+0x651821, 0x2c62233f, 0x14400040, 0x0,
+0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
+0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
+0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
+0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
+0x8ee20238, 0x883823, 0x67102b, 0x54400001,
+0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
+0x10400003, 0x0, 0x80041bc, 0x805821,
+0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
+0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
+0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
+0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
+0x54400001, 0xe53821, 0x147102b, 0x54400007,
+0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
+0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
+0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
+0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
+0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
+0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
+0x47102b, 0x54400007, 0x6021, 0x1683823,
+0x67102b, 0x54400003, 0xe33821, 0x80041cf,
+0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
+0x14400016, 0x318200ff, 0x14400006, 0x0,
+0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
+0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
+0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
+0x24020001, 0x641824, 0x3c010001, 0x370821,
+0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
+0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
+0x623823, 0x87102b, 0x54400001, 0xe43821,
+0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
+0x431025, 0x10400008, 0x0, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
+0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
+0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
+0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
+0x431024, 0x1040001d, 0x0, 0x10c4001b,
+0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
+0x24850008, 0x27622800, 0x50a20001, 0x27651800,
+0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
+0x431021, 0x4d1024, 0x24430010, 0x6b102b,
+0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
+0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
+0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
+0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
+0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
+0x0, 0x8ee20228, 0x24420001, 0xaee20228,
+0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820220, 0x8f830054,
+0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
+0x621023, 0x2c420003, 0x1440fffc, 0x0,
+0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
+0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
+0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
+0x24440032, 0x8f820054, 0x821023, 0x2c420033,
+0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
+0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
+0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
+0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
+0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
+0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
+0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
+0x441024, 0x431025, 0xaf820220, 0x8f830054,
+0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
+0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
+0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
+0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
+0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
+0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
+0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
+0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
+0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
+0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
+0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
+0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
+0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x2821, 0x24420001, 0xaee201a4, 0x800433d,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x800432a, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x800433d, 0x0, 0x8ee24e30,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
+0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
+0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8004396, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
+0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
+0x0, 0x3c040001, 0x24845a20, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
+0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
+0x0, 0x3c040001, 0x24845a38, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
+0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
+0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
+0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
+0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
+0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
+0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
+0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x3c120001,
+0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
+0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
+0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
+0x0, 0xd, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x80014d6,
+0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
+0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
+0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
+0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
+0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
+0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
+0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
+0x0, 0x80014d8, 0x0, 0x8002a75,
+0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
+0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
+0x0, 0x8002339, 0x0, 0x80014d8,
+0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
+0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
+0x0, 0x8004091, 0x0, 0x80014d8,
+0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
+0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
+0x3c0a0013, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x3c030001,
+0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
+0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
+0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
+0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
+0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
+0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
+0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
+0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
+0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
+0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
+0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
+0x3c024000, 0x10620008, 0x24020800, 0x8004539,
+0x0, 0x10620004, 0x24020800, 0x8004539,
+0x0, 0x24020700, 0x3c010001, 0xac225cdc,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
+0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xc004d71, 0x0, 0x24040001, 0x2821,
+0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
+0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
+0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
+0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
+0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
+0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
+0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
+0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
+0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
+0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
+0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
+0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
+0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
+0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
+0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
+0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
+0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
+0x24020015, 0x1462000f, 0x0, 0x3c020001,
+0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
+0x3842f430, 0x2c420001, 0x621825, 0x10600005,
+0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
+0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
+0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
+0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
+0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
+0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
+0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
+0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
+0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
+0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
+0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
+0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
+0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
+0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
+0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
+0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
+0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
+0x0, 0x3c04003d, 0x800462f, 0x34840900,
+0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
+0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
+0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+0x34844240, 0x24020005, 0x14620003, 0x0,
+0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
+0x8f830054, 0x441021, 0x431023, 0x44102b,
+0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
+0x14400033, 0x0, 0x3c010001, 0x10c00025,
+0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
+0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
+0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
+0xa91024, 0x10400010, 0x0, 0x14a70008,
+0x0, 0x8d020000, 0x441024, 0x1040000a,
+0x0, 0x3c010001, 0x800465b, 0xac255ce0,
+0x8d420000, 0x441024, 0x10400003, 0x0,
+0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
+0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
+0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
+0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
+0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
+0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
+0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
+0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
+0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
+0x24020008, 0x10620005, 0x24020001, 0xc004695,
+0x0, 0x8004692, 0x0, 0x3c030001,
+0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
+0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
+0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
+0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
+0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
+0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
+0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
+0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
+0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
+0x24020002, 0x10620169, 0x2c620003, 0x10400005,
+0x24020001, 0x10620008, 0x0, 0x800481c,
+0x0, 0x24020004, 0x106200b1, 0x24020001,
+0x800481d, 0x0, 0x3c020001, 0x571021,
+0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
+0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
+0x400008, 0x0, 0x3c030001, 0x8c635dbc,
+0x24020005, 0x14620014, 0x0, 0x3c020001,
+0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
+0x0, 0x24020002, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x800481f, 0xac205c60, 0xc004822, 0x0,
+0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
+0x104000dd, 0x24020002, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
+0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
+0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
+0x0, 0x3c030001, 0x8c635d00, 0x800478e,
+0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
+0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
+0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
+0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
+0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
+0x431024, 0x144000a9, 0x24020007, 0x8f830054,
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0xc005386, 0x2021, 0x3c030001,
+0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
+0x621024, 0x10400006, 0x0, 0x8f820214,
+0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
+0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
+0x8f820220, 0x3c030004, 0x431024, 0x14400005,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
+0x1462000a, 0x0, 0x3c020001, 0x94425da2,
+0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
+0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
+0x0, 0x3c010001, 0x800481f, 0xac205d50,
+0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
+0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
+0x220821, 0x8c225ae8, 0x400008, 0x0,
+0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
+0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
+0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
+0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
+0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
+0x24020009, 0x14620090, 0x24020003, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
+0x8c427e38, 0x30424000, 0x10400005, 0x0,
+0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
+0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
+0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
+0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
+0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
+0x14400059, 0x0, 0x24020007, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
+0x3c030300, 0x431024, 0x14400005, 0x1821,
+0x8f820220, 0x24030001, 0x441025, 0xaf820220,
+0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
+0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
+0xaf820214, 0x24020008, 0x3c010001, 0x370821,
+0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
+0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
+0xc004e54, 0x8f840220, 0x800480c, 0x0,
+0x8f820220, 0x3c030008, 0x431024, 0x14400017,
+0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
+0x2021, 0x3c030200, 0x431025, 0xc005386,
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
+0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0x800481f, 0x0, 0x3c020001,
+0x8c425d74, 0x10400010, 0x0, 0x3c020001,
+0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
+0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
+0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
+0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
+0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
+0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
+0x10c20008, 0x0, 0x8004868, 0x0,
+0x24020004, 0x10c20013, 0x24020001, 0x8004868,
+0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
+0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
+0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
+0x441025, 0x451025, 0x34420002, 0x8004867,
+0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
+0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
+0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
+0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
+0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
+0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
+0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
+0x431025, 0x451025, 0xaf820220, 0x3e00008,
+0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
+0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
+0x0, 0x8f830054, 0x8f820054, 0x24630002,
+0x621023, 0x2c420003, 0x10400011, 0x0,
+0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
+0x0, 0x8004879, 0x0, 0x8f830054,
+0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
+0x621023, 0x2c420008, 0x1440fffc, 0x0,
+0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
+0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
+0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
+0x0, 0x8f8200e0, 0x1082fff9, 0x0,
+0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
+0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
+0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
+0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
+0x1040009d, 0x31080, 0x3c010001, 0x220821,
+0x8c225b08, 0x400008, 0x0, 0x8f820044,
+0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
+0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
+0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
+0x24020003, 0x8004945, 0x0, 0x8f820044,
+0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
+0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
+0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
+0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
+0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
+0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
+0x80048ec, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+0x42040, 0xa4102b, 0x1040fff2, 0x0,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
+0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
+0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
+0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
+0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
+0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
+0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
+0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
+0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
+0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
+0x24020007, 0x8004945, 0x0, 0x8f8200e0,
+0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
+0x431024, 0xaf820220, 0x8f820044, 0x34428080,
+0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
+0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
+0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020009,
+0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x27bdffd8,
+0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
+0xafb10014, 0xc08821, 0xafb00010, 0x8021,
+0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x24100010, 0x2501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
+0x2501024, 0x24100010, 0x2701024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
+0xc004d71, 0x0, 0xc004d2b, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
+0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
+0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x2301024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96620000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8fbf0020,
+0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
+0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
+0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
+0x31080, 0x3c010001, 0x220821, 0x8c225b30,
+0x400008, 0x0, 0xc004d71, 0x8021,
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
+0x8021, 0xc004d4b, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
+0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004d4b, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004d71, 0x34108000,
+0xc004d71, 0x0, 0xc004d2b, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004d71, 0x0, 0x97a20010, 0x30428000,
+0x144002dc, 0x24020003, 0x8004d24, 0x0,
+0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x2021, 0x34108000, 0x96220000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fff8, 0x0, 0xc004d71,
+0x0, 0x8f830054, 0x8004d16, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
+0x431023, 0x2c420064, 0x1440029e, 0x24020002,
+0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
+0x14400296, 0x24020011, 0x24020003, 0x10620005,
+0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
+0x24020011, 0x8004d24, 0x24020005, 0x24020014,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8f830054,
+0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400250, 0x24020007, 0x8004d24, 0x0,
+0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020013, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8f830054,
+0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
+0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400004, 0x0, 0x24020011, 0x3c010001,
+0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
+0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
+0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
+0x24840001, 0x8f820054, 0x821023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
+0x3442ffff, 0x42480, 0x621824, 0x3c020002,
+0x822025, 0x641825, 0xaf830044, 0x8f820044,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x3e00008, 0x0,
+0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
+0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
+0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
+0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x12000075,
+0x0, 0x8004dc9, 0x0, 0x3274ffff,
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
+0x34108000, 0xc004d71, 0x0, 0xc004d2b,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004d71, 0x0, 0x32a5ffff,
+0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
+0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8fbf0030,
+0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+0x0, 0x0, 0x0, 0x27bdffe8,
+0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
+0x24020008, 0x1462022c, 0x803021, 0x3c020001,
+0x8c425d98, 0x14400033, 0x0, 0x8f850224,
+0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
+0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
+0x38a20400, 0x2c420001, 0x621825, 0x14600007,
+0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
+0x621825, 0x10600005, 0x0, 0xc00429b,
+0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
+0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
+0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
+0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
+0x0, 0x8f820220, 0x3c030400, 0x431024,
+0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
+0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
+0x0, 0x3c020001, 0x8c427de0, 0x24420001,
+0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
+0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
+0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
+0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
+0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
+0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
+0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
+0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
+0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
+0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
+0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
+0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
+0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
+0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
+0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
+0x220821, 0x8c225b80, 0x400008, 0x0,
+0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
+0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
+0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
+0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
+0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
+0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
+0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
+0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
+0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
+0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
+0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
+0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
+0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
+0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
+0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
+0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
+0x431024, 0xaee20000, 0x8f820204, 0x30420030,
+0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
+0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
+0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
+0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
+0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
+0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
+0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
+0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
+0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
+0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
+0x0, 0x3c010001, 0xac227e08, 0x24020003,
+0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
+0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
+0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
+0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
+0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
+0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
+0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
+0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
+0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
+0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
+0x641824, 0x10430004, 0x24020001, 0x3c010001,
+0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
+0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
+0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
+0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
+0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
+0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
+0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
+0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
+0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
+0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
+0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
+0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
+0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
+0x0, 0x3c020001, 0x8c427e00, 0x10400005,
+0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
+0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
+0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
+0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
+0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
+0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
+0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
+0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
+0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
+0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
+0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
+0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
+0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
+0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
+0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
+0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
+0x8c427e10, 0x10400005, 0x0, 0x2402000c,
+0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
+0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
+0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
+0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
+0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
+0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
+0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
+0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x1440003a, 0x0, 0x3c020001,
+0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
+0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
+0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
+0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
+0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
+0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
+0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
+0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
+0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
+0x8c427e00, 0x10400005, 0x0, 0x3c020001,
+0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
+0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
+0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
+0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
+0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
+0x3c020001, 0x8c427e00, 0x10400003, 0x0,
+0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
+0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
+0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
+0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
+0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
+0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
+0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
+0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
+0x24020030, 0x30822000, 0x1040005d, 0x30838000,
+0x31a02, 0x30820001, 0x21200, 0x3c040001,
+0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
+0x24635d78, 0x30828000, 0x21202, 0x30840001,
+0x42200, 0x441025, 0x239c2, 0x61080,
+0x431021, 0x471021, 0x90430000, 0x24020001,
+0x10620025, 0x0, 0x10600007, 0x24020002,
+0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
+0x80050f9, 0x0, 0x8f820200, 0x2403feff,
+0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
+0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
+0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
+0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
+0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
+0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
+0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x24020100, 0x3c010001,
+0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
+0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
+0xc002403, 0xafa00014, 0x8005104, 0x0,
+0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
+0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
+0x24020002, 0x12620083, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x800529b,
+0x0, 0x24020004, 0x126200fa, 0x24020008,
+0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
+0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
+0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010001, 0x310821,
+0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
+0x310821, 0xac207e40, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x800515c, 0xac227e48, 0x121140,
+0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
+0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
+0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
+0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
+0x24040001, 0x2821, 0xc00498e, 0x27a60018,
+0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
+0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
+0x0, 0x32028000, 0x1040011f, 0x0,
+0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
+0x24020005, 0x10620118, 0x24020002, 0x3c010001,
+0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
+0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
+0x2003021, 0x24040001, 0x2821, 0xc00498e,
+0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
+0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
+0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
+0x310821, 0x109300fa, 0xac227e34, 0x800529b,
+0x0, 0x3c022000, 0x2021024, 0x10400005,
+0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
+0x128940, 0x3c010001, 0xac205d98, 0x128940,
+0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
+0x2021024, 0x14400016, 0x0, 0x3c020001,
+0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
+0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
+0x370821, 0xac2283ac, 0x3c020001, 0x511021,
+0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
+0x3c010001, 0x310821, 0x8005299, 0xac227e30,
+0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
+0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
+0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
+0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
+0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
+0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
+0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
+0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
+0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
+0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
+0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
+0x2021024, 0x10400006, 0x24020100, 0x3c010001,
+0x310821, 0xac227e44, 0x8005201, 0x3c020080,
+0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
+0x2021024, 0x10400007, 0x121940, 0x3c020001,
+0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
+0x24040001, 0x121140, 0x3c010001, 0x220821,
+0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
+0xc00494c, 0x2003021, 0x24040001, 0x2821,
+0xc00494c, 0x2003021, 0x24040001, 0x24050001,
+0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
+0x24050001, 0xc00494c, 0x2003021, 0x8005299,
+0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
+0x3c020008, 0x2028025, 0x121140, 0x3c010001,
+0x220821, 0xac307e38, 0x3c022000, 0x2021024,
+0x10400009, 0x0, 0x3c020001, 0x8c425d74,
+0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
+0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
+0x3c024000, 0x2021024, 0x1440001e, 0x0,
+0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
+0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
+0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
+0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
+0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
+0x441024, 0x3c010001, 0x230821, 0xac227e30,
+0x24020001, 0x10a20044, 0x0, 0x8005299,
+0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
+0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
+0x2031024, 0x14430005, 0x121140, 0x3402a000,
+0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
+0x621821, 0x8c637e38, 0x3c020020, 0x621024,
+0x10400004, 0x24022001, 0x3c010001, 0x8005294,
+0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
+0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
+0x3c020020, 0x2021024, 0x10400007, 0x121940,
+0x24020100, 0x3c010001, 0x230821, 0xac227e44,
+0x8005288, 0x3c020080, 0x121140, 0x3c010001,
+0x220821, 0xac207e44, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x8005294, 0xac227e4c, 0x121140,
+0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
+0x8c635cc8, 0x24020001, 0x10620003, 0x0,
+0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
+0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
+0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
+0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
+0x128140, 0x8005380, 0x2201021, 0x24020004,
+0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
+0x8005380, 0x2201021, 0x3c030001, 0x701821,
+0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
+0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
+0x3c010001, 0x300821, 0xac317e34, 0x8005380,
+0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
+0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
+0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
+0x10400034, 0x31080, 0x3c010001, 0x220821,
+0x8c225be0, 0x400008, 0x0, 0x24040001,
+0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
+0x24040001, 0x24050011, 0xc00494c, 0x2003021,
+0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
+0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
+0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
+0x2003021, 0x24040001, 0x24050014, 0xc00494c,
+0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
+0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
+0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
+0x641825, 0x800530e, 0x438825, 0x3c110001,
+0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
+0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
+0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
+0x3c022000, 0x2228825, 0x121140, 0x3c010001,
+0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
+0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
+0x2228824, 0x121140, 0x3c010001, 0x220821,
+0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
+0x121140, 0x3c010001, 0x220821, 0xac317e34,
+0x8005380, 0x2201021, 0x122940, 0x3c030001,
+0x651821, 0x8c637e38, 0x3c024000, 0x621024,
+0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
+0x3c010001, 0x250821, 0xac317e30, 0x8005380,
+0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
+0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
+0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
+0x21023, 0x441024, 0x10600003, 0x518825,
+0x3c022000, 0x2228825, 0x3c020001, 0x451021,
+0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
+0x10400003, 0x3c020080, 0x8005368, 0x2228825,
+0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
+0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
+0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
+0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
+0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
+0x3442ffff, 0x628824, 0x121140, 0x3c010001,
+0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
+0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
+0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
+0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
+0x10400005, 0x24020001, 0x1062000a, 0x141940,
+0x8005448, 0x0, 0x24020004, 0x1062005a,
+0x24020008, 0x10620059, 0x149140, 0x8005448,
+0x0, 0x3c040001, 0x832021, 0x8c847e3c,
+0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
+0x821024, 0x1040003e, 0x3c020008, 0x2221024,
+0x10400020, 0x36100002, 0x3c020001, 0x431021,
+0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
+0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
+0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x141140, 0x3c010001, 0x220821, 0x8c227e48,
+0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
+0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
+0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
+0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
+0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
+0x2228824, 0x3c010001, 0x230821, 0xac207e40,
+0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
+0x0, 0xaf900200, 0xaf930220, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x34420002, 0xaf820220, 0x80053f3, 0x141140,
+0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+0x2228824, 0x141140, 0x3c010001, 0x220821,
+0x8005448, 0xac317e34, 0x149140, 0x3c040001,
+0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
+0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
+0x0, 0x3c020001, 0x8c425d98, 0x14400006,
+0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+0x2228824, 0x3c010001, 0x320821, 0x8005448,
+0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
+0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
+0x3c020020, 0x821024, 0x10400007, 0x36100020,
+0x24020100, 0x3c010001, 0x320821, 0xac227e44,
+0x8005428, 0x36100100, 0x3c010001, 0x320821,
+0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
+0x821024, 0x10400007, 0x141940, 0x3c020001,
+0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
+0x2629825, 0x141140, 0x3c010001, 0x220821,
+0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
+0xc00486a, 0x0, 0xaf900200, 0xaf930220,
+0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
+0x8f820220, 0x34420002, 0xaf820220, 0x141140,
+0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
+0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
+static u_int32_t tigonFwRodata[] = {
+0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
+0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
+0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
+0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
+0x0, 0x53544143, 0x4b5f3120, 0x0,
+0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
+0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
+0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
+0x6d000000, 0x52656376, 0x566c616e, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
+0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
+0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
+0x70202400, 0x542d446d, 0x61526431, 0x0,
+0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
+0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
+0x64527845, 0x0, 0x656e714d, 0x45765046,
+0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
+0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
+0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+0x6576526e, 0x6746756c, 0x6c000000, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
+0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
+0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
+0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
+0x0, 0x4e4f636f, 0x6d616e64, 0x0,
+0x68737465, 0x5f455252, 0x0, 0x412d4572,
+0x72427563, 0x0, 0x4552524f, 0x522d4164,
+0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
+0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+0x456e454d, 0x0, 0x442d4572, 0x724c6173,
+0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
+0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
+0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
+0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
+0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
+0x6746756c, 0x6c000000, 0x0, 0x6ea0,
+0x7fbc, 0x6e38, 0x8734, 0x82b0,
+0x8780, 0x8780, 0x6f54, 0x7694,
+0x7f0c, 0x80a8, 0x8074, 0x8780,
+0x7e70, 0x80cc, 0x6e64, 0x81cc,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
+0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
+0x24000000, 0x646d6172, 0x6441544e, 0x0,
+0x646d6177, 0x7241544e, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
+0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
+0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
+0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
+0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
+0x23312046, 0x72692041, 0x70722037, 0x2031373a,
+0x35353a34, 0x38205044, 0x54203230, 0x30300000,
+0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
+0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
+0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
+0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
+0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
+0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
+0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
+0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
+0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
+0x2e320000, 0x0, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
+0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
+0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
+0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
+0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
+0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
+0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
+0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
+0x0, 0x756e6b72, 0x64747970, 0x65000000,
+0x0, 0xaccc, 0xaccc, 0xad9c,
+0xaab0, 0xaab0, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad7c,
+0x0, 0xbca8, 0xbca8, 0xbd70,
+0xae4c, 0xb058, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd54,
+0xb040, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
+0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
+0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
+0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
+0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
+0x0, 0x72785144, 0x6d614446, 0x0,
+0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
+0x64527845, 0x0, 0x706b5278, 0x45525273,
+0x0, 0x66726d32, 0x4c726753, 0x0,
+0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
+0x0, 0x3f724a42, 0x64446d46, 0x0,
+0x0, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf670, 0xf670, 0xf670, 0x572d444d,
+0x41456e46, 0x0, 0x0, 0xfdc0,
+0x1015c, 0xfddc, 0x1015c, 0x1015c,
+0x1015c, 0x1015c, 0x1015c, 0x1015c,
+0xf704, 0x1015c, 0x1015c, 0x1015c,
+0x1015c, 0x1015c, 0x10154, 0x10154,
+0x10154, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
+0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
+0x20240000, 0x6d616374, 0x7841544e, 0x0,
+0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
+0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
+0x0, 0x656e714d, 0x45765046, 0x61696c00,
+0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
+0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
+0x70202400, 0x50726f62, 0x65506879, 0x0,
+0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
+0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
+0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
+0x11e24, 0x11e50, 0x11e90, 0x11ec0,
+0x11efc, 0x11f30, 0x1207c, 0x122c0,
+0x122d8, 0x12300, 0x12320, 0x12348,
+0x12478, 0x124a0, 0x124f4, 0x1251c,
+0x0, 0x1278c, 0x1285c, 0x12934,
+0x12a04, 0x12a60, 0x12b3c, 0x12b64,
+0x12c40, 0x12c68, 0x12e10, 0x12e38,
+0x12fe0, 0x131d8, 0x1346c, 0x13380,
+0x1346c, 0x13498, 0x13008, 0x131b0,
+0x0, 0x13b84, 0x13bc8, 0x13c60,
+0x13cac, 0x13d1c, 0x13db4, 0x13de8,
+0x13e70, 0x13f08, 0x13fd8, 0x14018,
+0x1409c, 0x140c0, 0x141f4, 0x646f4261,
+0x73655067, 0x0, 0x0, 0x0,
+0x0, 0x73746d61, 0x634c4e4b, 0x0,
+0x0, 0x14c38, 0x14c38, 0x14b80,
+0x14bc4, 0x14c38, 0x14c38, 0x0,
+0x0, 0x0 };
+static u_int32_t tigonFwData[] = {
+0x416c7465,
+0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
+0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
+0x0, 0x0, 0x0, 0x135418,
+0x13e7fc, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x60cf00,
+0x60, 0xcf000000, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x3, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x1, 0x0,
+0x0, 0x0, 0x0, 0x1,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x1000000, 0x21000000,
+0x12000140, 0x0, 0x0, 0x20000000,
+0x120000a0, 0x0, 0x12000060, 0x12000180,
+0x120001e0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2,
+0x0, 0x0, 0x30001, 0x1,
+0x30201, 0x0, 0x0, 0x0 };
diff --git a/sys/pci/ti_fw2.h b/sys/pci/ti_fw2.h
new file mode 100644
index 0000000..e54c920
--- /dev/null
+++ b/sys/pci/ti_fw2.h
@@ -0,0 +1,5232 @@
+/*
+ * Generated by Ken's special genfw.c
+ * Built on Wed Aug 2 17:21:09 MDT 2000 by ken@roadwarrior.plutotech.com
+ * OS: FreeBSD 5.0-CURRENT
+ * $FreeBSD$
+ */
+static int tigon2FwReleaseMajor = 0xc;
+static int tigon2FwReleaseMinor = 0x4;
+static int tigon2FwReleaseFix = 0xb;
+static u_int32_t tigon2FwStartAddr = 0x00004000;
+static u_int32_t tigon2FwTextAddr = 0x00004000;
+int tigon2FwTextLen = 0x132f8;
+static u_int32_t tigon2FwRodataAddr = 0x000172f8;
+int tigon2FwRodataLen = 0x10da;
+static u_int32_t tigon2FwDataAddr = 0x000185c0;
+int tigon2FwDataLen = 0x17c;
+static u_int32_t tigon2FwSbssAddr = 0x0001873c;
+int tigon2FwSbssLen = 0xcc;
+static u_int32_t tigon2FwBssAddr = 0x00018810;
+int tigon2FwBssLen = 0x20c0;
+static u_int32_t tigon2FwText[] = {
+0x0,
+0x10000003, 0x0, 0xd, 0xd,
+0x3c1d0002, 0x8fbd8600, 0x3a0f021, 0x3c100000,
+0x26104000, 0xc001082, 0x0, 0xd,
+0x3c1d0002, 0x8fbd8604, 0x3a0f021, 0x3c100000,
+0x26104000, 0xc0018cc, 0x0, 0xd,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2000008,
+0x0, 0x80017d9, 0x3c0a0001, 0x80017d9,
+0x3c0a0002, 0x80017d9, 0x0, 0x8002ec4,
+0x0, 0x8002e4e, 0x0, 0x80017d9,
+0x3c0a0004, 0x80035a3, 0x0, 0x8001b5a,
+0x0, 0x8003df3, 0x0, 0x8003d81,
+0x0, 0x80017d9, 0x3c0a0006, 0x8003e7a,
+0x3c0a0007, 0x80017d9, 0x3c0a0008, 0x80017d9,
+0x3c0a0009, 0x8003eeb, 0x0, 0x80030d9,
+0x0, 0x80017d9, 0x3c0a000b, 0x80017d9,
+0x3c0a000c, 0x80017d9, 0x3c0a000d, 0x8002af6,
+0x0, 0x8002a8a, 0x0, 0x80017d9,
+0x3c0a000e, 0x800219b, 0x0, 0x8001a69,
+0x0, 0x8001b0b, 0x0, 0x80041cb,
+0x0, 0x80041b9, 0x0, 0x80017d9,
+0x0, 0x8001a1f, 0x0, 0x80017d9,
+0x0, 0x80017d9, 0x3c0a0013, 0x80017d9,
+0x3c0a0014, 0x27bdffe0, 0x3c1cc000, 0xafbf001c,
+0xafb00018, 0x8f820140, 0x24030003, 0xaf8300ec,
+0x34420004, 0xaf820140, 0xc002d20, 0x0,
+0x3c0100c0, 0xac203ffc, 0xc00184f, 0x0,
+0x401821, 0x3c020010, 0x3c010002, 0xac238758,
+0x10620025, 0x43102b, 0x14400002, 0x3c020020,
+0x3c020008, 0x10620020, 0x24050100, 0x3c040001,
+0x248473ac, 0x3c060002, 0x8cc68758, 0x3821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x3c040001,
+0x248473b8, 0x24020256, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f830140,
+0x3c020020, 0x3c010002, 0xac228758, 0x3c020001,
+0x621825, 0xaf830140, 0x24020008, 0x3c010002,
+0xac228770, 0x2402001f, 0x3c010002, 0xac228780,
+0x24020016, 0x3c010002, 0xac228754, 0x3c05fffe,
+0x34a56f08, 0x3c020002, 0x8c428758, 0x3c030002,
+0x2463a8d0, 0x3c040002, 0x8c8485c4, 0x431023,
+0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
+0x2028024, 0xc001871, 0x2002021, 0x2022823,
+0x3c040020, 0x821823, 0x651823, 0x247bb000,
+0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
+0x34c6f000, 0x3c070002, 0x8ce785c0, 0x3c0300bf,
+0x3463e000, 0x852023, 0x3c010002, 0xac248764,
+0x822023, 0x3c010002, 0xac25874c, 0x52842,
+0x3c010002, 0xac228740, 0x27620ffc, 0x3c010002,
+0xac228600, 0x27621ffc, 0xdb3023, 0x7b1823,
+0x3c010002, 0xac248744, 0x3c010002, 0xac258768,
+0x3c010002, 0xac228604, 0xaf860150, 0xaf830250,
+0x10e00027, 0x33620fff, 0x10400014, 0x2402028b,
+0x3c040001, 0x248473b8, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x3c1d0002,
+0x8fbd85cc, 0x3a0f021, 0xc001807, 0x0,
+0x3c020002, 0x8c4285d0, 0x3c030002, 0x8c6385d4,
+0x2442fe00, 0x24630200, 0x3c010002, 0xac2285d0,
+0x3c010002, 0xac2385d4, 0x10000004, 0x0,
+0x3c1d0002, 0x8fbd8600, 0x3a0f021, 0x3c020002,
+0x8c4285c4, 0x1040000d, 0x26fafa38, 0x3c020002,
+0x8c4285d0, 0x3c030002, 0x8c6385d4, 0x3c1a0002,
+0x8f5a85d4, 0x2442fa38, 0x246305c8, 0x3c010002,
+0xac2285d0, 0x3c010002, 0xac2385d4, 0x3c020002,
+0x8c4285c8, 0x14400003, 0x0, 0x3c010002,
+0xac2085d0, 0xc001140, 0x0, 0x8fbf001c,
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x3c020002,
+0x8c4285d0, 0x3c030002, 0x8c6385d4, 0x27bdff98,
+0xafb00048, 0x3c100001, 0x8e107d5c, 0xafb20050,
+0x3c120000, 0x26524100, 0xafbf0060, 0xafbe005c,
+0xafb50058, 0xafb30054, 0xafb1004c, 0xafa20034,
+0xafa30030, 0xafa00010, 0xafa00014, 0x8f860040,
+0x3c040001, 0x248473cc, 0x24050200, 0x3c010002,
+0xac32873c, 0xc002d3b, 0x2003821, 0x8f830040,
+0x3c02f000, 0x621824, 0x3c026000, 0x1062001f,
+0xa3a0003f, 0x3c040001, 0x248473d4, 0xafa00010,
+0xafa00014, 0x8f860040, 0x24050300, 0xc002d3b,
+0x2003821, 0x3c040001, 0x248473b8, 0x240202e1,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e773c0, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x240e0001, 0x3c030001,
+0xa3ae003f, 0x431025, 0xaf820140, 0x8f820240,
+0x3c030001, 0x431025, 0xaf820240, 0xaf800048,
+0x8f820048, 0x14400005, 0x0, 0xaf800048,
+0x8f820048, 0x10400004, 0x0, 0xaf800048,
+0x10000003, 0x2e02021, 0xaf80004c, 0x2e02021,
+0x3c050001, 0xc002da8, 0x34a540f8, 0x3402021,
+0xc002da8, 0x240505c8, 0x3c020002, 0x8c428764,
+0x3c0d0002, 0x8dad8744, 0x3c030002, 0x8c638740,
+0x3c080002, 0x8d08874c, 0x3c090002, 0x8d298768,
+0x3c0a0002, 0x8d4a8770, 0x3c0b0002, 0x8d6b8780,
+0x3c0c0002, 0x8d8c8754, 0x3c040001, 0x248473e0,
+0x24050400, 0xaf42013c, 0x8f42013c, 0x24060001,
+0x24070001, 0xaf400000, 0xaf4d0138, 0xaf430144,
+0xaf480148, 0xaf49014c, 0xaf4a0150, 0xaf4b0154,
+0xaf4c0158, 0x2442ff80, 0xaf420140, 0x24020001,
+0xafa20010, 0xc002d3b, 0xafa00014, 0x8f420138,
+0xafa20010, 0x8f42013c, 0xafa20014, 0x8f460144,
+0x8f470148, 0x3c040001, 0x248473ec, 0xc002d3b,
+0x24050500, 0xafb70010, 0xafba0014, 0x8f46014c,
+0x8f470150, 0x3c040001, 0x248473f8, 0xc002d3b,
+0x24050600, 0x3c020002, 0x8c428758, 0x3603821,
+0x3c060002, 0x24c6a8d0, 0x2448ffff, 0x1061824,
+0xe81024, 0x43102b, 0x1040001a, 0x24050900,
+0x3c040001, 0x24847404, 0xafa80010, 0xc002d3b,
+0xafa00014, 0x3c040001, 0x248473b8, 0x2402033a,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e773c0, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x8f82000c, 0xafa20010, 0x8f82003c,
+0xafa20014, 0x8f860000, 0x8f870004, 0x3c040001,
+0x24847410, 0xc002d3b, 0x24051000, 0x8c020220,
+0x8c030224, 0x8c060218, 0x8c07021c, 0x3c040001,
+0x24847418, 0x24051100, 0xafa20010, 0xc002d3b,
+0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218,
+0x30420002, 0x10400009, 0x0, 0x8c020220,
+0x3c030002, 0x34630004, 0x431025, 0xaf42000c,
+0x8c02021c, 0x10000008, 0x34420004, 0x8c020220,
+0x3c030002, 0x34630006, 0x431025, 0xaf42000c,
+0x8c02021c, 0x34420006, 0xaf420014, 0x8c020218,
+0x30420010, 0x1040000a, 0x0, 0x8c02021c,
+0x34420004, 0xaf420010, 0x8c020220, 0x3c03000a,
+0x34630004, 0x431025, 0x10000009, 0xaf420008,
+0x8c020220, 0x3c03000a, 0x34630006, 0x431025,
+0xaf420008, 0x8c02021c, 0x34420006, 0xaf420010,
+0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
+0x8f820054, 0xaf8000d0, 0xaf8000c0, 0x10000002,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x0, 0x8c040208, 0x8c05020c,
+0x26e20028, 0xaee20020, 0x24020490, 0xaee20010,
+0xaee40008, 0xaee5000c, 0x26e40008, 0x8c820000,
+0x8c830004, 0xaf820090, 0xaf830094, 0x8c820018,
+0xaf8200b4, 0x9482000a, 0xaf82009c, 0x8f420014,
+0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
+0x0, 0x8f8200b0, 0x3c03ef00, 0x431024,
+0x10400021, 0x0, 0x8f8200b4, 0xafa20010,
+0x8f820090, 0x8f830094, 0x3c040001, 0x24847420,
+0xafa30014, 0x8f8600b0, 0x8f87009c, 0x3c050001,
+0xc002d3b, 0x34a5200d, 0x3c040001, 0x248473b8,
+0x240203c4, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x96e20472, 0x96e60452,
+0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001,
+0x2484742c, 0x24051200, 0xc002d3b, 0xafa20014,
+0x96f00452, 0x32020001, 0x10400002, 0xb021,
+0x24160001, 0x32020002, 0x54400001, 0x36d60002,
+0x32020008, 0x54400001, 0x36d60004, 0x32020010,
+0x54400001, 0x36d60008, 0x32020020, 0x54400001,
+0x36d60010, 0x32020040, 0x54400001, 0x36d60020,
+0x32020080, 0x54400001, 0x36d60040, 0x96e60482,
+0x30c20200, 0x54400001, 0x36d64000, 0x96e30472,
+0x30620200, 0x10400003, 0x30620100, 0x10000003,
+0x36d62000, 0x54400001, 0x36d61000, 0x96f00462,
+0x32c24000, 0x14400004, 0x3207009b, 0x30c2009b,
+0x14e20007, 0x0, 0x32c22000, 0x14400022,
+0x32020001, 0x3062009b, 0x10e2001f, 0x32020001,
+0x3c040001, 0x24847438, 0x24051300, 0x2003821,
+0xafa30010, 0xc002d3b, 0xafa00014, 0x3c040001,
+0x248473b8, 0x24020400, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x240e0001, 0x3c030001, 0xa3ae003f, 0x431025,
+0xaf820140, 0x32020001, 0x54400001, 0x36d60080,
+0x32020002, 0x54400001, 0x36d60100, 0x32020008,
+0x54400001, 0x36d60200, 0x32020010, 0x54400001,
+0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
+0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
+0x2c2b025, 0x8c020218, 0x30428000, 0x10400002,
+0x3c021000, 0x2c2b025, 0x8c020218, 0x30420800,
+0x10400002, 0x3c020080, 0x2c2b025, 0x8c020218,
+0x30420400, 0x10400002, 0x3c020100, 0x2c2b025,
+0x8c020218, 0x30420100, 0x10400002, 0x3c020200,
+0x2c2b025, 0x8c020218, 0x30420080, 0x10400002,
+0x3c020400, 0x2c2b025, 0x8c020218, 0x30422000,
+0x10400002, 0x3c020010, 0x2c2b025, 0x8c020218,
+0x30424000, 0x10400002, 0x3c020020, 0x2c2b025,
+0x8c020218, 0x30421000, 0x10400002, 0x3c020040,
+0x2c2b025, 0x8ee20498, 0x8ee3049c, 0xaf420160,
+0xaf430164, 0x8ee204a0, 0x8ee304a4, 0xaf420168,
+0xaf43016c, 0x8ee204a8, 0x8ee304ac, 0xaf420170,
+0xaf430174, 0x8ee20428, 0x8ee3042c, 0xaf420178,
+0xaf43017c, 0x8ee20448, 0x8ee3044c, 0xaf420180,
+0xaf430184, 0x8ee20458, 0x8ee3045c, 0xaf420188,
+0xaf43018c, 0x8ee20468, 0x8ee3046c, 0xaf420190,
+0xaf430194, 0x8ee20478, 0x8ee3047c, 0xaf420198,
+0xaf43019c, 0x8ee20488, 0x8ee3048c, 0xaf4201a0,
+0xaf4301a4, 0x8ee204b0, 0x8ee304b4, 0x24040080,
+0xaf4201a8, 0xaf4301ac, 0xc002da8, 0x24050080,
+0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+0x24050200, 0x24060008, 0xaf4201f8, 0xc002dbf,
+0x0, 0x3c043b9a, 0x3484ca00, 0x3821,
+0x24020006, 0x24030002, 0xaf4201f4, 0x240203e8,
+0xaf430204, 0xaf430200, 0xaf4401fc, 0xaf420294,
+0x24020001, 0xaf430290, 0xaf42029c, 0x3c030002,
+0x671821, 0x906385d8, 0x3471021, 0x24e70001,
+0xa043022c, 0x2ce2000f, 0x1440fff8, 0x3471821,
+0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040,
+0x3c040001, 0x24847444, 0x24051400, 0x21702,
+0x24420030, 0xa062022c, 0x3471021, 0xa040022c,
+0x8c070218, 0x2c03021, 0x240205c8, 0xafa20010,
+0xc002d3b, 0xafa80014, 0x3c040001, 0x24847450,
+0x3c050000, 0x24a55f28, 0x24060010, 0x27b10030,
+0x2203821, 0x27b30034, 0xc00188f, 0xafb30010,
+0x3c030002, 0x8c6385c8, 0x1060000a, 0x408021,
+0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff,
+0x852024, 0x831823, 0x431023, 0xafa20034,
+0xafa40030, 0x3c040001, 0x2484745c, 0x3c050000,
+0x24a54100, 0x24060108, 0x2203821, 0xc00188f,
+0xafb30010, 0x409021, 0x32c20003, 0x3c010002,
+0xac32873c, 0x10400059, 0x2203821, 0x8f820050,
+0x3c030010, 0x431024, 0x1040002a, 0x0,
+0x8c020218, 0x30420040, 0x10400023, 0x24020001,
+0x8f820050, 0x8c030218, 0x3c040001, 0x24847468,
+0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
+0xc002d3b, 0x2c03021, 0x3c040001, 0x248473b8,
+0x24020474, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x240e0001,
+0x3c030001, 0xa3ae003f, 0x431025, 0xaf820140,
+0x10000004, 0x0, 0x3c010001, 0x370821,
+0xa02240f4, 0x3c040001, 0x24847474, 0x3c050001,
+0x24a5a8fc, 0x3c060001, 0x24c6aa20, 0xc53023,
+0x8f420010, 0x27b30030, 0x2603821, 0x27b10034,
+0x34420a00, 0xaf420010, 0xc00188f, 0xafb10010,
+0x3c040001, 0x24847488, 0x3c050001, 0x24a5bfd4,
+0x3c060001, 0x24c6c35c, 0xc53023, 0x2603821,
+0xaf420108, 0xc00188f, 0xafb10010, 0x3c040001,
+0x248474a4, 0x3c050001, 0x24a5c7fc, 0x3c060001,
+0x24c6d53c, 0xc53023, 0x2603821, 0x3c010002,
+0xac2287b0, 0xc00188f, 0xafb10010, 0x3c040001,
+0x248474bc, 0x10000024, 0x24051600, 0x3c040001,
+0x248474c4, 0x3c050001, 0x24a5a744, 0x3c060001,
+0x24c6a8f4, 0xc53023, 0xc00188f, 0xafb30010,
+0x3c040001, 0x248474d4, 0x3c050001, 0x24a5bb10,
+0x3c060001, 0x24c6bfcc, 0xc53023, 0x2203821,
+0xaf420108, 0xc00188f, 0xafb30010, 0x3c040001,
+0x248474e8, 0x3c050001, 0x24a5c364, 0x3c060001,
+0x24c6c7f4, 0xc53023, 0x2203821, 0x3c010002,
+0xac2287b0, 0xc00188f, 0xafb30010, 0x3c040001,
+0x248474fc, 0x24051650, 0x2c03021, 0x3821,
+0x3c010002, 0xac2287b4, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x32c20020, 0x10400021, 0x27a70030,
+0x3c040001, 0x24847508, 0x3c050001, 0x24a5b938,
+0x3c060001, 0x24c6bb08, 0xc53023, 0x24022000,
+0xaf42001c, 0x27a20034, 0xc00188f, 0xafa20010,
+0x21900, 0x31982, 0x3c040800, 0x641825,
+0xae430028, 0x24030010, 0xaf43003c, 0x96e30450,
+0xaf430040, 0x8f430040, 0x3c040001, 0x2484751c,
+0xafa00014, 0xafa30010, 0x8f47001c, 0x24051660,
+0x3c010002, 0xac2287ac, 0x10000039, 0x32c60020,
+0x8ee20448, 0x8ee3044c, 0xaf43001c, 0x8f42001c,
+0x2442e000, 0x2c422001, 0x1440001e, 0x24051700,
+0x3c040001, 0x24847528, 0xafa00010, 0xafa00014,
+0x8f46001c, 0xc002d3b, 0x3821, 0x3c040001,
+0x248473b8, 0x240204dd, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x240e0001, 0x3c030001, 0xa3ae003f, 0x431025,
+0xaf820140, 0x3c020000, 0x24425f64, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0xae420028,
+0x24020008, 0xaf42003c, 0x96e20450, 0xaf420040,
+0x8f420040, 0x3c040001, 0x24847534, 0xafa00014,
+0xafa20010, 0x8f47001c, 0x24051800, 0x32c60020,
+0xc002d3b, 0x0, 0x3c050fff, 0x3c030002,
+0x8c6387b0, 0x34a5ffff, 0x2403021, 0x3c020002,
+0x8c4287b4, 0x3c040800, 0x651824, 0x31882,
+0x641825, 0x451024, 0x21082, 0x441025,
+0xacc20080, 0x32c20180, 0x1040007e, 0xacc30020,
+0x8f82005c, 0x3c030080, 0x431024, 0x10400021,
+0x0, 0x8f820050, 0xafa20010, 0x8f82005c,
+0x3c040001, 0x24847540, 0xafa20014, 0x8f870040,
+0x24051900, 0xc002d3b, 0x2c03021, 0x3c040001,
+0x248473b8, 0x240204fe, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x240e0001, 0x3c030001, 0xa3ae003f, 0x431025,
+0xaf820140, 0x8f820050, 0x3c030010, 0x431024,
+0x1040002a, 0x0, 0x8c020218, 0x30420040,
+0x10400023, 0x24020001, 0x8f820050, 0x8c030218,
+0x3c040001, 0x24847468, 0xafa20010, 0xafa30014,
+0x8f870040, 0x24052000, 0xc002d3b, 0x2c03021,
+0x3c040001, 0x248473b8, 0x2402050c, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e773c0,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x240e0001, 0x3c030001, 0xa3ae003f,
+0x431025, 0xaf820140, 0x10000004, 0x0,
+0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
+0x2484754c, 0x3c050001, 0x24a5a60c, 0x3c060001,
+0x24c6a73c, 0xc53023, 0x8f420008, 0x27b30030,
+0x2603821, 0x27b10034, 0x34420e00, 0xaf420008,
+0xc00188f, 0xafb10010, 0x3c040001, 0x24847564,
+0x3c050001, 0x24a5e844, 0x3c060001, 0x24c6f5fc,
+0xc53023, 0x2603821, 0xaf42010c, 0xc00188f,
+0xafb10010, 0x3c040001, 0x2484757c, 0x3c050001,
+0x24a5fde8, 0x3c060001, 0x24c60588, 0xc53023,
+0x2603821, 0x3c010002, 0xac2287c0, 0xc00188f,
+0xafb10010, 0x3c040001, 0x24847594, 0x10000027,
+0x24052100, 0x3c040001, 0x2484759c, 0x3c050001,
+0x24a5a444, 0x3c060001, 0x24c6a604, 0xc53023,
+0x27b10030, 0x2203821, 0x27b30034, 0xc00188f,
+0xafb30010, 0x3c040001, 0x248475ac, 0x3c050001,
+0x24a5d738, 0x3c060001, 0x24c6e83c, 0xc53023,
+0x2203821, 0xaf42010c, 0xc00188f, 0xafb30010,
+0x3c040001, 0x248475bc, 0x3c050001, 0x24a5fbac,
+0x3c060001, 0x24c6fde0, 0xc53023, 0x2203821,
+0x3c010002, 0xac2287c0, 0xc00188f, 0xafb30010,
+0x3c040001, 0x248475d0, 0x24052150, 0x2c03021,
+0x3821, 0x3c010002, 0xac2287cc, 0xafa00010,
+0xc002d3b, 0xafa00014, 0x3c110fff, 0x3c030002,
+0x8c6387c0, 0x3631ffff, 0x2409821, 0x3c020002,
+0x8c4287cc, 0x3c0e0800, 0x711824, 0x31882,
+0x6e1825, 0x511024, 0x21082, 0x4e1025,
+0xae630038, 0xae620078, 0x8c020218, 0x30420040,
+0x14400004, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f4, 0x3c040001, 0x248475dc, 0x3c050001,
+0x24a5f604, 0x3c060001, 0x24c6f7c4, 0xc53023,
+0x27be0030, 0x3c03821, 0x27b50034, 0xc00188f,
+0xafb50010, 0x3c010002, 0xac2287b8, 0x511024,
+0x21082, 0x3c0e0800, 0x4e1025, 0xae620050,
+0x32c22000, 0x10400006, 0x3c03821, 0x3c020000,
+0x24425f64, 0x2221024, 0x1000000f, 0x21082,
+0x3c040001, 0x248475f0, 0x3c050001, 0x24a5f7cc,
+0x3c060001, 0x24c6f9e0, 0xc53023, 0xc00188f,
+0xafb50010, 0x3c010002, 0xac2287d0, 0x511024,
+0x21082, 0x3c0e0800, 0x4e1025, 0xae620048,
+0x32c24000, 0x10400005, 0x27a70030, 0x3c020000,
+0x24425f64, 0x1000000e, 0x21100, 0x3c040001,
+0x24847608, 0x3c050001, 0x24a5f9e8, 0x3c060001,
+0x24c6fba4, 0xc53023, 0x27a20034, 0xc00188f,
+0xafa20010, 0x3c010002, 0xac2287c4, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0xae420060,
+0x3c040001, 0x24847620, 0x3c050001, 0x24a5866c,
+0x3c060001, 0x24c68aac, 0xc53023, 0x27b10030,
+0x2203821, 0x27b30034, 0xc00188f, 0xafb30010,
+0x3c0e0fff, 0x35ceffff, 0x3c040001, 0x2484762c,
+0x3c050000, 0x24a5687c, 0x3c060000, 0x24c6699c,
+0xc53023, 0x2203821, 0x240f021, 0x3c010002,
+0xac228798, 0x4e1024, 0x21082, 0x3c150800,
+0x551025, 0xafae0044, 0xafc200b8, 0xc00188f,
+0xafb30010, 0x3c040001, 0x24847638, 0x3c050000,
+0x24a569a4, 0x3c060000, 0x24c66c24, 0x8fae0044,
+0xc53023, 0x2203821, 0x3c010002, 0xac22878c,
+0x4e1024, 0x21082, 0x551025, 0xafc200e8,
+0xc00188f, 0xafb30010, 0x3c040001, 0x24847650,
+0x3c050000, 0x24a56c2c, 0x3c060000, 0x24c66d60,
+0x8fae0044, 0xc53023, 0x2203821, 0x3c010002,
+0xac228784, 0x4e1024, 0x21082, 0x551025,
+0xafc200c0, 0xc00188f, 0xafb30010, 0x3c040001,
+0x24847668, 0x3c050001, 0x24a51034, 0x3c060001,
+0x24c6110c, 0x8fae0044, 0xc53023, 0x2203821,
+0x3c010002, 0xac228790, 0x4e1024, 0x21082,
+0x551025, 0xafc200c8, 0xc00188f, 0xafb30010,
+0x3c040001, 0x24847674, 0x3c050001, 0x24a5d570,
+0x3c060001, 0x24c6d654, 0xc53023, 0x2203821,
+0xaf420110, 0xc00188f, 0xafb30010, 0x3c040001,
+0x24847684, 0x3c050001, 0x24a5d544, 0x3c060001,
+0x24c6d568, 0xc53023, 0x2203821, 0xaf420124,
+0xc00188f, 0xafb30010, 0x3c040001, 0x24847694,
+0x3c050001, 0x24a5d65c, 0x3c060001, 0x24c6d684,
+0xc53023, 0x2203821, 0xaf420120, 0xaf420114,
+0xc00188f, 0xafb30010, 0x3c040001, 0x248476a0,
+0x3c050001, 0x24a5072c, 0x3c060001, 0x24c60c24,
+0xc53023, 0x2203821, 0xaf420118, 0xc00188f,
+0xafb30010, 0x8fae0044, 0x3c010002, 0xac2287d4,
+0x4e1024, 0x21082, 0x551025, 0xc00451b,
+0xafc200d0, 0xc004164, 0x0, 0xc0028c7,
+0x0, 0xac000228, 0xac00022c, 0x96e20450,
+0x2442ffff, 0xaf420038, 0x96e20460, 0xaf420080,
+0x32c24000, 0x14400003, 0x0, 0x96e20480,
+0xaf420084, 0x96e70490, 0x50e00001, 0x24070800,
+0x24e2ffff, 0xaf420088, 0xaf42007c, 0x24020800,
+0x10e20023, 0x32c24000, 0x10400003, 0x24020400,
+0x10e2001f, 0x0, 0x3c040001, 0x248476b0,
+0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
+0xc002d3b, 0xafa00014, 0x3c040001, 0x248473b8,
+0x240205f1, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x240e0001,
+0x3c030001, 0xa3ae003f, 0x431025, 0xaf820140,
+0x8f430138, 0x8f440138, 0x24020001, 0xa34205c2,
+0xaf430094, 0xaf440098, 0xafa00010, 0xafa00014,
+0x8f460080, 0x8f470084, 0x3c040001, 0x248476bc,
+0xc002d3b, 0x24052200, 0xc0025c6, 0x3c110800,
+0x3c1433d8, 0x3694cb58, 0x3c020800, 0x34420080,
+0x3c040001, 0x248476c8, 0x3c050000, 0x24a55ff8,
+0x3c060000, 0x24c66014, 0xc53023, 0x27a70030,
+0xaf820060, 0x2402ffff, 0xaf820064, 0x27a20034,
+0xc00188f, 0xafa20010, 0x3c010002, 0xac228774,
+0x21100, 0x21182, 0x511025, 0xc0019e8,
+0xae420000, 0x8f820240, 0x3c030001, 0x431025,
+0xaf820240, 0x3c020000, 0x24424034, 0xaf820244,
+0xaf800240, 0x8f820060, 0x511024, 0x14400005,
+0x3c030800, 0x8f820060, 0x431024, 0x1040fffd,
+0x0, 0xc004171, 0x8821, 0x3c020100,
+0xafa20020, 0x8f530018, 0x240200ff, 0x56620001,
+0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x2484735c, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847364, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400010, 0x0, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x2484736c, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002d3b,
+0x2603821, 0x8f4202e4, 0x24420001, 0xaf4202e4,
+0x8f4202e4, 0x93a2003f, 0x1040007d, 0x3c020700,
+0x34423000, 0xafa20028, 0x8f530018, 0x240200ff,
+0x12620002, 0x8821, 0x26710001, 0x8c020228,
+0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484735c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60028, 0x1000003f, 0x34a50100, 0xd71021,
+0x8fa30028, 0x8fa4002c, 0xac4304c0, 0xac4404c4,
+0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
+0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
+0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x1440000b, 0x24070008,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847364, 0x3c050009, 0xafa20014, 0x8fa60028,
+0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
+0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
+0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400010, 0x0,
+0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x2484736c, 0x3c050009, 0xafa20014, 0x8fa60028,
+0x34a50300, 0xc002d3b, 0x2603821, 0x8f4202f0,
+0x24420001, 0xaf4202f0, 0x8f4202f0, 0x3c040001,
+0x248476d8, 0xafa00010, 0xafa00014, 0x8fa60028,
+0x24052300, 0xc002d3b, 0x3821, 0x3c040001,
+0x248473b8, 0x24020656, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e773c0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x10000004,
+0x0, 0x8c020264, 0x10400005, 0x0,
+0x8f8200a0, 0x30420004, 0x1440fffa, 0x0,
+0x8f820044, 0x34420004, 0xaf820044, 0x8f420308,
+0x24420001, 0xaf420308, 0x8f420308, 0x8f8200d8,
+0x8f8300d4, 0x431023, 0x2442ff80, 0xaf420090,
+0x8f420090, 0x2842ff81, 0x10400006, 0x24020001,
+0x8f420090, 0x8f430144, 0x431021, 0xaf420090,
+0x24020001, 0xaf42008c, 0x32c20008, 0x10400006,
+0x0, 0x8f820214, 0x3c038100, 0x3042ffff,
+0x431025, 0xaf820214, 0x3c030002, 0x8c638668,
+0x30620002, 0x10400009, 0x30620001, 0x3c040001,
+0x248476e4, 0x3c050000, 0x24a57174, 0x3c060000,
+0x24c675f8, 0x10000012, 0xc53023, 0x10400009,
+0x0, 0x3c040001, 0x248476f4, 0x3c050000,
+0x24a57600, 0x3c060000, 0x24c67aa8, 0x10000008,
+0xc53023, 0x3c040001, 0x24847704, 0x3c050000,
+0x24a56d68, 0x3c060000, 0x24c6716c, 0xc53023,
+0x27a70030, 0x27a20034, 0xc00188f, 0xafa20010,
+0x3c010002, 0xac228788, 0x3c020002, 0x8c428788,
+0x3c030800, 0x21100, 0x21182, 0x431025,
+0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0,
+0xafa20014, 0x8f86005c, 0x8f87011c, 0x3c040001,
+0x24847714, 0x3c010002, 0xac368760, 0x3c010002,
+0xac208750, 0x3c010002, 0xac3c8748, 0x3c010002,
+0xac3b8778, 0x3c010002, 0xac37877c, 0x3c010002,
+0xac3a875c, 0xc002d3b, 0x24052400, 0x8f820200,
+0xafa20010, 0x8f820220, 0xafa20014, 0x8f860044,
+0x8f870050, 0x3c040001, 0x24847720, 0xc002d3b,
+0x24052500, 0x8f830060, 0x74100b, 0x242000a,
+0x200f821, 0x0, 0xd, 0x8fbf0060,
+0x8fbe005c, 0x8fb50058, 0x8fb30054, 0x8fb20050,
+0x8fb1004c, 0x8fb00048, 0x3e00008, 0x27bd0068,
+0x27bdffe0, 0x3c040001, 0x2484772c, 0x24052600,
+0x3021, 0x3821, 0xafbf0018, 0xafa00010,
+0xc002d3b, 0xafa00014, 0x3c040001, 0x248473b8,
+0x240206bb, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x3e00008, 0x0, 0x3e00008,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x3e00008, 0x0,
+0x3e00008, 0x0, 0x27bdfde0, 0xafb00218,
+0x27b00018, 0x3c0200bf, 0x3442ffff, 0x50102b,
+0x10400015, 0xafbf021c, 0x3c040001, 0x248473b8,
+0x240206df, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x3c04dead, 0x3484beef,
+0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018,
+0x2028023, 0x2038024, 0x8e020000, 0x1044001e,
+0x0, 0xafb00010, 0x8e020000, 0xafa20014,
+0x8f860150, 0x8f870250, 0x3c040001, 0x24847734,
+0xc002d3b, 0x24052700, 0x3c040001, 0x248473b8,
+0x240206ed, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e773c0, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x8fbf021c, 0x8fb00218,
+0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
+0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
+0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
+0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
+0xaca30000, 0x10460005, 0xae040000, 0xa08021,
+0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
+0x24847740, 0x24052800, 0x2003021, 0x3821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x2001021,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
+0x2821, 0x24030020, 0xe31024, 0x10400002,
+0x63042, 0xa62821, 0x31842, 0x1460fffb,
+0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
+0x45102b, 0x14400003, 0x3c020001, 0x10000008,
+0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
+0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
+0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
+0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
+0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
+0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
+0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
+0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
+0xc002d3b, 0x2403021, 0x8e230000, 0x702021,
+0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
+0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
+0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
+0x8e220000, 0x501021, 0x1000000b, 0xae220000,
+0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
+0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
+0xc002d3b, 0x2603021, 0x2601021, 0x8fbf002c,
+0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
+0x3c1cc000, 0x3c05fffe, 0x3c030002, 0x8c638740,
+0x3c040002, 0x8c84874c, 0x34a5bf08, 0x24021ffc,
+0x3c010002, 0xac2285d0, 0x3c0200c0, 0x3c010002,
+0xac2285d4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
+0xac201ffc, 0x431023, 0x441023, 0x245bb000,
+0x365b821, 0x3c1d0002, 0x8fbd85cc, 0x3a0f021,
+0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
+0x346307c8, 0x24021dfc, 0x3c010002, 0xac2285d0,
+0x24021834, 0x3c010002, 0xac2485d4, 0x3c010002,
+0xac2285d0, 0x3c010002, 0xac2385d4, 0xc0018f9,
+0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffc8, 0x3c040001, 0x2484774c, 0x24053200,
+0x3c020002, 0x8c4285d0, 0x3c030002, 0x8c6385d4,
+0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
+0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
+0xafa30018, 0xafb70010, 0xc002d3b, 0xafba0014,
+0xc001a1b, 0x0, 0x8f820240, 0x34420004,
+0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
+0x571021, 0x904240f4, 0x10400093, 0x2403fffc,
+0x3c100001, 0x2610b47b, 0x3c120001, 0x2652b044,
+0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
+0x24847758, 0x70102b, 0x1440001a, 0x27b30018,
+0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
+0xafa30014, 0xc002d3b, 0x2203821, 0x8fa30018,
+0x702021, 0x64102b, 0x10400007, 0x2403021,
+0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
+0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
+0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
+0xae620000, 0x2408821, 0x24053100, 0xafb00010,
+0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
+0xc002d3b, 0xa0820000, 0x24070020, 0x8fa3001c,
+0x3c040001, 0x24847774, 0x24120020, 0x3c010002,
+0xac31876c, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060002, 0x24c68810,
+0xafa70010, 0xafa30014, 0xc002d3b, 0x2003821,
+0x8fa30018, 0x3c040002, 0x24848810, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100002, 0x26108810, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002d3b, 0xa0820000, 0x24070020, 0x3c040001,
+0x24847788, 0x8fa3001c, 0x24120020, 0x3c010002,
+0xac3087a0, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060002, 0x24c68830,
+0xafa70010, 0xafa30014, 0xc002d3b, 0x2003821,
+0x8fa30018, 0x3c040002, 0x24848830, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100002, 0x26108830, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002d3b, 0xa0820000, 0x3c010002, 0xac30879c,
+0x10000031, 0x0, 0x3c100001, 0x26108667,
+0x3c120001, 0x265284d8, 0x2121023, 0x438024,
+0x8fa3001c, 0x3c040001, 0x2484779c, 0x70102b,
+0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000,
+0x2403021, 0xafb00010, 0xafa30014, 0xc002d3b,
+0x2203821, 0x8fa30018, 0x702021, 0x64102b,
+0x10400007, 0x2403021, 0x8cc20000, 0xac620000,
+0x24630004, 0x64102b, 0x1440fffb, 0x24c60004,
+0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000,
+0x501021, 0x1000000a, 0xae620000, 0x2408821,
+0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018,
+0x2203021, 0x2402002d, 0xc002d3b, 0xa0820000,
+0x3c010002, 0xac31876c, 0x3c030002, 0x8c63876c,
+0x24020400, 0xaf820070, 0x60f809, 0x0,
+0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024,
+0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffe0,
+0xafbf0018, 0x8f820040, 0x3c03f000, 0x431024,
+0x3c036000, 0x14430008, 0x240201f9, 0x8f820050,
+0x2403ff80, 0x431024, 0x34420055, 0xaf820050,
+0x10000014, 0x0, 0x3c040001, 0x2484785c,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e7786c, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x8f820054, 0x244203e8, 0xaf820058,
+0x240201f4, 0xaf4200e0, 0x24020004, 0xaf4200e8,
+0x24020002, 0xaf4001b0, 0xaf4000e4, 0xaf4200dc,
+0xaf4000d8, 0xaf4000d4, 0x8fbf0018, 0xaf4000d0,
+0x3e00008, 0x27bd0020, 0x8f820054, 0x24420005,
+0x3e00008, 0xaf820078, 0x27bdffe8, 0xafbf0010,
+0x8f820054, 0x244203e8, 0xaf820058, 0x3c020800,
+0x2c21024, 0x10400004, 0x3c02f7ff, 0x3442ffff,
+0x2c2b024, 0x36940040, 0x3c020002, 0x8c42867c,
+0x10400017, 0x3c020200, 0x3c030002, 0x8c6387d8,
+0x10600016, 0x282a025, 0x3c020002, 0x8c428708,
+0x14400012, 0x3c020200, 0x3c020002, 0x8c428668,
+0x30420003, 0x1440000d, 0x3c020200, 0x8f830224,
+0x3c020002, 0x8c42a8ac, 0x10620008, 0x3c020200,
+0xc00430b, 0x0, 0x10000004, 0x3c020200,
+0xc00470e, 0x0, 0x3c020200, 0x2c21024,
+0x10400003, 0x0, 0xc002058, 0x0,
+0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8,
+0x43102b, 0x14400003, 0x0, 0xaf4000d8,
+0x36940080, 0x8c030238, 0x1060000c, 0x0,
+0x8f4201b0, 0x244203e8, 0xaf4201b0, 0x43102b,
+0x14400006, 0x0, 0x934205c5, 0x14400003,
+0x0, 0xc001eac, 0x0, 0x8fbf0010,
+0x3e00008, 0x27bd0018, 0x3e00008, 0x0,
+0x27bdffd8, 0xafbf0020, 0x8f43002c, 0x8f420038,
+0x10620059, 0x0, 0x3c020001, 0x571021,
+0x904240f0, 0x10400026, 0x24070008, 0x8f440170,
+0x8f450174, 0x8f48000c, 0x8f860120, 0x24020020,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f0, 0x8f820124,
+0xafa20010, 0x8f820128, 0x3c040001, 0x24847840,
+0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009,
+0xc002d3b, 0x34a50900, 0x1000005d, 0x0,
+0x8f420300, 0x24420001, 0xaf420300, 0x8f420300,
+0x8f42002c, 0xa34005c1, 0x10000027, 0xaf420038,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x2484784c, 0xafa20014, 0x8f46002c,
+0x8f870120, 0x3c050009, 0xc002d3b, 0x34a51100,
+0x10000037, 0x0, 0x8f420300, 0x8f43002c,
+0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
+0xa34205c1, 0xaf430038, 0x3c010001, 0x370821,
+0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0,
+0x10000027, 0xaf400034, 0x934205c1, 0x1040001e,
+0x0, 0xa34005c1, 0x8f820040, 0x30420001,
+0x14400008, 0x2021, 0x8c030104, 0x24020001,
+0x50620005, 0x24040001, 0x8c020264, 0x10400003,
+0x801021, 0x24040001, 0x801021, 0x10400007,
+0x0, 0x8f42030c, 0x24420001, 0xaf42030c,
+0x8f42030c, 0x10000008, 0x0, 0x8f820044,
+0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
+0xaf420308, 0x8f420308, 0x3c010001, 0x370821,
+0xa02040f0, 0x3c010001, 0x370821, 0xa02040f1,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x3c03ff7f, 0x3463ffff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400004,
+0x0, 0xaf80004c, 0x10000002, 0x0,
+0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0020,
+0x8f430044, 0x8f42007c, 0x10620029, 0x24070008,
+0x8f440168, 0x8f45016c, 0x8f48000c, 0x8f860120,
+0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f2,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x24847854, 0xafa20014, 0x8f460044, 0x8f870120,
+0x3c050009, 0xc002d3b, 0x34a51300, 0x1000000f,
+0x0, 0x8f420304, 0x24420001, 0xaf420304,
+0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
+0x370821, 0xa02040f2, 0x10000004, 0xaf400078,
+0x3c010001, 0x370821, 0xa02040f2, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x3c03feff, 0x3463ffff, 0x431024,
+0xaf820060, 0x8f420000, 0x10400004, 0x0,
+0xaf80004c, 0x10000002, 0x0, 0xaf800048,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+0x0, 0x3c020002, 0x8c42867c, 0x27bdffa8,
+0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
+0xafb20040, 0xafb1003c, 0xafb00038, 0x8f900044,
+0x104000d5, 0x0, 0x8f4200d0, 0x24430001,
+0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004,
+0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004,
+0x3c030002, 0x8c63866c, 0x34420002, 0xaf420004,
+0x24020001, 0x14620003, 0x3c020600, 0x10000002,
+0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018,
+0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034,
+0x240200ff, 0x11420002, 0x1821, 0x25430001,
+0x8c020228, 0x609821, 0x1662000e, 0x3c050009,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x8fa70034, 0x3c040001, 0x24847824,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070,
+0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247103e8, 0x2221023,
+0x2c4203e9, 0x1040001b, 0xa821, 0xe09021,
+0x265e04c0, 0x8f440178, 0x8f45017c, 0x2401821,
+0x240a0004, 0xafaa0010, 0xafb30014, 0x8f48000c,
+0x1021, 0x2fe3021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24150001,
+0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x32a200ff, 0x54400018, 0xaf530018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847830, 0xafa20014,
+0x8d460000, 0x3c050009, 0x10000035, 0x34a50600,
+0x8f420308, 0x24150001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001e, 0x32a200ff, 0x8f830054,
+0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
+0x10400016, 0xa821, 0x3c1e0020, 0x24120010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb20010, 0xafb30014, 0x5e1025, 0xafa20018,
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+0x1440ffe3, 0x0, 0x8f820054, 0x2221023,
+0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff,
+0x14400011, 0x3c050009, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0x8fa70034, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847838, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002d3b, 0x0, 0x8f4202ec, 0x24420001,
+0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+0x50400029, 0x36100040, 0x3c020400, 0x2c21024,
+0x10400013, 0x2404ffdf, 0x8f420250, 0x8f430254,
+0x8f4401b4, 0x14640006, 0x36100040, 0x8f420270,
+0x8f430274, 0x8f4401b8, 0x10640007, 0x2402ffdf,
+0x8f420250, 0x8f430254, 0x8f440270, 0x8f450274,
+0x10000012, 0x3a100020, 0x1000002b, 0x2028024,
+0x8f420250, 0x8f430254, 0x8f4501b4, 0x14650006,
+0x2048024, 0x8f420270, 0x8f430274, 0x8f4401b8,
+0x50640021, 0x36100040, 0x8f420250, 0x8f430254,
+0x8f440270, 0x8f450274, 0x3a100040, 0xaf4301b4,
+0x10000019, 0xaf4501b8, 0x8f4200d4, 0x24430001,
+0x10000011, 0x28420033, 0x8f420004, 0x30420001,
+0x10400009, 0x3c020400, 0x2c21024, 0x10400004,
+0x2402ffdf, 0x2028024, 0x1000000b, 0x36100040,
+0x10000009, 0x36100060, 0x8f4200d4, 0x36100040,
+0x24430001, 0x284201f5, 0x14400003, 0xaf4300d4,
+0xaf4000d4, 0x3a100020, 0xaf900044, 0x2402ff7f,
+0x282a024, 0x8fbf0050, 0x8fbe004c, 0x8fb50048,
+0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038,
+0x3e00008, 0x27bd0058, 0x3e00008, 0x0,
+0x3c020002, 0x8c42867c, 0x27bdffb0, 0xafbf0048,
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038,
+0xafb10034, 0x104000c9, 0xafb00030, 0x8f4200d0,
+0x24430001, 0x2842000b, 0x144000dd, 0xaf4300d0,
+0x8f420004, 0x30420002, 0x14400097, 0xaf4000d0,
+0x8f420004, 0x3c030002, 0x8c63866c, 0x34420002,
+0xaf420004, 0x24020001, 0x14620003, 0x3c020600,
+0x10000002, 0x34423000, 0x34421000, 0xafa20020,
+0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
+0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x3c040001, 0x24847824, 0x3c050009, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
+0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
+0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
+0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
+0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
+0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
+0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
+0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
+0x822021, 0x100f809, 0x892021, 0x54400006,
+0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
+0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847830, 0x3c050009,
+0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
+0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
+0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+0x10400016, 0x9821, 0x3c150020, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
+0x14400011, 0x0, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24847838,
+0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002d3b, 0x3c03821, 0x8f4202ec, 0x24420001,
+0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+0x1040001a, 0x24040001, 0x8f420250, 0x8f430254,
+0x8f4501b4, 0x3c010002, 0xa02485e9, 0x14650006,
+0x0, 0x8f420270, 0x8f430274, 0x8f4401b8,
+0x10640022, 0x0, 0x8f420250, 0x8f430254,
+0x3c040002, 0x908485e8, 0x8f460270, 0x8f470274,
+0x38840001, 0xaf4301b4, 0xaf4701b8, 0x3c010002,
+0xa02485e8, 0x10000026, 0x0, 0x8f4200d4,
+0x3c010002, 0xa02085e8, 0x24430001, 0x28420033,
+0x1440001f, 0xaf4300d4, 0x3c020002, 0x904285e9,
+0xaf4000d4, 0x10000018, 0x38420001, 0x8f420004,
+0x30420001, 0x10400009, 0x0, 0xc005c9f,
+0x2021, 0x3c010002, 0xa02085e9, 0x3c010002,
+0xa02085e8, 0x1000000e, 0x0, 0x8f4200d4,
+0x3c010002, 0xa02085e8, 0x24430001, 0x284201f5,
+0x14400007, 0xaf4300d4, 0x3c020002, 0x904285e9,
+0xaf4000d4, 0x421026, 0x3c010002, 0xa02285e9,
+0x3c030002, 0x8c63866c, 0x24020002, 0x1462000c,
+0x3c030002, 0x3c030002, 0x906385e9, 0x24020001,
+0x5462001f, 0x2021, 0x3c020002, 0x904285e8,
+0x1443001b, 0x24040005, 0x10000019, 0x24040006,
+0x3c020002, 0x8c42a8b4, 0x431024, 0x1040000b,
+0x24020001, 0x3c030002, 0x906385e9, 0x54620010,
+0x2021, 0x3c020002, 0x904285e8, 0x1443000c,
+0x24040003, 0x1000000a, 0x24040004, 0x3c030002,
+0x906385e9, 0x14620006, 0x2021, 0x3c020002,
+0x904285e8, 0x24040001, 0x50440001, 0x24040002,
+0xc005c9f, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x3c020002,
+0x8c42867c, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040002,
+0x8c84866c, 0x24430001, 0x2842000b, 0xaf4400e8,
+0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
+0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
+0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
+0x10000002, 0x34423000, 0x34421000, 0xafa20020,
+0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
+0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x3c040001, 0x24847824, 0x3c050009, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
+0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
+0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
+0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
+0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
+0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
+0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
+0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
+0x822021, 0x100f809, 0x892021, 0x54400006,
+0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
+0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847830, 0x3c050009,
+0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
+0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
+0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+0x10400016, 0x9821, 0x3c150020, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
+0x14400011, 0x0, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24847838,
+0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002d3b, 0x3c03821, 0x8f4202ec, 0x24420001,
+0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
+0x0, 0x934205c0, 0x8f440250, 0x8f450254,
+0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
+0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
+0x0, 0x8f420250, 0x8f430254, 0x934405c0,
+0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
+0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
+0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
+0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
+0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
+0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
+0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
+0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
+0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
+0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
+0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
+0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
+0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
+0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
+0x10400007, 0x0, 0x934205c0, 0x34420040,
+0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
+0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
+0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
+0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
+0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
+0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
+0x14620005, 0x0, 0x934405c0, 0x42102,
+0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
+0xc005c85, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
+0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
+0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
+0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
+0x8c820000, 0xac620000, 0x24630004, 0x65102b,
+0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
+0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
+0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
+0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
+0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
+0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
+0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
+0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
+0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
+0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
+0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
+0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
+0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
+0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
+0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
+0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
+0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
+0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
+0x24090000, 0x401821, 0x1021, 0x882024,
+0xa92824, 0x822025, 0xa32825, 0xaee400c0,
+0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
+0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
+0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
+0x65302b, 0x441021, 0x461021, 0xaee200d0,
+0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
+0x401821, 0x1021, 0x882024, 0xa92824,
+0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
+0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
+0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
+0x1021, 0x882024, 0xa92824, 0x822025,
+0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
+0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
+0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
+0x40f809, 0x24070400, 0x104000f1, 0x3c020400,
+0xafa20020, 0x934205c6, 0x10400089, 0x1821,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x24847824, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24847830, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847838, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002d3b, 0x3c03821, 0x1021,
+0x1440005b, 0x24020001, 0x10000066, 0x0,
+0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x2484780c, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847814, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x54400011, 0x24020001, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x2484781c, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002d3b,
+0x2203821, 0x1021, 0x1040000e, 0x24020001,
+0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
+0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
+0xaee20150, 0x8ee20150, 0x10000003, 0x0,
+0x24020001, 0xa34205c6, 0x8fbf0048, 0x8fbe0044,
+0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034,
+0x8fb00030, 0x3e00008, 0x27bd0050, 0x27bdffd8,
+0xafbf0020, 0x8f8200b0, 0x30420004, 0x10400069,
+0x0, 0x8f430128, 0x8f820104, 0x14620005,
+0x0, 0x8f430130, 0x8f8200b4, 0x10620006,
+0x0, 0x8f820104, 0xaf420128, 0x8f8200b4,
+0x1000005c, 0xaf420130, 0x8f8200b0, 0x3c030080,
+0x431024, 0x1040000e, 0x0, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
+0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x1000004a, 0x0,
+0x8f430128, 0x8f820104, 0x14620005, 0x0,
+0x8f430130, 0x8f8200b4, 0x10620010, 0x0,
+0x8f820104, 0xaf420128, 0x8f8200b4, 0x8f430128,
+0xaf420130, 0xafa30010, 0x8f420130, 0x3c040001,
+0x24847874, 0xafa20014, 0x8f86011c, 0x8f8700b0,
+0x3c050005, 0x10000031, 0x34a50900, 0x8f420128,
+0xafa20010, 0x8f420130, 0x3c040001, 0x24847880,
+0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
+0xc002d3b, 0x34a51000, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
+0xaf8200b0, 0x24020008, 0xaf830104, 0xafa20010,
+0xafa00014, 0x8f42000c, 0x8c040208, 0x8c05020c,
+0xafa20018, 0x8f42010c, 0x26e60028, 0x40f809,
+0x24070400, 0x8f82011c, 0x2403fffd, 0x431024,
+0xaf82011c, 0x8ee201dc, 0x24420001, 0xaee201dc,
+0x8ee201dc, 0x8f420128, 0xafa20010, 0x8f420130,
+0x3c040001, 0x2484788c, 0xafa20014, 0x8f86011c,
+0x8f8700b0, 0x3c050005, 0x34a51100, 0xc002d3b,
+0x0, 0x8f8200a0, 0x30420004, 0x1040006a,
+0x0, 0x8f43012c, 0x8f820124, 0x14620005,
+0x0, 0x8f430134, 0x8f8200a4, 0x10620006,
+0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
+0x1000005d, 0xaf420134, 0x8f8200a0, 0x3c030080,
+0x431024, 0x1040000e, 0x0, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f8200a0, 0x2403fffb,
+0x431024, 0xaf8200a0, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x1000004b, 0x0,
+0x8f43012c, 0x8f820124, 0x14620005, 0x0,
+0x8f430134, 0x8f8200a4, 0x10620010, 0x0,
+0x8f820124, 0xaf42012c, 0x8f8200a4, 0x8f43012c,
+0xaf420134, 0xafa30010, 0x8f420134, 0x3c040001,
+0x24847898, 0xafa20014, 0x8f86011c, 0x8f8700a0,
+0x3c050005, 0x10000032, 0x34a51200, 0x8f42012c,
+0xafa20010, 0x8f420134, 0x3c040001, 0x248478a4,
+0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
+0xc002d3b, 0x34a51300, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
+0xaf8200a0, 0x24020080, 0xaf830124, 0xafa20010,
+0xafa00014, 0x8f420014, 0x8c040208, 0x8c05020c,
+0xafa20018, 0x8f420108, 0x3c060002, 0x24c68794,
+0x40f809, 0x24070004, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x8ee201dc, 0x24420001,
+0xaee201dc, 0x8ee201dc, 0x8f42012c, 0xafa20010,
+0x8f420134, 0x3c040001, 0x248478b0, 0xafa20014,
+0x8f86011c, 0x8f8700a0, 0x3c050005, 0x34a51400,
+0xc002d3b, 0x0, 0x8fbf0020, 0x3e00008,
+0x27bd0028, 0x3c081000, 0x24070001, 0x3c060080,
+0x3c050100, 0x8f820070, 0x481024, 0x1040fffd,
+0x0, 0x8f820054, 0x24420005, 0xaf820078,
+0x8c040234, 0x10800017, 0x1821, 0x3c020001,
+0x571021, 0x8c4240e8, 0x24420005, 0x3c010001,
+0x370821, 0xac2240e8, 0x3c020001, 0x571021,
+0x8c4240e8, 0x44102b, 0x1440000a, 0x0,
+0x3c030080, 0x3c010001, 0x370821, 0xac2040e8,
+0x3c010001, 0x370821, 0xa02740f0, 0x1000000b,
+0x0, 0x3c020001, 0x571021, 0x904240f0,
+0x54400006, 0x661825, 0x3c020001, 0x571021,
+0x904240f1, 0x54400001, 0x661825, 0x8c040230,
+0x10800013, 0x0, 0x3c020001, 0x571021,
+0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
+0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
+0x44102b, 0x14400006, 0x0, 0x3c010001,
+0x370821, 0xac2040ec, 0x10000006, 0x651825,
+0x3c020001, 0x571021, 0x904240f2, 0x54400001,
+0x651825, 0x1060ffbb, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
+0x10400004, 0x0, 0xaf80004c, 0x1000ffa5,
+0x0, 0xaf800048, 0x1000ffa2, 0x0,
+0x3e00008, 0x0, 0x27bdffe0, 0xafbf0018,
+0x8f860064, 0x30c20004, 0x10400026, 0x24040004,
+0x8c020114, 0xaf420020, 0xaf840064, 0x8f4202fc,
+0x24420001, 0xaf4202fc, 0x8f4202fc, 0x8f820064,
+0x30420004, 0x14400005, 0x0, 0x8c030114,
+0x8f420020, 0x1462fff2, 0x0, 0x8f420000,
+0x8f43003c, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x431025, 0xaf820060,
+0x8f420000, 0x10400074, 0x0, 0x1000006f,
+0x0, 0x30c20008, 0x10400020, 0x24040008,
+0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
+0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
+0x30420008, 0x14400005, 0x0, 0x8c03011c,
+0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
+0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
+0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
+0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
+0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
+0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
+0x30c20010, 0x1040002b, 0x24040010, 0x8c020124,
+0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
+0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
+0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
+0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420100, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x10000072, 0x0, 0xaf800048, 0x1000006f,
+0x0, 0x30c20001, 0x10400004, 0x24020001,
+0xaf820064, 0x10000069, 0x0, 0x30c20002,
+0x1440000c, 0x3c050003, 0x3c040001, 0x24847974,
+0x34a50500, 0x3821, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x2402ffc0, 0xaf820064, 0x1000005b,
+0x0, 0x8c05022c, 0x8c02010c, 0x10a2004c,
+0x51080, 0x8c460300, 0x24a20001, 0x3045003f,
+0x24020003, 0xac05022c, 0x61e02, 0x10620005,
+0x24020010, 0x1062001e, 0x30c20fff, 0x1000003d,
+0x0, 0x8f4302a8, 0x8f440000, 0x30c20fff,
+0xaf420048, 0x24630001, 0xaf4302a8, 0x8f4202a8,
+0x10800007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
+0x10400021, 0x0, 0x1000001c, 0x0,
+0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
+0x8f4202d4, 0x10600007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420100, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x10000007, 0x0, 0xaf800048, 0x10000004,
+0x0, 0xc0022ad, 0xc02021, 0x402821,
+0x8c02010c, 0x14a20002, 0x24020002, 0xaf820064,
+0x8f820064, 0x30420002, 0x14400004, 0x0,
+0x8c02010c, 0x14a2ffa8, 0x0, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x3e00008, 0x0,
+0x27bdffa0, 0xafb00040, 0x808021, 0x101602,
+0x2442ffff, 0x304300ff, 0x2c620013, 0xafbf0058,
+0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048,
+0xafb10044, 0x104001fe, 0xafa50034, 0x31080,
+0x3c010001, 0x220821, 0x8c2279b8, 0x400008,
+0x0, 0x101302, 0x30440fff, 0x24020001,
+0x10820005, 0x24020002, 0x1082000c, 0x2402fffe,
+0x10000025, 0x3c050003, 0x8f430004, 0x3c020002,
+0x8c4287c0, 0xaf440200, 0xaf440204, 0x3c040002,
+0x8c84873c, 0x10000009, 0x34630001, 0x8f430004,
+0xaf440200, 0xaf440204, 0x3c040002, 0x8c84873c,
+0x621824, 0x3c020001, 0x2442d68c, 0x21100,
+0x21182, 0xaf430004, 0x3c030800, 0x431025,
+0xac820038, 0x8f840054, 0x41442, 0x41c82,
+0x431021, 0x41cc2, 0x431023, 0x41d02,
+0x431021, 0x41d42, 0x431023, 0xaf420208,
+0x10000009, 0x0, 0x3c040001, 0x24847980,
+0x34a51000, 0x2003021, 0x3821, 0xafa00010,
+0xc002d3b, 0xafa00014, 0x8f4202a0, 0x24420001,
+0xaf4202a0, 0x8f4202a0, 0x10000228, 0x0,
+0x27b00028, 0x2002021, 0x24050210, 0xc002dbf,
+0x24060008, 0xc00263a, 0x2002021, 0x1000021f,
+0x0, 0x8faa0034, 0x27a40028, 0xa1880,
+0x25420001, 0x3042003f, 0xafa20034, 0x8c650300,
+0x8faa0034, 0x21080, 0x8c430300, 0x25420001,
+0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028,
+0xc00263a, 0xafa3002c, 0x1000020c, 0x0,
+0x27b00028, 0x2002021, 0x24050210, 0xc002dbf,
+0x24060008, 0xc002779, 0x2002021, 0x10000203,
+0x0, 0x8faa0034, 0x27a40028, 0xa1880,
+0x25420001, 0x3042003f, 0xafa20034, 0x8c650300,
+0x8faa0034, 0x21080, 0x8c430300, 0x25420001,
+0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028,
+0xc002779, 0xafa3002c, 0x100001f0, 0x0,
+0x101302, 0x30430fff, 0x24020001, 0x10620005,
+0x24020002, 0x1062001e, 0x3c020002, 0x10000033,
+0x3c050003, 0x3c030002, 0x2c31024, 0x54400037,
+0x2c3b025, 0x8f820228, 0x3c010001, 0x370821,
+0xac2238d8, 0x8f82022c, 0x3c010001, 0x370821,
+0xac2238dc, 0x8f820230, 0x3c010001, 0x370821,
+0xac2238e0, 0x8f820234, 0x3c010001, 0x370821,
+0xac2238e4, 0x2402ffff, 0xaf820228, 0xaf82022c,
+0xaf820230, 0xaf820234, 0x10000020, 0x2c3b025,
+0x2c21024, 0x10400012, 0x3c02fffd, 0x3c020001,
+0x571021, 0x8c4238d8, 0xaf820228, 0x3c020001,
+0x571021, 0x8c4238dc, 0xaf82022c, 0x3c020001,
+0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001,
+0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd,
+0x3442ffff, 0x10000009, 0x2c2b024, 0x3c040001,
+0x2484798c, 0x34a51100, 0x2003021, 0x3821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x8f4202cc,
+0x24420001, 0xaf4202cc, 0x8f4202cc, 0x100001a7,
+0x0, 0x101302, 0x30450fff, 0x24020001,
+0x10a20005, 0x24020002, 0x10a2000e, 0x3c0408ff,
+0x10000016, 0x3c050003, 0x3c0208ff, 0x3442ffff,
+0x8f830220, 0x3c040004, 0x2c4b025, 0x621824,
+0x34630008, 0xaf830220, 0xaf450298, 0x10000013,
+0x0, 0x3484fff7, 0x3c03fffb, 0x8f820220,
+0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220,
+0xaf450298, 0x10000009, 0x0, 0x3c040001,
+0x24847998, 0x34a51200, 0x2003021, 0x3821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x8f4202bc,
+0x24420001, 0xaf4202bc, 0x8f4202bc, 0x1000017b,
+0x0, 0x27840208, 0x24050200, 0xc002dbf,
+0x24060008, 0x27440224, 0x24050200, 0xc002dbf,
+0x24060008, 0x8f4202c4, 0x24420001, 0xaf4202c4,
+0x8f4202c4, 0x1000016d, 0x0, 0x101302,
+0x30430fff, 0x24020001, 0x10620011, 0x28620002,
+0x50400005, 0x24020002, 0x10600007, 0x0,
+0x10000017, 0x0, 0x1062000f, 0x0,
+0x10000013, 0x0, 0x8c060248, 0x2021,
+0xc005738, 0x24050004, 0x10000007, 0x0,
+0x8c060248, 0x2021, 0xc005738, 0x24050004,
+0x10000010, 0x0, 0x8c06024c, 0x2021,
+0xc005738, 0x24050001, 0x1000000a, 0x0,
+0x3c040001, 0x248479a4, 0x3c050003, 0x34a51300,
+0x2003021, 0x3821, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x8f4202c0, 0x24420001, 0xaf4202c0,
+0x8f4202c0, 0x1000013d, 0x0, 0xc002548,
+0x0, 0x10000139, 0x0, 0x24020001,
+0xa34205c5, 0x24100100, 0x8f4401a8, 0x8f4501ac,
+0xafb00010, 0xafa00014, 0x8f420014, 0xafa20018,
+0x8f420108, 0x26e60028, 0x40f809, 0x24070400,
+0x1040fff5, 0x0, 0x10000128, 0x0,
+0x3c03ffff, 0x34637fff, 0x8f420368, 0x8f440360,
+0x2c3b024, 0x1821, 0xaf400058, 0xaf40005c,
+0xaf400060, 0xaf400064, 0x441023, 0xaf420368,
+0x3c020900, 0xaf400360, 0xafa20020, 0x8f5e0018,
+0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa003c,
+0x27c30001, 0x8c020228, 0x609021, 0x1642000e,
+0x1e38c0, 0x8f42033c, 0x24420001, 0xaf42033c,
+0x8f42033c, 0x8c020228, 0x3c040001, 0x2484793c,
+0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020,
+0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020,
+0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
+0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+0x1040001b, 0x9821, 0xe08821, 0x263504c0,
+0x8f440178, 0x8f45017c, 0x2201821, 0x240a0004,
+0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021,
+0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008,
+0xa32821, 0xa3482b, 0x822021, 0x100f809,
+0x892021, 0x54400006, 0x24130001, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0,
+0x326200ff, 0x54400017, 0xaf520018, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847948, 0x3c050009, 0xafa20014, 0x8d460000,
+0x10000033, 0x34a50600, 0x8f420308, 0x24130001,
+0x24420001, 0xaf420308, 0x8f420308, 0x1000001c,
+0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8,
+0x2021023, 0x2c4203e9, 0x10400014, 0x9821,
+0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
+0x8f860120, 0xafb10010, 0xafb20014, 0xafa20018,
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+0x1440ffe5, 0x0, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff,
+0x14400011, 0x0, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa003c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24847950,
+0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002d3b, 0x3c03821, 0x8f4202b0, 0x24420001,
+0xaf4202b0, 0x8f4202b0, 0x8f4202f8, 0x24420001,
+0xaf4202f8, 0x8f4202f8, 0x1000008c, 0x0,
+0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+0x24050200, 0x24060008, 0xaf4201f8, 0xc002dbf,
+0x0, 0x8f820220, 0x30420008, 0x14400002,
+0x24020001, 0x24020002, 0xaf420298, 0x8f4202ac,
+0x24420001, 0xaf4202ac, 0x8f4202ac, 0x10000077,
+0x0, 0x3c0200ff, 0x3442ffff, 0x2021824,
+0x32c20180, 0x14400006, 0x3402fffb, 0x43102b,
+0x14400003, 0x0, 0x1000006c, 0xaf4300bc,
+0x3c040001, 0x248479b0, 0x3c050003, 0x34a51500,
+0x2003021, 0x3821, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x3c020700, 0x34421000, 0x101e02,
+0x621825, 0xafa30020, 0x8f510018, 0x240200ff,
+0x12220002, 0x8021, 0x26300001, 0x8c020228,
+0x1602000e, 0x1130c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x24847924, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
+0x24070004, 0xafa70010, 0xafb00014, 0x8f48000c,
+0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x1440000b, 0x24070008,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x2484792c, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
+0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010,
+0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400010, 0x0,
+0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847934, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x34a50300, 0xc002d3b, 0x2203821, 0x8f4202e0,
+0x24420001, 0xaf4202e0, 0x8f4202e0, 0x8f4202f0,
+0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8fa20034,
+0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c,
+0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008,
+0x27bd0060, 0x27bdfff8, 0x2408ffff, 0x10a00014,
+0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
+0x24840001, 0x3021, 0x1071026, 0x30420001,
+0x10400002, 0x81842, 0x6a1826, 0x604021,
+0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
+0x25290001, 0x125102b, 0x1440fff0, 0x0,
+0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffb0,
+0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
+0xafb20038, 0xafb10034, 0xafb00030, 0x8f870220,
+0xafa70024, 0x8f870200, 0xafa7002c, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004,
+0xaf820220, 0x8f820200, 0x3c03c0ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820200, 0x8f530358,
+0x8f55035c, 0x8f5e0360, 0x8f470364, 0xafa70014,
+0x8f470368, 0xafa7001c, 0x8f4202d0, 0x274401c0,
+0x24420001, 0xaf4202d0, 0x8f5002d0, 0x8f510204,
+0x8f520200, 0xc002da8, 0x24050400, 0xaf530358,
+0xaf55035c, 0xaf5e0360, 0x8fa70014, 0xaf470364,
+0x8fa7001c, 0xaf470368, 0xaf5002d0, 0xaf510204,
+0xaf520200, 0x8c02025c, 0x27440224, 0xaf4201f0,
+0x8c020260, 0x24050200, 0x24060008, 0xaf4201f8,
+0x24020006, 0xaf4201f4, 0xc002dbf, 0x0,
+0x3c023b9a, 0x3442ca00, 0xaf4201fc, 0x240203e8,
+0x24040002, 0x24030001, 0xaf420294, 0xaf440290,
+0xaf43029c, 0x8f820220, 0x30420008, 0x10400004,
+0x0, 0xaf430298, 0x10000003, 0x3021,
+0xaf440298, 0x3021, 0x3c030002, 0x661821,
+0x906385ec, 0x3461021, 0x24c60001, 0xa043022c,
+0x2cc2000f, 0x1440fff8, 0x3461821, 0x24c60001,
+0x8f820040, 0x24040080, 0x24050080, 0x21702,
+0x24420030, 0xa062022c, 0x3461021, 0xa040022c,
+0xc002da8, 0x0, 0x8fa70024, 0x30e20004,
+0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
+0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
+0x30e20004, 0x14400006, 0x0, 0x8f820200,
+0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0xaf400104, 0x24040001, 0x410c0,
+0x2e21821, 0x24820001, 0x3c010001, 0x230821,
+0xa42234d0, 0x402021, 0x2c820080, 0x1440fff8,
+0x410c0, 0x24020001, 0x3c010001, 0x370821,
+0xa42038d0, 0xaf420100, 0xaf800228, 0xaf80022c,
+0xaf800230, 0xaf800234, 0x3e00008, 0x0,
+0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f420104,
+0x28420005, 0x10400026, 0x808021, 0x3c020001,
+0x8f430104, 0x344230d0, 0x2e23021, 0x318c0,
+0x621821, 0x2e33821, 0xc7102b, 0x10400015,
+0x1021, 0x96080000, 0x24c40006, 0x9482fffc,
+0x14480009, 0x2821, 0x9483fffe, 0x96020002,
+0x14620006, 0xa01021, 0x94820000, 0x96030004,
+0x431026, 0x2c450001, 0xa01021, 0x1440000a,
+0x24c60008, 0xc7102b, 0x1440fff0, 0x24840008,
+0x1021, 0x304200ff, 0x14400030, 0x24020001,
+0x1000002e, 0x1021, 0x1000fffa, 0x24020001,
+0x2002021, 0xc00252e, 0x24050006, 0x3042007f,
+0x218c0, 0x2e31021, 0x3c010001, 0x220821,
+0x942230d0, 0x1040fff2, 0x2e31021, 0x3c060001,
+0xc23021, 0x94c630d0, 0x10c0ffed, 0x3c080001,
+0x350834d2, 0x96070000, 0x610c0, 0x572021,
+0x882021, 0x94820000, 0x14470009, 0x2821,
+0x94830002, 0x96020002, 0x14620006, 0xa01021,
+0x94820004, 0x96030004, 0x431026, 0x2c450001,
+0xa01021, 0x14400007, 0x610c0, 0x2e21021,
+0x3c060001, 0xc23021, 0x94c634d0, 0x14c0ffeb,
+0x610c0, 0x10c0ffd2, 0x24020001, 0x8fbf0014,
+0x8fb00010, 0x3e00008, 0x27bd0018, 0x3e00008,
+0x0, 0x27bdffb0, 0x801021, 0xafb00030,
+0x24500002, 0x2002021, 0x24050006, 0xafb10034,
+0x408821, 0xafbf0048, 0xafbe0044, 0xafb50040,
+0xafb3003c, 0xc00252e, 0xafb20038, 0x3047007f,
+0x710c0, 0x2e21021, 0x3c050001, 0xa22821,
+0x94a530d0, 0x50a0001c, 0xa03021, 0x3c090001,
+0x352934d2, 0x96280002, 0x510c0, 0x572021,
+0x892021, 0x94820000, 0x14480009, 0x3021,
+0x94830002, 0x96020002, 0x14620006, 0xc01021,
+0x94820004, 0x96030004, 0x431026, 0x2c460001,
+0xc01021, 0x14400007, 0x510c0, 0x2e21021,
+0x3c050001, 0xa22821, 0x94a534d0, 0x14a0ffeb,
+0x510c0, 0xa03021, 0x10c00014, 0x610c0,
+0x571821, 0x3c010001, 0x230821, 0x8c2334d0,
+0x571021, 0xafa30010, 0x3c010001, 0x220821,
+0x8c2234d4, 0x3c040001, 0x24847ab8, 0xafa20014,
+0x8e260000, 0x8e270004, 0x3c050004, 0xc002d3b,
+0x34a50400, 0x10000063, 0x3c020800, 0x8f450100,
+0x10a00006, 0x510c0, 0x2e21021, 0x3c010001,
+0x220821, 0x942234d0, 0xaf420100, 0xa03021,
+0x14c00011, 0x628c0, 0x710c0, 0x2e21021,
+0xafa70010, 0x3c010001, 0x220821, 0x942230d0,
+0x3c040001, 0x24847ac4, 0xafa20014, 0x8e260000,
+0x8e270004, 0x3c050004, 0xc002d3b, 0x34a50500,
+0x10000048, 0x3c020800, 0xb71821, 0x3c020001,
+0x96040000, 0x344234d2, 0x621821, 0xa4640000,
+0x8e020002, 0x720c0, 0xac620002, 0x2e41021,
+0x3c030001, 0x621821, 0x946330d0, 0x2e51021,
+0x3c010001, 0x220821, 0xa42334d0, 0x2e41021,
+0x3c010001, 0x220821, 0xa42630d0, 0x8f420104,
+0x24420001, 0x28420080, 0x1040000f, 0x3c020002,
+0x8f420104, 0x3c040001, 0x348430d2, 0x96030000,
+0x210c0, 0x571021, 0x441021, 0xa4430000,
+0x8e030002, 0xac430002, 0x8f420104, 0x24420001,
+0xaf420104, 0x3c020002, 0x2c21024, 0x10400011,
+0x72142, 0x3c030001, 0x346338d8, 0x24020003,
+0x441023, 0x21080, 0x572021, 0x832021,
+0x571021, 0x431021, 0x30e5001f, 0x8c430000,
+0x24020001, 0xa21004, 0x621825, 0x1000000c,
+0xac830000, 0x24020003, 0x441023, 0x21080,
+0x5c2821, 0x5c1021, 0x30e4001f, 0x8c430228,
+0x24020001, 0x821004, 0x621825, 0xaca30228,
+0x3c020800, 0x34421000, 0x1821, 0xafa20020,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x24847a80, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24847a8c, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24847a94, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002d3b, 0x3c03821, 0x8f4202b4,
+0x24420001, 0xaf4202b4, 0x8f4202b4, 0x8f4202f4,
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0048,
+0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
+0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
+0x27bdffa0, 0x801021, 0xafb00040, 0x24500002,
+0x2002021, 0x24050006, 0xafb10044, 0x408821,
+0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
+0xc00252e, 0xafb20048, 0x3048007f, 0x810c0,
+0x2e21021, 0x3c060001, 0xc23021, 0x94c630d0,
+0x10c0001c, 0x3821, 0x3c0a0001, 0x354a34d2,
+0x96290002, 0x610c0, 0x572021, 0x8a2021,
+0x94820000, 0x14490009, 0x2821, 0x94830002,
+0x96020002, 0x14620006, 0xa01021, 0x94820004,
+0x96030004, 0x431026, 0x2c450001, 0xa01021,
+0x14400008, 0x610c0, 0xc03821, 0x2e21021,
+0x3c060001, 0xc23021, 0x94c634d0, 0x14c0ffea,
+0x610c0, 0x14c00011, 0xafa70028, 0x810c0,
+0x2e21021, 0xafa80010, 0x3c010001, 0x220821,
+0x942230d0, 0x3c040001, 0x24847ad0, 0xafa20014,
+0x8e260000, 0x8e270004, 0x3c050004, 0xc002d3b,
+0x34a50900, 0x10000075, 0x3c020800, 0x10e0000c,
+0x610c0, 0x2e21021, 0x3c030001, 0x621821,
+0x946334d0, 0x710c0, 0x2e21021, 0x3c010001,
+0x220821, 0xa42334d0, 0x1000000b, 0x3c040001,
+0x2e21021, 0x3c030001, 0x621821, 0x946334d0,
+0x810c0, 0x2e21021, 0x3c010001, 0x220821,
+0xa42330d0, 0x3c040001, 0x348430d0, 0x8f430100,
+0x610c0, 0x2e21021, 0x3c010001, 0x220821,
+0xa42334d0, 0x8f420104, 0x2e43821, 0x2821,
+0x18400029, 0xaf460100, 0x24e60006, 0x94c3fffc,
+0x96020000, 0x14620009, 0x2021, 0x94c3fffe,
+0x96020002, 0x14620006, 0x801021, 0x94c20000,
+0x96030004, 0x431026, 0x2c440001, 0x801021,
+0x50400014, 0x24a50001, 0x8f420104, 0x2442ffff,
+0xa2102a, 0x1040000b, 0x24e40004, 0x94820006,
+0x8c830008, 0xa482fffe, 0xac830000, 0x8f420104,
+0x24a50001, 0x2442ffff, 0xa2102a, 0x1440fff7,
+0x24840008, 0x8f420104, 0x2442ffff, 0x10000006,
+0xaf420104, 0x8f420104, 0x24c60008, 0xa2102a,
+0x1440ffda, 0x24e70008, 0x810c0, 0x2e21021,
+0x3c010001, 0x220821, 0x942230d0, 0x14400023,
+0x3c020800, 0x3c020002, 0x2c21024, 0x10400012,
+0x82142, 0x3c030001, 0x346338d8, 0x24020003,
+0x441023, 0x21080, 0x572021, 0x832021,
+0x571021, 0x431021, 0x3105001f, 0x24030001,
+0x8c420000, 0xa31804, 0x31827, 0x431024,
+0x1000000d, 0xac820000, 0x24020003, 0x441023,
+0x21080, 0x5c2821, 0x5c1021, 0x3104001f,
+0x24030001, 0x8c420228, 0x831804, 0x31827,
+0x431024, 0xaca20228, 0x3c020800, 0x34422000,
+0x1821, 0xafa20020, 0x8f5e0018, 0x27ab0020,
+0x240200ff, 0x13c20002, 0xafab0034, 0x27c30001,
+0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24847a80, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240b0004, 0xafab0010,
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8fab0034,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24847a8c,
+0x3c050009, 0xafa20014, 0x8d660000, 0x10000033,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
+0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffef, 0x0, 0x326200ff, 0x14400011,
+0x0, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8fab0034, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24847a94, 0x3c050009,
+0xafa20014, 0x8d660000, 0x34a50700, 0xc002d3b,
+0x3c03821, 0x8f4202b8, 0x24420001, 0xaf4202b8,
+0x8f4202b8, 0x8f4202f4, 0x24420001, 0xaf4202f4,
+0x8f4202f4, 0x8fbf0058, 0x8fbe0054, 0x8fb50050,
+0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040,
+0x3e00008, 0x27bd0060, 0x27bdffe0, 0x27644000,
+0xafbf0018, 0xc002da8, 0x24051000, 0x3c030001,
+0x34632cc0, 0x3c040001, 0x34842ec8, 0x24020020,
+0xaf82011c, 0x2e31021, 0xaf800100, 0xaf800104,
+0xaf800108, 0xaf800110, 0xaf800114, 0xaf800118,
+0xaf800120, 0xaf800124, 0xaf800128, 0xaf800130,
+0xaf800134, 0xaf800138, 0xaf4200ec, 0x2e31021,
+0xaf4200f0, 0x2e41021, 0xaf4200f4, 0x2e41021,
+0xaf4200f8, 0x3c020001, 0x571021, 0x904240f4,
+0x1440001c, 0x3c050001, 0x8f82011c, 0x3c040001,
+0x24847b8c, 0x3c050001, 0x34420001, 0xaf82011c,
+0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50100,
+0xc002d3b, 0x3821, 0x8c020218, 0x30420040,
+0x10400014, 0x0, 0x8f82011c, 0x3c040001,
+0x24847b98, 0x3c050001, 0x34420004, 0xaf82011c,
+0xafa00010, 0xafa00014, 0x8f86011c, 0x10000007,
+0x34a50200, 0x3c040001, 0x24847ba0, 0xafa00010,
+0xafa00014, 0x8f86011c, 0x34a50300, 0xc002d3b,
+0x3821, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x27bdffd8, 0xafb1001c, 0x8fb10038, 0xafbf0020,
+0xafb00018, 0x8f83012c, 0x8fa9003c, 0x8faa0040,
+0x1060000a, 0x27624fe0, 0x14620002, 0x24680020,
+0x27684800, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020008, 0x0, 0x8f430334,
+0x1021, 0x24630001, 0xaf430334, 0x8f430334,
+0x10000052, 0x0, 0xac640000, 0xac650004,
+0xac660008, 0xa467000e, 0xac710018, 0xac69001c,
+0xac6a0010, 0xac620014, 0xaf880120, 0x8f4200fc,
+0x8f5000f4, 0x2442ffff, 0xaf4200fc, 0x8e020000,
+0x10510005, 0x3042ff8f, 0x10400019, 0x3222ff8f,
+0x10400018, 0x3c020001, 0x8e030004, 0x2c620010,
+0x10400013, 0x3c020001, 0x24630001, 0xae030004,
+0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x1450002e, 0x24020001, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x10000028, 0x24020001,
+0x3c020001, 0x344230c8, 0x2e21021, 0x16020004,
+0x26030008, 0x3c020001, 0x34422ec8, 0x2e21821,
+0x8f4200f8, 0x608021, 0x12020004, 0xaf5000f4,
+0x8e020000, 0x10400016, 0x24020001, 0x24020170,
+0x3c040001, 0x24847ba8, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77bb0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x24020001,
+0xae110000, 0xae020004, 0x24020001, 0x8fbf0020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0xafb20020, 0x809021, 0xa09821, 0xafb50028,
+0xc0a821, 0xafbf0030, 0xafbe002c, 0xafb1001c,
+0xafb00018, 0x8f900120, 0x27624fe0, 0x16020003,
+0xe0f021, 0x10000002, 0x27714800, 0x26110020,
+0x8f820128, 0x16220008, 0x0, 0x8f430334,
+0x1021, 0x24630001, 0xaf430334, 0x8f430334,
+0x10000028, 0x0, 0x8f820124, 0x16220014,
+0x240201ab, 0x3c040001, 0x24847ba8, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77bb0,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0xae120000, 0xae130004, 0xae150008, 0xa61e000e,
+0x8fa80048, 0xae080018, 0x8fa8004c, 0x26020016,
+0xae08001c, 0xae020014, 0x8fa80050, 0xae080010,
+0xaf910120, 0x8f4300fc, 0x24020001, 0x2463ffff,
+0xaf4300fc, 0x8fbf0030, 0x8fbe002c, 0x8fb50028,
+0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0038, 0x3e00008, 0x0,
+0x27bdffd8, 0xafb1001c, 0x8fb10038, 0xafbf0020,
+0xafb00018, 0x8f83010c, 0x8fa9003c, 0x8faa0040,
+0x1060000a, 0x276247e0, 0x14620002, 0x24680020,
+0x27684000, 0x8f820108, 0x11020004, 0x0,
+0x8f820104, 0x15020008, 0x0, 0x8f430338,
+0x1021, 0x24630001, 0xaf430338, 0x8f430338,
+0x1000004e, 0x0, 0xac640000, 0xac650004,
+0xac660008, 0xa467000e, 0xac710018, 0xac69001c,
+0xac6a0010, 0xac620014, 0xaf880100, 0x8f5000ec,
+0x8e020000, 0x30420006, 0x10400019, 0x32220006,
+0x10400018, 0x3c020001, 0x8e030004, 0x2c620010,
+0x10400013, 0x3c020001, 0x24630001, 0xae030004,
+0x8f4300f0, 0x34422ec0, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422cc0, 0x2e21021,
+0x1450002e, 0x24020001, 0x8f820108, 0x24420020,
+0xaf820108, 0x8f820108, 0x10000028, 0x24020001,
+0x3c020001, 0x34422ec0, 0x2e21021, 0x16020004,
+0x26030008, 0x3c020001, 0x34422cc0, 0x2e21821,
+0x8f4200f0, 0x608021, 0x12020004, 0xaf5000ec,
+0x8e020000, 0x10400016, 0x24020001, 0x24020212,
+0x3c040001, 0x24847ba8, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77bb0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x24020001,
+0xae110000, 0xae020004, 0x24020001, 0x8fbf0020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0xafb20020, 0x809021, 0xa09821, 0xafb50028,
+0xc0a821, 0xafbf0030, 0xafbe002c, 0xafb1001c,
+0xafb00018, 0x8f900100, 0x276247e0, 0x16020003,
+0xe0f021, 0x10000002, 0x27714000, 0x26110020,
+0x8f820108, 0x16220008, 0x0, 0x8f430338,
+0x1021, 0x24630001, 0xaf430338, 0x8f430338,
+0x10000025, 0x0, 0x8f820104, 0x16220014,
+0x2402024d, 0x3c040001, 0x24847ba8, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77bb0,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0xae120000, 0xae130004, 0xae150008, 0xa61e000e,
+0x8fa80048, 0xae080018, 0x8fa8004c, 0x26030016,
+0xae08001c, 0xae030014, 0x8fa80050, 0x24020001,
+0xae080010, 0xaf910100, 0x8fbf0030, 0x8fbe002c,
+0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0038, 0x3e00008,
+0x0, 0x27bdffd8, 0x3c040001, 0x24847bb8,
+0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c,
+0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c,
+0x34a52500, 0x8f820100, 0x2403021, 0x2203821,
+0xafa20010, 0xc002d3b, 0xafb00014, 0x8e020008,
+0xafa20010, 0x8e02000c, 0x3c040001, 0x24847bc4,
+0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001,
+0xc002d3b, 0x34a52510, 0x8e020018, 0xafa20010,
+0x8e02001c, 0x3c040001, 0x24847bd0, 0xafa20014,
+0x8e060010, 0x8e070014, 0x3c050001, 0xc002d3b,
+0x34a52520, 0x3c027f00, 0x2221024, 0x3c030800,
+0x54430016, 0x3c030200, 0x8f82009c, 0x3042ffff,
+0x14400012, 0x3c030200, 0x3c040001, 0x24847bdc,
+0x3c050002, 0x34a5f030, 0x3021, 0x3821,
+0x36420002, 0xaf82011c, 0x36220001, 0xaf8200b0,
+0xaf900104, 0xaf92011c, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x10000025, 0x0, 0x2c31024,
+0x1040000e, 0x2231024, 0x1040000c, 0x36420002,
+0xaf82011c, 0x36220001, 0xaf8200b0, 0xaf900104,
+0xaf92011c, 0x8f420330, 0x24420001, 0xaf420330,
+0x8f420330, 0x10000015, 0x0, 0x3c040001,
+0x24847ba8, 0x240202a9, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77bb0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0x3c040001, 0x24847be4,
+0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c,
+0xafb00018, 0x8f900124, 0x8f9100a0, 0x8f92011c,
+0x34a52600, 0x8f820120, 0x2403021, 0x2203821,
+0xafa20010, 0xc002d3b, 0xafb00014, 0x8e020008,
+0xafa20010, 0x8e02000c, 0x3c040001, 0x24847bf0,
+0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001,
+0xc002d3b, 0x34a52610, 0x8e020018, 0xafa20010,
+0x8e02001c, 0x3c040001, 0x24847bfc, 0xafa20014,
+0x8e060010, 0x8e070014, 0x3c050001, 0xc002d3b,
+0x34a52620, 0x3c027f00, 0x2221024, 0x3c030800,
+0x54430016, 0x3c030200, 0x8f8200ac, 0x3042ffff,
+0x14400012, 0x3c030200, 0x3c040001, 0x24847c08,
+0x3c050001, 0x34a5f030, 0x3021, 0x3821,
+0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
+0xaf900124, 0xaf92011c, 0xafa00010, 0xc002d3b,
+0xafa00014, 0x10000025, 0x0, 0x2c31024,
+0x1040000e, 0x2231024, 0x1040000c, 0x36420002,
+0xaf82011c, 0x36220001, 0xaf8200a0, 0xaf900124,
+0xaf92011c, 0x8f42032c, 0x24420001, 0xaf42032c,
+0x8f42032c, 0x10000015, 0x0, 0x3c040001,
+0x24847ba8, 0x240202e2, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77bb0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x6021, 0x5021, 0x3021,
+0x2821, 0x6821, 0x4821, 0x7821,
+0x7021, 0x8f880124, 0x8f870104, 0x8f8b011c,
+0x1580002e, 0x0, 0x11a00014, 0x31620800,
+0x8f820120, 0x10460029, 0x0, 0x3c040002,
+0x8c8487a0, 0x8cc20000, 0x8cc30004, 0xac820000,
+0xac830004, 0x8cc20008, 0xac820008, 0x94c2000e,
+0xa482000e, 0x8cc20010, 0x240c0001, 0xac820010,
+0x8cc20014, 0x10000012, 0x24c60020, 0x10400017,
+0x0, 0x3c040002, 0x8c8487a0, 0x8d020000,
+0x8d030004, 0xac820000, 0xac830004, 0x8d020008,
+0xac820008, 0x9502000e, 0xa482000e, 0x8d020010,
+0x25060020, 0xac820010, 0x8d020014, 0x240c0001,
+0xc01821, 0xac820014, 0x27624fe0, 0x43102b,
+0x54400001, 0x27634800, 0x603021, 0x1540002f,
+0x31620100, 0x11200014, 0x31628000, 0x8f820100,
+0x1045002a, 0x31620100, 0x3c040002, 0x8c84879c,
+0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004,
+0x8ca20008, 0xac820008, 0x94a2000e, 0xa482000e,
+0x8ca20010, 0x240a0001, 0xac820010, 0x8ca20014,
+0x10000012, 0x24a50020, 0x10400018, 0x31620100,
+0x3c040002, 0x8c84879c, 0x8ce20000, 0x8ce30004,
+0xac820000, 0xac830004, 0x8ce20008, 0xac820008,
+0x94e2000e, 0xa482000e, 0x8ce20010, 0x24e50020,
+0xac820010, 0x8ce20014, 0x240a0001, 0xa01821,
+0xac820014, 0x276247e0, 0x43102b, 0x54400001,
+0x27634000, 0x602821, 0x31620100, 0x5440001d,
+0x31621000, 0x11a00009, 0x31a20800, 0x10400004,
+0x25020020, 0x8f8200a8, 0xa5e20000, 0x25020020,
+0xaf820124, 0x8f880124, 0x6821, 0x11800011,
+0x31621000, 0x3c040002, 0x8c8487a0, 0x8c820000,
+0x8c830004, 0xaf820080, 0xaf830084, 0x8c820008,
+0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010,
+0x6021, 0xaf8200a0, 0x8c8d0010, 0x8c8f0014,
+0x31621000, 0x1440ff81, 0x0, 0x1120000f,
+0x31220800, 0x10400004, 0x3c020002, 0x8f8200b8,
+0xa5c20000, 0x3c020002, 0x1221024, 0x10400004,
+0x24e20020, 0x8f8200b4, 0xaf8200d4, 0x24e20020,
+0xaf820104, 0x8f870104, 0x4821, 0x1140ff6f,
+0x0, 0x3c040002, 0x8c84879c, 0x8c820000,
+0x8c830004, 0xaf820090, 0xaf830094, 0x8c820008,
+0xaf8200b4, 0x9482000e, 0xaf82009c, 0x8c820010,
+0x5021, 0xaf8200b0, 0x8c890010, 0x8c8e0014,
+0x1000ff5e, 0x0, 0x3e00008, 0x0,
+0x6021, 0x5821, 0x3021, 0x2821,
+0x6821, 0x5021, 0x7821, 0x7021,
+0x8f880124, 0x8f870104, 0x3c180100, 0x8f89011c,
+0x1580002e, 0x0, 0x11a00014, 0x31220800,
+0x8f820120, 0x10460029, 0x0, 0x3c040002,
+0x8c8487a0, 0x8cc20000, 0x8cc30004, 0xac820000,
+0xac830004, 0x8cc20008, 0xac820008, 0x94c2000e,
+0xa482000e, 0x8cc20010, 0x240c0001, 0xac820010,
+0x8cc20014, 0x10000012, 0x24c60020, 0x10400017,
+0x0, 0x3c040002, 0x8c8487a0, 0x8d020000,
+0x8d030004, 0xac820000, 0xac830004, 0x8d020008,
+0xac820008, 0x9502000e, 0xa482000e, 0x8d020010,
+0x25060020, 0xac820010, 0x8d020014, 0x240c0001,
+0xc01821, 0xac820014, 0x27624fe0, 0x43102b,
+0x54400001, 0x27634800, 0x603021, 0x1560002f,
+0x31220100, 0x11400014, 0x31228000, 0x8f820100,
+0x1045002a, 0x31220100, 0x3c040002, 0x8c84879c,
+0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004,
+0x8ca20008, 0xac820008, 0x94a2000e, 0xa482000e,
+0x8ca20010, 0x240b0001, 0xac820010, 0x8ca20014,
+0x10000012, 0x24a50020, 0x10400018, 0x31220100,
+0x3c040002, 0x8c84879c, 0x8ce20000, 0x8ce30004,
+0xac820000, 0xac830004, 0x8ce20008, 0xac820008,
+0x94e2000e, 0xa482000e, 0x8ce20010, 0x24e50020,
+0xac820010, 0x8ce20014, 0x240b0001, 0xa01821,
+0xac820014, 0x276247e0, 0x43102b, 0x54400001,
+0x27634000, 0x602821, 0x31220100, 0x5440001d,
+0x31221000, 0x11a00009, 0x31a20800, 0x10400004,
+0x25020020, 0x8f8200a8, 0xa5e20000, 0x25020020,
+0xaf820124, 0x8f880124, 0x6821, 0x11800011,
+0x31221000, 0x3c040002, 0x8c8487a0, 0x8c820000,
+0x8c830004, 0xaf820080, 0xaf830084, 0x8c820008,
+0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010,
+0x6021, 0xaf8200a0, 0x8c8d0010, 0x8c8f0014,
+0x31221000, 0x14400022, 0x0, 0x1140000f,
+0x31420800, 0x10400004, 0x3c020002, 0x8f8200b8,
+0xa5c20000, 0x3c020002, 0x1421024, 0x10400004,
+0x24e20020, 0x8f8200b4, 0xaf8200d4, 0x24e20020,
+0xaf820104, 0x8f870104, 0x5021, 0x11600010,
+0x0, 0x3c040002, 0x8c84879c, 0x8c820000,
+0x8c830004, 0xaf820090, 0xaf830094, 0x8c820008,
+0xaf8200b4, 0x9482000e, 0xaf82009c, 0x8c820010,
+0x5821, 0xaf8200b0, 0x8c8a0010, 0x8c8e0014,
+0x8f820070, 0x3c031000, 0x431024, 0x1040ff5b,
+0x0, 0x8f820054, 0x24420005, 0xaf820078,
+0x8c040234, 0x10800017, 0x1821, 0x3c020001,
+0x571021, 0x8c4240e8, 0x24420005, 0x3c010001,
+0x370821, 0xac2240e8, 0x3c020001, 0x571021,
+0x8c4240e8, 0x44102b, 0x1440000a, 0x24020001,
+0x3c030080, 0x3c010001, 0x370821, 0xac2040e8,
+0x3c010001, 0x370821, 0xa02240f0, 0x1000000c,
+0x0, 0x3c020001, 0x571021, 0x904240f0,
+0x14400006, 0x3c020080, 0x3c020001, 0x571021,
+0x904240f1, 0x10400002, 0x3c020080, 0x621825,
+0x8c040230, 0x10800013, 0x0, 0x3c020001,
+0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
+0x370821, 0xac2240ec, 0x3c020001, 0x571021,
+0x8c4240ec, 0x44102b, 0x14400006, 0x0,
+0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
+0x781825, 0x3c020001, 0x571021, 0x904240f2,
+0x54400001, 0x781825, 0x1060ff18, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x431025, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x1000ff02, 0x0, 0xaf800048, 0x1000feff,
+0x0, 0x3e00008, 0x0, 0x3c020002,
+0x8c428608, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100002, 0x26108850, 0x2002021,
+0xc002da8, 0x24052000, 0x26021fe0, 0x3c010002,
+0xac2287a8, 0x3c010002, 0xac2287a4, 0xac020250,
+0x24022000, 0xac100254, 0xac020258, 0x24020001,
+0x3c010002, 0xac228608, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c090002, 0x8d2987a8,
+0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
+0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
+0xad260010, 0xad270014, 0xad230018, 0xad28001c,
+0xad22000c, 0x2529ffe0, 0x3c020002, 0x24428850,
+0x122102b, 0x10400003, 0x0, 0x3c090002,
+0x8d2987a4, 0x3c020002, 0x8c4285fc, 0xad220000,
+0x3c020002, 0x8c4285fc, 0x3c010002, 0xac2987a8,
+0xad220004, 0xac090250, 0x3e00008, 0x0,
+0x27bdffd0, 0xafb00010, 0x3c100002, 0x8e1087a8,
+0x3c020002, 0x8c4285fc, 0xafb10014, 0x808821,
+0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
+0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
+0xae020000, 0x3c020002, 0x8c4285fc, 0xc09821,
+0xe0a821, 0x10800006, 0xae020004, 0x26050008,
+0xc002db3, 0x24060018, 0x10000005, 0x2610ffe0,
+0x26040008, 0xc002da8, 0x24050018, 0x2610ffe0,
+0x3c030002, 0x24638850, 0x203102b, 0x10400003,
+0x0, 0x3c100002, 0x8e1087a4, 0x8e220000,
+0xae020000, 0x8e220004, 0xae120008, 0xae020004,
+0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
+0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
+0x203102b, 0x10400003, 0x0, 0x3c100002,
+0x8e1087a4, 0x3c020002, 0x8c4285fc, 0xae020000,
+0x3c020002, 0x8c4285fc, 0x3c010002, 0xac3087a8,
+0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
+0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
+0x83102b, 0x10400006, 0x0, 0xac800000,
+0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
+0x3e00008, 0x0, 0xa61821, 0xa3102b,
+0x10400007, 0x0, 0x8c820000, 0xaca20000,
+0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
+0x3e00008, 0x0, 0x861821, 0x83102b,
+0x10400007, 0x0, 0x8ca20000, 0xac820000,
+0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
+0x3e00008, 0x0, 0x63080, 0x861821,
+0x83102b, 0x10400006, 0x0, 0xac850000,
+0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
+0x3e00008, 0x0, 0x26e50028, 0xa03021,
+0x274301c0, 0x8f4d0358, 0x8f47035c, 0x8f480360,
+0x8f490364, 0x8f4a0368, 0x8f4b0204, 0x8f4c0200,
+0x24640400, 0x64102b, 0x10400008, 0x3c0208ff,
+0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
+0x1440fffb, 0x24c60004, 0x3c0208ff, 0x3442ffff,
+0x3c03c0ff, 0xaf4d0358, 0xaf47035c, 0xaf480360,
+0xaf490364, 0xaf4a0368, 0xaf4b0204, 0xaf4c0200,
+0x8f840220, 0x3463ffff, 0x8f860200, 0x821024,
+0x34420004, 0xc31824, 0x34630004, 0xaf820220,
+0xaf830200, 0x8ca20214, 0xac020084, 0x8ca20218,
+0xac020088, 0x8ca2021c, 0xac02008c, 0x8ca20220,
+0xac020090, 0x8ca20224, 0xac020094, 0x8ca20228,
+0xac020098, 0x8ca2022c, 0xac02009c, 0x8ca20230,
+0xac0200a0, 0x8ca20234, 0xac0200a4, 0x8ca20238,
+0xac0200a8, 0x8ca2023c, 0xac0200ac, 0x8ca20240,
+0xac0200b0, 0x8ca20244, 0xac0200b4, 0x8ca20248,
+0xac0200b8, 0x8ca2024c, 0xac0200bc, 0x8ca2001c,
+0xac020080, 0x8ca20018, 0xac0200c0, 0x8ca20020,
+0xac0200cc, 0x8ca20024, 0xac0200d0, 0x8ca201d0,
+0xac0200e0, 0x8ca201d4, 0xac0200e4, 0x8ca201d8,
+0xac0200e8, 0x8ca201dc, 0xac0200ec, 0x8ca201e0,
+0xac0200f0, 0x8ca20098, 0x8ca3009c, 0xac0300fc,
+0x8ca200a8, 0x8ca300ac, 0xac0300f4, 0x8ca200a0,
+0x8ca300a4, 0x30840004, 0xac0300f8, 0x14800007,
+0x30c20004, 0x8f820220, 0x3c0308ff, 0x3463fffb,
+0x431024, 0xaf820220, 0x30c20004, 0x14400006,
+0x0, 0x8f820200, 0x3c03c0ff, 0x3463fffb,
+0x431024, 0xaf820200, 0x8f4202dc, 0xa34005c5,
+0x24420001, 0xaf4202dc, 0x8f4202dc, 0x3e00008,
+0x0, 0x27bdffd0, 0xafbf0028, 0xafb10024,
+0xafb00020, 0x8f430024, 0x8f420020, 0x1062004e,
+0x0, 0x8f430020, 0x8f420024, 0x628823,
+0x6210003, 0x0, 0x8f420040, 0x2228821,
+0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
+0x0, 0x8f430040, 0x8f420024, 0x10000005,
+0x628023, 0x8f420030, 0x8f430024, 0x431023,
+0x2450ffff, 0x16000016, 0x2006821, 0x3c040001,
+0x24847e74, 0x240202aa, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77e84, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x2006821,
+0x22d102a, 0x54400001, 0x2206821, 0x8f4b0024,
+0x8f4a0040, 0x8f490024, 0x8f440180, 0x8f450184,
+0x8f460024, 0x8f4c001c, 0xd3900, 0x24080001,
+0xafa80010, 0x94900, 0x1201821, 0x16d5821,
+0x254affff, 0x16a8024, 0xafb00014, 0x8f480014,
+0x1021, 0xa32821, 0xa3482b, 0x822021,
+0x892021, 0xafa80018, 0x8f420108, 0x63100,
+0x40f809, 0x1863021, 0x54400001, 0xaf500024,
+0x8f430024, 0x8f420020, 0x14620019, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x2403ffef, 0x431024,
+0xaf820060, 0x8f420000, 0x10400004, 0x0,
+0xaf80004c, 0x10000002, 0x0, 0xaf800048,
+0x8fbf0028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0030, 0x3e00008, 0x0, 0x27bdffc0,
+0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
+0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
+0x10000002, 0x0, 0x8f530020, 0x8f420030,
+0x10530102, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
+0x9611000a, 0x3246ffff, 0x46102a, 0x10400018,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400007, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x8f420348, 0x100000f8, 0x0,
+0x8f8200fc, 0x14400007, 0x0, 0x8f420344,
+0x24420001, 0xaf420344, 0x8f420344, 0x100000ef,
+0x0, 0x934205c2, 0x1040000b, 0x32c20008,
+0x10400008, 0x32220200, 0x10400006, 0x3c034000,
+0x9602000e, 0xaf4300ac, 0x21400, 0x10000002,
+0xaf4200b0, 0xaf4000ac, 0x32220004, 0x10400094,
+0x32220800, 0x10400003, 0x3247ffff, 0x10000002,
+0x24020020, 0x24020004, 0xafa20010, 0x8f420030,
+0xafa20014, 0x8f420010, 0x3c030002, 0x431025,
+0xafa20018, 0x8f460098, 0x8f420108, 0x40f809,
+0x0, 0x104000cd, 0x0, 0x8f42009c,
+0x8f430094, 0x2421021, 0xaf42009c, 0xae03000c,
+0x8f4200ac, 0x10400008, 0x3c034000, 0x8f420094,
+0x431025, 0xafa20020, 0x8f42009c, 0x8f4300b0,
+0x10000004, 0x431025, 0x8f420094, 0xafa20020,
+0x8f42009c, 0xafa20024, 0x8f9000fc, 0x16000014,
+0x240200e1, 0x3c040001, 0x24847e74, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e7c,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8fa20020, 0x8fa30024, 0xae020000, 0xae030004,
+0x26020008, 0xaf8200f0, 0x8f42009c, 0x8f440270,
+0x8f450274, 0x401821, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0x32230060,
+0x24020040, 0xaf440270, 0xaf450274, 0x10620017,
+0x2c620041, 0x10400005, 0x24020020, 0x10620008,
+0x24020001, 0x10000026, 0x0, 0x24020060,
+0x10620019, 0x24020001, 0x10000021, 0x0,
+0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001,
+0x441021, 0xaf420278, 0xaf43027c, 0x8f420278,
+0x8f43027c, 0x10000016, 0x24020001, 0x8f420280,
+0x8f430284, 0x24630001, 0x2c640001, 0x441021,
+0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
+0x1000000b, 0x24020001, 0x8f420288, 0x8f43028c,
+0x24630001, 0x2c640001, 0x441021, 0xaf420288,
+0xaf43028c, 0x8f420288, 0x8f43028c, 0x24020001,
+0xa34205c2, 0x8f420098, 0x3244ffff, 0x2406fff8,
+0x8f45013c, 0x441021, 0x24420007, 0x461024,
+0x24840007, 0xaf420094, 0x8f420090, 0x8f430094,
+0x862024, 0x441023, 0x65182b, 0x14600005,
+0xaf420090, 0x8f420094, 0x8f430144, 0x431023,
+0xaf420094, 0x8f420094, 0x10000023, 0xaf40009c,
+0x3247ffff, 0x50e00022, 0x32c20020, 0x14400002,
+0x24020010, 0x24020002, 0xafa20010, 0x8f420030,
+0xafa20014, 0x8f420010, 0xafa20018, 0x8f460098,
+0x8f420108, 0x40f809, 0x0, 0x1040003b,
+0x3245ffff, 0x8f420098, 0x8f430090, 0x8f46013c,
+0x451021, 0xaf420098, 0x8f42009c, 0x8f440098,
+0xa34005c2, 0x651823, 0xaf430090, 0x451021,
+0x86202b, 0x14800005, 0xaf42009c, 0x8f420098,
+0x8f430144, 0x431023, 0xaf420098, 0x32c20020,
+0x10400005, 0x0, 0x8f420358, 0x2442ffff,
+0xaf420358, 0x8f420358, 0x8f420030, 0x8f430040,
+0x24420001, 0x2463ffff, 0x431024, 0xaf420030,
+0x8f420030, 0x14530019, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x10000002, 0x0, 0xaf800048, 0x8fbf0038,
+0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
+0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
+0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
+0x10000002, 0x0, 0x8f520020, 0x8f420030,
+0x105200b7, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
+0x9607000a, 0x3226ffff, 0x46102a, 0x10400018,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400007, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x8f420348, 0x100000ad, 0x0,
+0x8f8600fc, 0x10c0000c, 0x0, 0x8f8200f4,
+0x2403fff8, 0x431024, 0x461023, 0x218c3,
+0x58600001, 0x24630100, 0x8f42008c, 0x43102b,
+0x14400007, 0x712c2, 0x8f420344, 0x24420001,
+0xaf420344, 0x8f420344, 0x10000099, 0x0,
+0x934305c2, 0x1060000f, 0x30460001, 0x8f420010,
+0x34480400, 0x32c20008, 0x10400008, 0x30e20200,
+0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
+0x21400, 0x10000004, 0xaf4200b0, 0x10000002,
+0xaf4000ac, 0x8f480010, 0x30e20004, 0x10400045,
+0x3227ffff, 0x8f4900ac, 0x11200005, 0x30c200ff,
+0x14400006, 0x24020040, 0x10000004, 0x24020008,
+0x14400002, 0x24020020, 0x24020004, 0xafa20010,
+0x8f430030, 0x11200004, 0xafa30014, 0x8f4200b0,
+0x621025, 0xafa20014, 0x3c020002, 0x1021025,
+0xafa20018, 0x8f460098, 0x8f420108, 0x40f809,
+0x0, 0x1040006a, 0x3224ffff, 0x8f42008c,
+0x8f430094, 0x24420001, 0xaf42008c, 0x24020001,
+0xae03000c, 0xa34205c2, 0x8f420098, 0x2406fff8,
+0x8f45013c, 0x441021, 0x24420007, 0x461024,
+0x24840007, 0xaf420094, 0x8f420090, 0x8f430094,
+0x862024, 0x441023, 0x65182b, 0x14600005,
+0xaf420090, 0x8f420094, 0x8f430144, 0x431023,
+0xaf420094, 0x8f430094, 0x8f420140, 0x43102b,
+0x10400009, 0x0, 0x8f43013c, 0x8f440094,
+0x8f420090, 0x8f450138, 0x641823, 0x431023,
+0xaf420090, 0xaf450094, 0x8f420094, 0x1000001f,
+0xaf420098, 0x10e0001d, 0x30c200ff, 0x14400002,
+0x24020010, 0x24020002, 0xafa20010, 0x8f420030,
+0xafa80018, 0xafa20014, 0x8f460098, 0x8f420108,
+0x40f809, 0x0, 0x10400031, 0x3225ffff,
+0x8f420098, 0x8f44013c, 0x451021, 0xaf420098,
+0x8f420090, 0x8f430098, 0xa34005c2, 0x451023,
+0x64182b, 0x14600005, 0xaf420090, 0x8f420098,
+0x8f430144, 0x431023, 0xaf420098, 0x8f420030,
+0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+0xaf420030, 0x8f420030, 0x14520019, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x2403fff7, 0x431024,
+0xaf820060, 0x8f420000, 0x10400004, 0x0,
+0xaf80004c, 0x10000002, 0x0, 0xaf800048,
+0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+0x3e00008, 0x27bd0030, 0x3e00008, 0x0,
+0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f4300f0,
+0x8f4200ec, 0x8f900108, 0x14620017, 0x3c020001,
+0x3c040001, 0x24847e74, 0x240204ea, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e84,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x3c020001, 0x8f4300f0, 0x34422ec0, 0x2e21021,
+0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
+0x8f4200ec, 0x8c660004, 0x14620005, 0x3c020001,
+0x26020020, 0xaf820108, 0x1000000f, 0x0,
+0x8f4300f0, 0x34422ec0, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422cc0, 0x2e21021,
+0x401821, 0x8c620004, 0x21140, 0x2021021,
+0xaf820108, 0xac600000, 0x8e050018, 0x30a20036,
+0x1040006d, 0x30a20001, 0x8e02001c, 0x8f430040,
+0x8f440034, 0x24420001, 0x2463ffff, 0x431024,
+0x862021, 0xaf42002c, 0x30a20030, 0x14400006,
+0xaf440034, 0x8f420034, 0x8c03023c, 0x43102b,
+0x144000cf, 0x0, 0x32c20010, 0x10400028,
+0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
+0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
+0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
+0x8f820128, 0x3c040001, 0x24847e64, 0xafa20014,
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002d3b,
+0x34a51100, 0x10000036, 0x0, 0x8f420300,
+0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
+0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x24847e58, 0xafa20014, 0x8f46002c,
+0x8f870120, 0x3c050009, 0xc002d3b, 0x34a50900,
+0x1000000f, 0x0, 0x8f420300, 0x24420001,
+0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
+0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
+0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
+0x8f420314, 0x24420001, 0xaf420314, 0x8f420314,
+0x10000073, 0x0, 0x10400025, 0x30a27000,
+0x8e05001c, 0x8f420028, 0xa22023, 0x4810003,
+0x0, 0x8f420040, 0x822021, 0x8f420358,
+0x8f430000, 0xaf450028, 0x441021, 0xaf420358,
+0x10600007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420008, 0xaf820060, 0x8f420000,
+0x10400004, 0x0, 0xaf80004c, 0x10000050,
+0x0, 0xaf800048, 0x1000004d, 0x0,
+0x1040002f, 0x30a21000, 0x1040000c, 0x30a24000,
+0x8e03001c, 0x8f420050, 0x622023, 0x4820001,
+0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
+0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
+0x32c28000, 0x8e03001c, 0x8f420070, 0x622023,
+0x4820001, 0x24840400, 0x8f420364, 0x441021,
+0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
+0x1040000e, 0x3c020800, 0x8e03001c, 0x8f420060,
+0x622023, 0x4820001, 0x24840100, 0x8f420360,
+0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
+0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
+0x5040001f, 0x36940040, 0x1000001d, 0x0,
+0x30a20100, 0x10400005, 0x30a20080, 0xc002dd7,
+0x0, 0x10000016, 0x0, 0x14400014,
+0x240205dd, 0x3c040001, 0x24847e74, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e84,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
+0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
+0xafb1004c, 0xafb00048, 0x8f920108, 0x8f820104,
+0x16420016, 0x26420020, 0x3c040001, 0x24847e74,
+0x240205f8, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e77e84, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x26420020, 0xaf820108,
+0x8e530018, 0xa3a0003f, 0x32620024, 0x1040022c,
+0xafa00034, 0x8e50001c, 0x8f42001c, 0x101900,
+0x431021, 0x8c51000c, 0x8f430140, 0x965e0016,
+0x9455000a, 0x71182b, 0x10600014, 0x24020634,
+0x3c040001, 0x24847e74, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77e84, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x9624000c,
+0x2c8305dd, 0x38828870, 0x2c420001, 0x621825,
+0x10600015, 0x2821, 0x32c20040, 0x10400015,
+0x24020800, 0x96230014, 0x14620012, 0x3402aaaa,
+0x9623000e, 0x14620007, 0x2021, 0x96230010,
+0x24020300, 0x14620004, 0x801021, 0x96220012,
+0x2c440001, 0x801021, 0x54400006, 0x24050016,
+0x10000004, 0x0, 0x24020800, 0x50820001,
+0x2405000e, 0x934205c3, 0x14400008, 0x5021,
+0x240a0001, 0x32a20180, 0xaf4500a8, 0xaf5100a0,
+0x10400002, 0xaf5000a4, 0xa34a05c3, 0x10a00086,
+0x2253821, 0x90e20000, 0x3021, 0x3042000f,
+0x24880, 0x32c20002, 0x10400012, 0xe91821,
+0x32a20002, 0x10400010, 0x32c20001, 0xe02021,
+0x94820000, 0x24840002, 0xc23021, 0x83102b,
+0x1440fffb, 0x30c2ffff, 0x61c02, 0x623021,
+0x61c02, 0x30c2ffff, 0x623021, 0x61027,
+0xa4e2000a, 0x32c20001, 0x1040006b, 0x32a20001,
+0x10400069, 0x0, 0x8f4200a8, 0x10400066,
+0x0, 0x8f4200a0, 0x8f4300a8, 0x431021,
+0x904b0009, 0x316800ff, 0x39030006, 0x3182b,
+0x39020011, 0x2102b, 0x621824, 0x1060000d,
+0x3c050006, 0x3c040001, 0x24847e8c, 0x8f4200a4,
+0x34a54600, 0xafa20010, 0x8f4200a0, 0x2003021,
+0x1003821, 0xc002d3b, 0xafa20014, 0x1000004e,
+0x0, 0x32c20004, 0x14400013, 0x2821,
+0x314200ff, 0x14400004, 0x0, 0x94e20002,
+0x1000000d, 0x492823, 0x94e5000c, 0x94e2000e,
+0x94e30010, 0xa22821, 0xa32821, 0x94e30012,
+0x90e40009, 0x94e20002, 0xa32821, 0xa42821,
+0x491023, 0xa22821, 0x2202021, 0x94820000,
+0x24840002, 0xc23021, 0x87102b, 0x1440fffb,
+0x61c02, 0x30c2ffff, 0x623021, 0x61c02,
+0x30c2ffff, 0x623021, 0x3c52821, 0x51c02,
+0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
+0x622821, 0xa62823, 0x51402, 0xa22821,
+0x30a5ffff, 0x50a00001, 0x3405ffff, 0x314200ff,
+0x14400008, 0x316300ff, 0x8f4300a0, 0x8f4200a8,
+0x623821, 0x90e20000, 0x3042000f, 0x24880,
+0x316300ff, 0x24020006, 0x14620003, 0xe91021,
+0x10000002, 0x24440010, 0x24440006, 0x314200ff,
+0x14400006, 0x0, 0x94820000, 0xa22821,
+0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
+0x10400003, 0x32a20100, 0x50400003, 0xa4850000,
+0x52827, 0xa4850000, 0x9642000e, 0x8f43009c,
+0x621821, 0xaf43009c, 0x93a2003f, 0x10400007,
+0x3c024000, 0x2221025, 0xafa20020, 0x8f42009c,
+0x8fac0034, 0x10000003, 0x4c1025, 0xafb10020,
+0x8f42009c, 0xafa20024, 0x32a20080, 0x10400027,
+0x32a20100, 0x8f4200b4, 0x2c420100, 0x14400014,
+0x2402076a, 0x3c040001, 0x24847e74, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e84,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
+0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
+0x220821, 0xac2338e8, 0x3c010001, 0x220821,
+0xac2438ec, 0x100000e7, 0x32c20020, 0x10400091,
+0x0, 0x8f4200b4, 0x2c420100, 0x14400014,
+0x24020778, 0x3c040001, 0x24847e74, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e84,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
+0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
+0x220821, 0xac2338e8, 0x3c010001, 0x220821,
+0xac2438ec, 0x8f4200b4, 0x10400067, 0x8821,
+0x1110c0, 0x571021, 0x3c030001, 0x621821,
+0x8c6338e8, 0x3c040001, 0x822021, 0x8c8438ec,
+0xafa30028, 0xafa4002c, 0x8f9000fc, 0x16000014,
+0x240200f4, 0x3c040001, 0x24847e74, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77e7c,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8fa20028, 0x8fa3002c, 0xae020000, 0xae030004,
+0x26020008, 0xaf8200f0, 0x8f42008c, 0x2442ffff,
+0xaf42008c, 0x97a2002e, 0x8f440270, 0x8f450274,
+0x401821, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaf440270, 0xaf450274,
+0x8fa30028, 0x3c02001f, 0x3442ffff, 0x622024,
+0x90820000, 0x30420001, 0x1440000c, 0x2402ffff,
+0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001,
+0x441021, 0xaf420278, 0xaf43027c, 0x8f420278,
+0x8f43027c, 0x1000001b, 0x0, 0x8c830000,
+0x1462000f, 0x3402ffff, 0x94830004, 0x1462000c,
+0x0, 0x8f420288, 0x8f43028c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
+0x8f420288, 0x8f43028c, 0x1000000a, 0x0,
+0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
+0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
+0x8f430284, 0x8f4200b4, 0x26310001, 0x222102b,
+0x1440ff9c, 0x1110c0, 0xa34005c3, 0x10000054,
+0xaf4000b4, 0x8f9000fc, 0x16000014, 0x240200f4,
+0x3c040001, 0x24847e74, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77e7c, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fa20020,
+0x8fa30024, 0xae020000, 0xae030004, 0x26020008,
+0xaf8200f0, 0x8f42009c, 0x8f46008c, 0x8f440270,
+0x8f450274, 0x401821, 0x1021, 0x24c6ffff,
+0xaf46008c, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaf440270, 0xaf450274, 0x92220000,
+0x30420001, 0x1440000c, 0x2402ffff, 0x8f420278,
+0x8f43027c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420278, 0xaf43027c, 0x8f420278, 0x8f43027c,
+0x1000001c, 0x32c20020, 0x8e230000, 0x1462000f,
+0x3402ffff, 0x96230004, 0x1462000c, 0x0,
+0x8f420288, 0x8f43028c, 0x24630001, 0x2c640001,
+0x441021, 0xaf420288, 0xaf43028c, 0x8f420288,
+0x8f43028c, 0x1000000b, 0x32c20020, 0x8f420280,
+0x8f430284, 0x24630001, 0x2c640001, 0x441021,
+0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
+0x32c20020, 0x10400005, 0xaf40009c, 0x8f420358,
+0x2442ffff, 0xaf420358, 0x8f420358, 0x8e42001c,
+0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+0xaf42002c, 0x32620060, 0x14400008, 0x32c20010,
+0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
+0x43102b, 0x1440011f, 0x32c20010, 0x10400018,
+0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
+0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+0x24c6001c, 0x10400047, 0x24020001, 0x8f420300,
+0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
+0x24020001, 0xa34205c1, 0x1000007c, 0xaf430038,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x10400057, 0x24020001, 0x10000065, 0x0,
+0x32620012, 0x10400076, 0x32620001, 0x9642000e,
+0x8f43009c, 0x621821, 0x32c20020, 0x10400005,
+0xaf43009c, 0x8f420358, 0x2442ffff, 0xaf420358,
+0x8f420358, 0x8e42001c, 0x8f430040, 0x24420001,
+0x2463ffff, 0x431024, 0xaf42002c, 0x32620010,
+0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
+0xaf420034, 0x8c03023c, 0x43102b, 0x144000d9,
+0x32c20010, 0x10400028, 0x24070008, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x24847e64, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002d3b, 0x34a51100, 0x10000036,
+0x0, 0x8f420300, 0x8f43002c, 0x24420001,
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+0x10000026, 0xaf430038, 0x8f440170, 0x8f450174,
+0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f0, 0x8f820124,
+0xafa20010, 0x8f820128, 0x3c040001, 0x24847e58,
+0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009,
+0xc002d3b, 0x34a50900, 0x1000000f, 0x0,
+0x8f420300, 0x24420001, 0xaf420300, 0x8f420300,
+0x8f42002c, 0xa34005c1, 0xaf420038, 0x3c010001,
+0x370821, 0xa02040f1, 0x3c010001, 0x370821,
+0xa02040f0, 0xaf400034, 0x8f420314, 0x24420001,
+0xaf420314, 0x8f420314, 0x1000007e, 0x0,
+0x10400025, 0x32627000, 0x8e45001c, 0x8f420028,
+0xa22023, 0x4810003, 0x0, 0x8f420040,
+0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
+0x441021, 0xaf420358, 0x10600007, 0x0,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x34420008,
+0xaf820060, 0x8f420000, 0x10400004, 0x0,
+0xaf80004c, 0x1000005b, 0x0, 0xaf800048,
+0x10000058, 0x0, 0x1040002f, 0x32621000,
+0x1040000c, 0x32624000, 0x8e43001c, 0x8f420050,
+0x622023, 0x4820001, 0x24840200, 0x8f42035c,
+0x441021, 0xaf42035c, 0x8f420368, 0x1000001a,
+0xaf430050, 0x1040000c, 0x32c28000, 0x8e43001c,
+0x8f420070, 0x622023, 0x4820001, 0x24840400,
+0x8f420364, 0x441021, 0xaf420364, 0x8f420368,
+0x1000000d, 0xaf430070, 0x1040000e, 0x3c020800,
+0x8e43001c, 0x8f420060, 0x622023, 0x4820001,
+0x24840100, 0x8f420360, 0x441021, 0xaf420360,
+0x8f420368, 0xaf430060, 0x441021, 0xaf420368,
+0x3c020800, 0x2c21024, 0x5040002a, 0x36940040,
+0x10000028, 0x0, 0x32620048, 0x10400009,
+0x240c0001, 0x8e42001c, 0x3c03ffff, 0xa3ac003f,
+0x431824, 0x3042ffff, 0xafa30034, 0x1000fcfd,
+0xae42001c, 0x32620100, 0x10400005, 0x32620080,
+0xc002dd7, 0x0, 0x10000016, 0x0,
+0x14400014, 0x24020896, 0x3c040001, 0x24847e74,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e77e84, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
+0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
+0x3e00008, 0x27bd0068, 0x3e00008, 0x0,
+0x8f8300e4, 0x8f8200e0, 0x2404fff8, 0x441024,
+0x621026, 0x2102b, 0x21023, 0x3e00008,
+0x621024, 0x3e00008, 0x0, 0x27bdffe0,
+0xafbf001c, 0xafb00018, 0x8f8600c4, 0x8f8400e0,
+0x8f8500e4, 0x2402fff8, 0x821824, 0x10a30009,
+0x27623ff8, 0x14a20002, 0x24a20008, 0x27623000,
+0x408021, 0x16030005, 0x30820004, 0x10400004,
+0xc02021, 0x10000022, 0x1021, 0x8e040000,
+0x8f42011c, 0x14a20003, 0x0, 0x8f420120,
+0xaf420114, 0x8ca30000, 0x8f420148, 0x831823,
+0x43102b, 0x10400003, 0x0, 0x8f420148,
+0x621821, 0x94a20006, 0x24420050, 0x62102b,
+0x1440000f, 0xa01021, 0xafa40010, 0xafa30014,
+0x8ca60000, 0x8ca70004, 0x3c040001, 0xc002d3b,
+0x24847f5c, 0x8f42020c, 0x24420001, 0xaf42020c,
+0x8f42020c, 0x1021, 0xaf9000e8, 0xaf9000e4,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x3e00008, 0x0, 0x8f8300e4, 0x27623ff8,
+0x14620002, 0x24620008, 0x27623000, 0x401821,
+0xaf8300e8, 0xaf8300e4, 0x3e00008, 0x0,
+0x3e00008, 0x0, 0x8f8400e0, 0x8f8800c4,
+0x8f8300e8, 0x2402fff8, 0x823824, 0xe32023,
+0x2c821000, 0x50400001, 0x24841000, 0x420c2,
+0x801821, 0x8f440258, 0x8f45025c, 0x1021,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xaf440258, 0xaf45025c, 0x8f8300c8, 0x8f420148,
+0x1032023, 0x82102b, 0x14400004, 0x801821,
+0x8f420148, 0x822021, 0x801821, 0x8f440250,
+0x8f450254, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaf440250, 0xaf450254,
+0xaf8800c8, 0xaf8700e4, 0xaf8700e8, 0x3e00008,
+0x0, 0x27bdff28, 0x240a0001, 0xafbf00d0,
+0xafbe00cc, 0xafb500c8, 0xafb300c4, 0xafb200c0,
+0xafb100bc, 0xafb000b8, 0xa3a0009f, 0xafa0004c,
+0xafaa0064, 0xa7a00096, 0xafa00040, 0x934205c4,
+0x8821, 0x1040000a, 0xa7a0008e, 0x8f4b00c4,
+0xafab006c, 0x8f4a00c0, 0xafaa0074, 0x8f4b00cc,
+0xafab007c, 0x8f4a00c8, 0x1000019f, 0xafaa0084,
+0x8f420114, 0x40f809, 0x0, 0x403021,
+0x10c00418, 0x0, 0x8cc20000, 0x8cc30004,
+0xafa20020, 0xafa30024, 0x8fab0024, 0x8faa0020,
+0x3162ffff, 0x2442fffc, 0xafa20074, 0x3c020006,
+0x2c21024, 0xafab0084, 0x14400015, 0xafaa006c,
+0x91420000, 0x30420001, 0x10400011, 0x2402ffff,
+0x8d430000, 0x14620004, 0x3402ffff, 0x95430004,
+0x1062000b, 0x0, 0xc0025dd, 0x8fa4006c,
+0x304200ff, 0x14400006, 0x0, 0x8f420118,
+0x40f809, 0x0, 0x100003f6, 0x0,
+0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024,
+0x3c03ffff, 0x431824, 0x14600003, 0xafa20024,
+0x10000040, 0x1821, 0x3c020080, 0x621024,
+0x10400007, 0x0, 0x8f42038c, 0x24420001,
+0xaf42038c, 0x8f42038c, 0x10000036, 0x24030001,
+0x8f420210, 0x24420001, 0xaf420210, 0x8f420210,
+0x3c020001, 0x621024, 0x10400006, 0x3c020002,
+0x8f4201c4, 0x24420001, 0xaf4201c4, 0x8f4201c4,
+0x3c020002, 0x621024, 0x10400006, 0x3c020004,
+0x8f42037c, 0x24420001, 0xaf42037c, 0x8f42037c,
+0x3c020004, 0x621024, 0x10400006, 0x3c020008,
+0x8f420380, 0x24420001, 0xaf420380, 0x8f420380,
+0x3c020008, 0x621024, 0x10400006, 0x3c020010,
+0x8f420384, 0x24420001, 0xaf420384, 0x8f420384,
+0x3c020010, 0x621024, 0x10400006, 0x3c020020,
+0x8f4201c0, 0x24420001, 0xaf4201c0, 0x8f4201c0,
+0x3c020020, 0x621024, 0x10400006, 0x24030001,
+0x8f420388, 0x24420001, 0xaf420388, 0x8f420388,
+0x24030001, 0x8c020260, 0x8fab0074, 0x4b102b,
+0x10400014, 0x307000ff, 0x8f4201e8, 0x24420001,
+0xaf4201e8, 0x8f4201e8, 0x8faa0084, 0x8f8200e0,
+0x354a0100, 0xafaa0084, 0xafa20010, 0x8f8200e4,
+0x24100001, 0x3c040001, 0x24847f68, 0xafa20014,
+0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002d3b,
+0x34a50800, 0x12000011, 0x3c020080, 0x2c21024,
+0x1440000f, 0x32c20400, 0x8fab0084, 0x3c020080,
+0x34420100, 0x1621024, 0x10400005, 0x0,
+0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+0x8fa30074, 0x10000377, 0x0, 0x32c20400,
+0x10400015, 0x34028100, 0x8faa006c, 0x9543000c,
+0x14620012, 0x3c020100, 0x240b0200, 0xa7ab0096,
+0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
+0x8faa0074, 0x8fab006c, 0x254afffc, 0xafaa0074,
+0xa7a2008e, 0xad63000c, 0xad640008, 0xad650004,
+0x256b0004, 0xafab006c, 0x3c020100, 0x2c21024,
+0x10400004, 0x0, 0x8faa0074, 0x254a0004,
+0xafaa0074, 0x16000005, 0x24020800, 0x8fab006c,
+0x9563000c, 0x50620001, 0x2411000e, 0x8f4200bc,
+0x5040000a, 0xafa0007c, 0x8faa0074, 0x4a102b,
+0x50400006, 0xafa0007c, 0x8f4200bc, 0x1421023,
+0xafa2007c, 0x8f4b00bc, 0xafab0074, 0x8f420080,
+0x8faa0074, 0x4a102b, 0x104000c5, 0x32c28000,
+0x104000cd, 0x32c21000, 0x10400058, 0x240b0004,
+0x3c021000, 0x2c21024, 0x104000c7, 0xafab0064,
+0x122000c5, 0x0, 0x8faa006c, 0x8fab0074,
+0x1711023, 0x2c420014, 0x144000c0, 0x1512021,
+0x24830006, 0x90820000, 0x3c05001f, 0x34a5ffff,
+0x3042000f, 0x23080, 0xa3102b, 0x10400003,
+0x0, 0x8f420148, 0x621823, 0x94620000,
+0x30421fff, 0x10400003, 0x2261021, 0x100000ae,
+0xafa20040, 0x24830009, 0xa3102b, 0x10400003,
+0x0, 0x8f420148, 0x621823, 0x90630000,
+0x24020006, 0x14620017, 0x24020011, 0x94820002,
+0x2c420028, 0x144000a0, 0x861821, 0xa3102b,
+0x50400004, 0x2463000c, 0x8f420148, 0x621823,
+0x2463000c, 0xa3102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x90630000, 0x306200f0,
+0x21882, 0x2261021, 0x431021, 0x1000008e,
+0xafa20040, 0x1462008c, 0x0, 0x94820002,
+0x2c42001c, 0x14400088, 0x2263821, 0x94830002,
+0x24e20008, 0x2c63009c, 0x14600083, 0xafa20040,
+0x861821, 0xa3102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x94620000, 0x24040801,
+0x10440004, 0x24e20088, 0x94620002, 0x14440076,
+0x24e20088, 0x10000074, 0xafa20040, 0x10000071,
+0x240a0003, 0x8f420350, 0x2403ffbf, 0x283a024,
+0x24420001, 0xaf420350, 0x8f420350, 0x100002b8,
+0x0, 0x2c2b025, 0x2402ffbf, 0x282a024,
+0x8f830128, 0x3c040001, 0x24847fa0, 0x26620001,
+0xafa20014, 0xafa30010, 0x8f860120, 0x8f870124,
+0x3c050007, 0xc002d3b, 0x34a52250, 0x100002a8,
+0x0, 0x2c2b025, 0x2402ffbf, 0x282a024,
+0x8f830128, 0x3c040001, 0x24847fa0, 0x24020002,
+0xafa20014, 0xafa30010, 0x8f860120, 0x8f870124,
+0x3c050007, 0xc002d3b, 0x34a52450, 0x10000298,
+0x0, 0x8ea20000, 0x8ea30004, 0x3c040001,
+0x24847fb8, 0xafb00010, 0xafbe0014, 0x8ea70018,
+0x34a52800, 0xc002d3b, 0x603021, 0x3c040001,
+0x24847f4c, 0x1000001f, 0x2402058d, 0xa6b1000a,
+0x8f820124, 0x3c040001, 0x24847fc0, 0xafbe0014,
+0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007,
+0xc002d3b, 0x34a53000, 0x3c040001, 0x24847f4c,
+0x10000010, 0x240205c9, 0xa6b1000a, 0xa6b2000e,
+0x8f820124, 0x3c040001, 0x24847fcc, 0xafbe0014,
+0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007,
+0xc002d3b, 0x34a53200, 0x3c040001, 0x24847f4c,
+0x240205fe, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070001, 0x24e77f98, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x10000259, 0x0,
+0x8f420084, 0x8fab0074, 0x4b102b, 0x14400007,
+0x3c020001, 0x2c21024, 0x10400004, 0x0,
+0x240a0002, 0xafaa0064, 0x8fab0074, 0x1160026d,
+0x27aa0020, 0xafaa00ac, 0x3c0b001f, 0x356bffff,
+0xafab00a4, 0x8faa0064, 0x240b0001, 0x154b0022,
+0x24020002, 0x8f430054, 0x8f420050, 0x1062000b,
+0x274a0054, 0x8f5e0054, 0x3403ecc0, 0xafaa0054,
+0x27c20001, 0x304201ff, 0xafa2005c, 0x1e1140,
+0x431021, 0x10000077, 0x2e2a821, 0x8f420044,
+0x8fab0074, 0x3c040001, 0x24847f74, 0xafab0014,
+0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
+0xc002d3b, 0x34a51300, 0x8f430350, 0x2402ffbf,
+0x282a024, 0x24630001, 0xaf430350, 0x8f420350,
+0x10000223, 0x0, 0x1542001d, 0x0,
+0x8f430074, 0x8f420070, 0x1062000a, 0x274b0074,
+0x8f5e0074, 0xafab0054, 0x27c20001, 0x304203ff,
+0xafa2005c, 0x1e1140, 0x24426cc0, 0x10000055,
+0x2e2a821, 0x8f420044, 0x8faa0074, 0x3c040001,
+0x24847f80, 0x3c050007, 0xafaa0014, 0xafa20010,
+0x8f460074, 0x8f470070, 0x34a51500, 0x240b0001,
+0xc002d3b, 0xafab0064, 0x1000ffc2, 0x0,
+0x8f430064, 0x8f420060, 0x1062002b, 0x274a0064,
+0x8f5e0064, 0x8fab0064, 0xafaa0054, 0x27c20001,
+0x304200ff, 0xafa2005c, 0x24020004, 0x1562001f,
+0x1e1140, 0x1e1180, 0x24420cc0, 0x2e21021,
+0xafa2004c, 0x24550020, 0x3c021000, 0x2c21024,
+0x1040000e, 0x0, 0x8faa004c, 0x8fab0074,
+0x9542002a, 0x4b102b, 0x54400006, 0x240a0001,
+0x8fa20040, 0x10400027, 0x0, 0x104b0025,
+0x240a0001, 0x10000023, 0xa3aa009f, 0x8fab004c,
+0x8faa0074, 0x9562002a, 0x4a102b, 0x1040001d,
+0x240b0001, 0x1000001b, 0xa3ab009f, 0x24424cc0,
+0x10000018, 0x2e2a821, 0x8f420044, 0x8faa0074,
+0x3c040001, 0x24847f8c, 0xafaa0014, 0xafa20010,
+0x8f460064, 0x8f470060, 0x3c050007, 0xc002d3b,
+0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff09,
+0x0, 0x8f420370, 0x240b0001, 0xafab0064,
+0x24420001, 0xaf420370, 0x8f420370, 0x1000ff7d,
+0x0, 0x8faa006c, 0xaeaa0018, 0x93a2009f,
+0x104000ae, 0x24050002, 0x8fab004c, 0x8fa40040,
+0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
+0x25620010, 0xafab002c, 0x1080000e, 0xafa20034,
+0x9563002a, 0x83102b, 0x54400001, 0x801821,
+0x1000000b, 0xa7a30038, 0x27a30036, 0x131040,
+0x621821, 0x94620000, 0x441021, 0x10000016,
+0xa4620000, 0x8faa004c, 0x9542002a, 0xa7a20038,
+0x8fab004c, 0x8fa40074, 0x8fa300ac, 0x95620018,
+0xa7a2003a, 0x9562001a, 0xa7a2003c, 0x9562001c,
+0x9821, 0xa7a2003e, 0x94620018, 0x24630002,
+0x822023, 0x1880ffe8, 0x26730001, 0x2e620004,
+0x1440fff9, 0x0, 0x18800014, 0x2402052b,
+0x3c040001, 0x24847f4c, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77f98, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8f4200fc,
+0x26650001, 0xa2102a, 0x1440003f, 0x24030001,
+0x8f83012c, 0x10600037, 0x0, 0x8f820124,
+0x431023, 0x22143, 0x58800001, 0x24840040,
+0x8f820128, 0x431023, 0x21943, 0x58600001,
+0x24630040, 0x64102a, 0x54400001, 0x602021,
+0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400025,
+0x24030001, 0x10000029, 0x306200ff, 0x8faa006c,
+0x96070018, 0xafaa0010, 0x8e220008, 0x3c040001,
+0x24847fac, 0x8c430004, 0x8c420000, 0x34a52400,
+0x2403021, 0xc002d3b, 0xafa30014, 0x3c040001,
+0x24847f4c, 0x2402054f, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77f98, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x1000002b,
+0x0, 0x8f420334, 0x1821, 0x24420001,
+0xaf420334, 0x8f420334, 0x306200ff, 0x5040fe7d,
+0x3c020800, 0x12600021, 0x9021, 0x8fb100ac,
+0x2208021, 0x8e220008, 0x96070018, 0x8fa6006c,
+0x8c440000, 0x8c450004, 0x240b0001, 0xafab0010,
+0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
+0x40f809, 0x0, 0x1040ffc4, 0x3c050007,
+0x96020018, 0x8faa006c, 0x8fab00a4, 0x1425021,
+0x16a102b, 0x10400004, 0xafaa006c, 0x8f420148,
+0x1425023, 0xafaa006c, 0x26100002, 0x26520001,
+0x253102b, 0x1440ffe3, 0x26310004, 0x8fb00074,
+0x97b10038, 0x10000035, 0x0, 0x8f4200fc,
+0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
+0x10600013, 0x0, 0x8f820124, 0x431023,
+0x22143, 0x58800001, 0x24840040, 0x8f820128,
+0x431023, 0x21943, 0x58600001, 0x24630040,
+0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
+0x8f420334, 0x1821, 0x24420001, 0xaf420334,
+0x8f420334, 0x306200ff, 0x1040fe46, 0x3c020800,
+0x96b1000a, 0x8fb00074, 0x3223ffff, 0x70102b,
+0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
+0x240a0001, 0xafaa0010, 0xafbe0014, 0x8f420008,
+0x8fa6006c, 0xafa20018, 0x8f42010c, 0x40f809,
+0x2003821, 0x1040fe43, 0x3c050007, 0x96a4000e,
+0x97ab0096, 0x11600007, 0x809021, 0x934205c4,
+0x14400004, 0x0, 0x97aa008e, 0x8b2025,
+0xa6aa0016, 0x8fab0084, 0x3c02ffff, 0x1621024,
+0x10400003, 0xb1402, 0x34840400, 0xa6a20014,
+0x3c021000, 0x2c21024, 0x10400006, 0x0,
+0x8fa20040, 0x401821, 0x1021, 0xaea20000,
+0xaea30004, 0x8faa0074, 0x560a0073, 0xa6a4000e,
+0x34820004, 0xa6a2000e, 0x8fab007c, 0x14b1021,
+0xa6a2000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
+0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
+0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
+0x604821, 0xafa20018, 0x8f42010c, 0x4021,
+0xa92821, 0xa9182b, 0x882021, 0x40f809,
+0x832021, 0x5040fe19, 0xa6b2000e, 0x8f420368,
+0xafa00074, 0xa34005c4, 0x2442ffff, 0xaf420368,
+0x8faa0064, 0x240b0001, 0x8f420368, 0x154b0006,
+0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
+0x1000000c, 0x8f42035c, 0x15420006, 0x0,
+0x8f420364, 0x2442ffff, 0xaf420364, 0x10000005,
+0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
+0x8f420360, 0x8faa005c, 0x8fab0054, 0xad6a0000,
+0x8f420044, 0x8f440088, 0x8f430078, 0x24420001,
+0x441024, 0x24630001, 0xaf420044, 0xaf430078,
+0x8c020240, 0x62182b, 0x14600076, 0x24070008,
+0x8f440168, 0x8f45016c, 0x8f430044, 0x8f48000c,
+0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x240b0001, 0x3c010001, 0x370821,
+0xa02b40f2, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x24847f44, 0xafa20014, 0x8f460044,
+0x8f870120, 0x3c050009, 0xc002d3b, 0x34a51300,
+0x1000000b, 0x0, 0x8f420304, 0x24420001,
+0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
+0x3c010001, 0x370821, 0xa02040f2, 0xaf400078,
+0x8f420318, 0x24420001, 0xaf420318, 0x8f420318,
+0x10000048, 0x0, 0xa6b0000a, 0x8f430044,
+0x8f4401a0, 0x8f4501a4, 0x34028000, 0xafa20010,
+0x8f420044, 0x2a03021, 0x24070020, 0xafa20014,
+0x8f42000c, 0x31940, 0x604821, 0xafa20018,
+0x8f42010c, 0x4021, 0xa92821, 0xa9182b,
+0x882021, 0x40f809, 0x832021, 0x1040fdba,
+0x240a0001, 0xa34a05c4, 0x8fab0074, 0x8faa006c,
+0x1705823, 0xafab0074, 0x8fab00a4, 0x1505021,
+0x16a102b, 0x10400004, 0xafaa006c, 0x8f420148,
+0x1425023, 0xafaa006c, 0x8f420368, 0x2442ffff,
+0xaf420368, 0x8faa0064, 0x240b0001, 0x8f420368,
+0x154b0006, 0x24020002, 0x8f42035c, 0x2442ffff,
+0xaf42035c, 0x1000000c, 0x8f42035c, 0x11420006,
+0x0, 0x8f420360, 0x2442ffff, 0xaf420360,
+0x10000005, 0x8f420360, 0x8f420364, 0x2442ffff,
+0xaf420364, 0x8f420364, 0x8faa005c, 0x8fab0054,
+0xad6a0000, 0x8f420044, 0x8f440088, 0x8f430078,
+0x24420001, 0x441024, 0x24630001, 0xaf420044,
+0xaf430078, 0x8fab0074, 0x1560fdba, 0x0,
+0x8faa0074, 0x1140001f, 0x0, 0x934205c4,
+0x10400009, 0x0, 0x8fab006c, 0xaf4b00c4,
+0xaf4a00c0, 0x8faa0084, 0xaf4a00c8, 0x8fab007c,
+0x1000000e, 0xaf4b00cc, 0x97aa0096, 0x1140000b,
+0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c,
+0x97ab008e, 0x8c440004, 0x8c450008, 0xa44b000e,
+0xac440000, 0xac450004, 0xac460008, 0x8f42034c,
+0x24420001, 0xaf42034c, 0x8f42034c, 0x10000011,
+0x0, 0x8faa0084, 0x3144ffff, 0x2484fffc,
+0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
+0x1021, 0xa32821, 0xa3382b, 0x822021,
+0x872021, 0xaf440250, 0xaf450254, 0xc0f809,
+0x0, 0x8fbf00d0, 0x8fbe00cc, 0x8fb500c8,
+0x8fb300c4, 0x8fb200c0, 0x8fb100bc, 0x8fb000b8,
+0x3e00008, 0x27bd00d8, 0x3e00008, 0x0,
+0x27bdff30, 0x240b0001, 0xafbf00c8, 0xafbe00c4,
+0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
+0xafb000b0, 0xa3a0008f, 0xafa0004c, 0xafab0064,
+0xa7a0007e, 0xafa00040, 0x934205c4, 0x8821,
+0x10400007, 0xa7a00086, 0x8f4c00c0, 0xafac006c,
+0x8f4b00c8, 0x8f5e00c4, 0x10000184, 0xafab0074,
+0x8f420114, 0x40f809, 0x0, 0x403021,
+0x10c00348, 0x0, 0x8cc20000, 0x8cc30004,
+0xafa20020, 0xafa30024, 0x8fac0024, 0x8fbe0020,
+0x3182ffff, 0x2442fffc, 0xafa2006c, 0x3c020006,
+0x2c21024, 0x14400015, 0xafac0074, 0x93c20000,
+0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000,
+0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b,
+0x0, 0xc0025dd, 0x3c02021, 0x304200ff,
+0x14400006, 0x0, 0x8f420118, 0x40f809,
+0x0, 0x10000327, 0x0, 0x8fa20024,
+0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff,
+0x431824, 0x14600003, 0xafa20024, 0x10000040,
+0x8021, 0x3c020080, 0x621024, 0x10400007,
+0x0, 0x8f42038c, 0x24420001, 0xaf42038c,
+0x8f42038c, 0x10000036, 0x24100001, 0x8f420210,
+0x24420001, 0xaf420210, 0x8f420210, 0x3c020001,
+0x621024, 0x10400006, 0x3c020002, 0x8f4201c4,
+0x24420001, 0xaf4201c4, 0x8f4201c4, 0x3c020002,
+0x621024, 0x10400006, 0x3c020004, 0x8f42037c,
+0x24420001, 0xaf42037c, 0x8f42037c, 0x3c020004,
+0x621024, 0x10400006, 0x3c020008, 0x8f420380,
+0x24420001, 0xaf420380, 0x8f420380, 0x3c020008,
+0x621024, 0x10400006, 0x3c020010, 0x8f420384,
+0x24420001, 0xaf420384, 0x8f420384, 0x3c020010,
+0x621024, 0x10400006, 0x3c020020, 0x8f4201c0,
+0x24420001, 0xaf4201c0, 0x8f4201c0, 0x3c020020,
+0x621024, 0x10400006, 0x24100001, 0x8f420388,
+0x24420001, 0xaf420388, 0x8f420388, 0x24100001,
+0x8c020260, 0x8fab006c, 0x4b102b, 0x10400015,
+0x320200ff, 0x8f4201e8, 0x24420001, 0xaf4201e8,
+0x8f4201e8, 0x8fac0074, 0x8f8200e0, 0x358c0100,
+0xafac0074, 0xafa20010, 0x8f8200e4, 0x24100001,
+0x3c040001, 0x24847f68, 0xafa20014, 0x8fa60020,
+0x8fa70024, 0x3c050007, 0xc002d3b, 0x34a53600,
+0x320200ff, 0x10400011, 0x3c020080, 0x2c21024,
+0x1440000f, 0x32c20400, 0x8fab0074, 0x3c020080,
+0x34420100, 0x1621024, 0x10400005, 0x0,
+0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+0x8fa3006c, 0x100002a7, 0x0, 0x32c20400,
+0x10400012, 0x34028100, 0x97c3000c, 0x1462000f,
+0x0, 0x240c0200, 0xa7ac007e, 0x97c2000e,
+0x8fc30008, 0x8fc40004, 0x8fab006c, 0x8fc50000,
+0x256bfffc, 0xafab006c, 0xa7a20086, 0xafc3000c,
+0xafc40008, 0xafc50004, 0x27de0004, 0x8fa7006c,
+0x320200ff, 0x14400033, 0x3c020100, 0x97c4000c,
+0x2c8305dd, 0x38828870, 0x2c420001, 0x621825,
+0x10600014, 0x32c20800, 0x10400015, 0x24020800,
+0x97c30014, 0x14620012, 0x3402aaaa, 0x97c3000e,
+0x14620007, 0x2021, 0x97c30010, 0x24020300,
+0x14620004, 0x801021, 0x97c20012, 0x2c440001,
+0x801021, 0x54400006, 0x24110016, 0x10000004,
+0x0, 0x24020800, 0x50820001, 0x2411000e,
+0x12200013, 0x3d12021, 0x24830009, 0x3c02001f,
+0x3442ffff, 0x43102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x90620000, 0x38430006,
+0x2c630001, 0x38420011, 0x2c420001, 0x621825,
+0x10600004, 0x3c020100, 0x94820002, 0x513821,
+0x3c020100, 0x2c21024, 0x5040000e, 0xafa7006c,
+0x8fac006c, 0x10ec0008, 0x3c050007, 0x3c040001,
+0x24847fd8, 0x8fa6006c, 0x34a54000, 0xafa00010,
+0xc002d3b, 0xafa00014, 0x8fab006c, 0x256b0004,
+0xafab006c, 0x8f420080, 0x8fac006c, 0x4c102b,
+0x10400080, 0x32c28000, 0x10400088, 0x32c21000,
+0x10400055, 0x240b0004, 0x3c021000, 0x2c21024,
+0x10400082, 0xafab0064, 0x12200080, 0x1911023,
+0x2c420014, 0x1440007d, 0x3d12021, 0x24830006,
+0x90820000, 0x3c05001f, 0x34a5ffff, 0x3042000f,
+0x23080, 0xa3102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x94620000, 0x30421fff,
+0x10400003, 0x2261021, 0x1000006c, 0xafa20040,
+0x24830009, 0xa3102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x90630000, 0x24020006,
+0x14620017, 0x24020011, 0x94820002, 0x2c420028,
+0x1440005e, 0x861821, 0xa3102b, 0x50400004,
+0x2463000c, 0x8f420148, 0x621823, 0x2463000c,
+0xa3102b, 0x10400003, 0x0, 0x8f420148,
+0x621823, 0x90630000, 0x306200f0, 0x21882,
+0x2261021, 0x431021, 0x1000004c, 0xafa20040,
+0x1462004a, 0x0, 0x94820002, 0x2c42001c,
+0x14400046, 0x2263821, 0x94830002, 0x24e20008,
+0x2c63009c, 0x14600041, 0xafa20040, 0x861821,
+0xa3102b, 0x10400003, 0x0, 0x8f420148,
+0x621823, 0x94620000, 0x24040801, 0x10440004,
+0x24e20088, 0x94620002, 0x14440034, 0x24e20088,
+0x10000032, 0xafa20040, 0x1000002f, 0x240c0003,
+0x8f420350, 0x2403ffbf, 0x283a024, 0x24420001,
+0xaf420350, 0x8f420350, 0x100001c4, 0x0,
+0x3c020800, 0x2c2b025, 0x2402ffbf, 0x282a024,
+0x8f830128, 0x3c040001, 0x24847fa0, 0x26620001,
+0xafa20014, 0xafa30010, 0x8f860120, 0x8f870124,
+0x3c050007, 0xc002d3b, 0x34a55300, 0x100001b3,
+0x0, 0x8ea20000, 0x8ea30004, 0x3c040001,
+0x24847fb8, 0xafb00010, 0xafb10014, 0x8ea70018,
+0x34a55900, 0xc002d3b, 0x603021, 0x100001a7,
+0x0, 0x8f420084, 0x8fab006c, 0x4b102b,
+0x14400007, 0x3c020001, 0x2c21024, 0x10400004,
+0x0, 0x240c0002, 0xafac0064, 0x8fab006c,
+0x116001b8, 0x27ac0020, 0xafac0094, 0x8fab0064,
+0x240c0001, 0x556c0022, 0x240c0002, 0x8f430054,
+0x8f420050, 0x1062000b, 0x274b0054, 0x8f510054,
+0x3403ecc0, 0xafab0054, 0x26220001, 0x304201ff,
+0xafa2005c, 0x111140, 0x431021, 0x10000077,
+0x2e2a821, 0x8f420044, 0x8fac006c, 0x3c040001,
+0x24847f74, 0xafac0014, 0xafa20010, 0x8f460054,
+0x8f470050, 0x3c050007, 0xc002d3b, 0x34a54300,
+0x8f430350, 0x2402ffbf, 0x282a024, 0x24630001,
+0xaf430350, 0x8f420350, 0x10000174, 0x0,
+0x156c001d, 0x0, 0x8f430074, 0x8f420070,
+0x1062000a, 0x274b0074, 0x8f510074, 0xafab0054,
+0x26220001, 0x304203ff, 0xafa2005c, 0x111140,
+0x24426cc0, 0x10000055, 0x2e2a821, 0x8f420044,
+0x8fac006c, 0x3c040001, 0x24847f80, 0x3c050007,
+0xafac0014, 0xafa20010, 0x8f460074, 0x8f470070,
+0x34a54500, 0x240b0001, 0xc002d3b, 0xafab0064,
+0x1000ffc2, 0x0, 0x8f430064, 0x8f420060,
+0x1062002b, 0x274c0064, 0x8f510064, 0x8fab0064,
+0xafac0054, 0x26220001, 0x304200ff, 0xafa2005c,
+0x24020004, 0x1562001f, 0x111140, 0x111180,
+0x24420cc0, 0x2e21021, 0xafa2004c, 0x24550020,
+0x3c021000, 0x2c21024, 0x1040000e, 0x0,
+0x8fac004c, 0x8fab006c, 0x9582002a, 0x4b102b,
+0x54400006, 0x240c0001, 0x8fa20040, 0x50400028,
+0xaebe0018, 0x104b0025, 0x240c0001, 0x10000023,
+0xa3ac008f, 0x8fab004c, 0x8fac006c, 0x9562002a,
+0x4c102b, 0x1040001d, 0x240b0001, 0x1000001b,
+0xa3ab008f, 0x24424cc0, 0x10000018, 0x2e2a821,
+0x8f420044, 0x8fac006c, 0x3c040001, 0x24847f8c,
+0xafac0014, 0xafa20010, 0x8f460064, 0x8f470060,
+0x3c050007, 0xc002d3b, 0x34a54800, 0x3c020008,
+0x2c21024, 0x1440ff4e, 0x0, 0x8f420370,
+0x240b0001, 0xafab0064, 0x24420001, 0xaf420370,
+0x8f420370, 0x1000ff7d, 0x0, 0xaebe0018,
+0x93a2008f, 0x104000bf, 0x0, 0x8fac004c,
+0x8fa40040, 0x25820020, 0xafa20028, 0x25820008,
+0xafa20030, 0x25820010, 0xafac002c, 0x1080000e,
+0xafa20034, 0x9583002a, 0x83102b, 0x54400001,
+0x801821, 0x1000000b, 0xa7a30038, 0x27a30036,
+0x131040, 0x621821, 0x94620000, 0x441021,
+0x10000016, 0xa4620000, 0x8fab004c, 0x9562002a,
+0xa7a20038, 0x8fac004c, 0x8fa4006c, 0x8fa30094,
+0x95820018, 0xa7a2003a, 0x9582001a, 0xa7a2003c,
+0x9582001c, 0x9821, 0xa7a2003e, 0x94620018,
+0x24630002, 0x822023, 0x1880ffe8, 0x26730001,
+0x2e620004, 0x1440fff9, 0x0, 0x18800014,
+0x240207c2, 0x3c040001, 0x24847f4c, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77f98,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8f4200fc, 0x262102a, 0x14400044, 0x24030001,
+0x8f83012c, 0x1060003c, 0x0, 0x8f820124,
+0x431023, 0x22143, 0x58800001, 0x24840040,
+0x8f820128, 0x431023, 0x21943, 0x58600001,
+0x24630040, 0x64102a, 0x54400001, 0x602021,
+0xaf4400fc, 0x8f4200fc, 0x262102a, 0x1040002a,
+0x24030001, 0x1000002e, 0x306200ff, 0x8fab0094,
+0x101040, 0x4b1021, 0x94470018, 0x101080,
+0x4b1021, 0xafbe0010, 0x8c420008, 0x3c040001,
+0x24847fac, 0x3c050007, 0x8c430004, 0x8c420000,
+0x34a55500, 0x2003021, 0xc002d3b, 0xafa30014,
+0x3c040001, 0x24847f4c, 0x240207f4, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77f98,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x10000039, 0x0, 0x8f420334, 0x1821,
+0x24420001, 0xaf420334, 0x8f420334, 0x306200ff,
+0x1040febf, 0x8021, 0x8f430008, 0x2402fbff,
+0x1260002d, 0x625024, 0x3c0c4000, 0x22c4025,
+0x8fb10094, 0x2669ffff, 0x2209021, 0x8e420008,
+0x96270018, 0x8c440000, 0x8c450004, 0x56090004,
+0x240c0001, 0x240b0002, 0x10000002, 0xafab0010,
+0xafac0010, 0x16000004, 0xafa80014, 0x8f420008,
+0x10000002, 0xafa20018, 0xafaa0018, 0x8f42010c,
+0x3c03021, 0xafa800a0, 0xafa900a4, 0x40f809,
+0xafaa00a8, 0x8fa800a0, 0x8fa900a4, 0x8faa00a8,
+0x1040ffae, 0x3c02001f, 0x96230018, 0x3442ffff,
+0x3c3f021, 0x5e102b, 0x10400003, 0x26310002,
+0x8f420148, 0x3c2f023, 0x26100001, 0x213102b,
+0x1440ffda, 0x26520004, 0x8fb0006c, 0x1000001a,
+0x0, 0x96a3000a, 0x8fb0006c, 0x70102b,
+0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
+0x8fac0064, 0x240b0002, 0xafab0010, 0x934305c4,
+0xc1700, 0x10600003, 0x2223025, 0x3c020800,
+0xc23025, 0xafa60014, 0x8f420008, 0xafa20018,
+0x8f42010c, 0x3c03021, 0x40f809, 0x2003821,
+0x1040fe84, 0x3c050007, 0x97ab007e, 0x96a3000e,
+0x11600007, 0x0, 0x934205c4, 0x14400004,
+0x0, 0x97ac0086, 0x6b1825, 0xa6ac0016,
+0x8fab0074, 0x3c02ffff, 0x1621024, 0x10400003,
+0xb1402, 0x34630400, 0xa6a20014, 0xa6b0000a,
+0x8fac006c, 0x560c0006, 0x3d0f021, 0x34620004,
+0xafa0006c, 0xa6a2000e, 0x1000000d, 0xa34005c4,
+0x8fab006c, 0x3c02001f, 0x3442ffff, 0x5e102b,
+0x1705823, 0xafab006c, 0xa6a3000e, 0x240c0001,
+0x10400003, 0xa34c05c4, 0x8f420148, 0x3c2f023,
+0x3c021000, 0x2c21024, 0x10400006, 0x0,
+0x8fa20040, 0x401821, 0x1021, 0xaea20000,
+0xaea30004, 0x8fac005c, 0x8fab0054, 0xad6c0000,
+0x8fab006c, 0x1560fe69, 0x0, 0x8fac006c,
+0x1180001c, 0x0, 0x934205c4, 0x10400006,
+0x0, 0xaf5e00c4, 0xaf4c00c0, 0x8fab0074,
+0x1000000e, 0xaf4b00c8, 0x97ac007e, 0x1180000b,
+0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c,
+0x97ab0086, 0x8c440004, 0x8c450008, 0xa44b000e,
+0xac440000, 0xac450004, 0xac460008, 0x8f42034c,
+0x24420001, 0xaf42034c, 0x8f42034c, 0x10000011,
+0x0, 0x8fac0074, 0x3184ffff, 0x2484fffc,
+0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
+0x1021, 0xa32821, 0xa3382b, 0x822021,
+0x872021, 0xaf440250, 0xaf450254, 0xc0f809,
+0x0, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
+0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
+0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
+0x27bdffd0, 0xafbf0028, 0xafb10024, 0xafb00020,
+0x8f43004c, 0x8f420048, 0x1062004a, 0x0,
+0x8f430048, 0x8f42004c, 0x628823, 0x6220001,
+0x26310200, 0x8f430054, 0x8f42004c, 0x43102b,
+0x14400004, 0x24020200, 0x8f43004c, 0x10000005,
+0x438023, 0x8f420054, 0x8f43004c, 0x431023,
+0x2450ffff, 0x16000016, 0x2005821, 0x3c040001,
+0x24847f4c, 0x24020888, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77f98, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x2005821,
+0x22b102a, 0x54400001, 0x2205821, 0x8f4a004c,
+0x8f49004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
+0xb3940, 0x24081000, 0xafa80010, 0x94940,
+0x1201821, 0x1021, 0x14b5021, 0x315001ff,
+0xafb00014, 0x8f480014, 0xa32821, 0xa3482b,
+0x822021, 0x892021, 0x63140, 0x3402ecc0,
+0xafa80018, 0x8f430108, 0xc23021, 0x60f809,
+0x2e63021, 0x54400001, 0xaf50004c, 0x8f43004c,
+0x8f420048, 0x14620019, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x10000002, 0x0, 0xaf800048, 0x8fbf0028,
+0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030,
+0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028,
+0xafb10024, 0xafb00020, 0x8f43005c, 0x8f420058,
+0x1062005f, 0x0, 0x8f430058, 0x8f42005c,
+0x628823, 0x6220001, 0x26310100, 0x8f430064,
+0x8f42005c, 0x43102b, 0x14400004, 0x24020100,
+0x8f43005c, 0x10000005, 0x438023, 0x8f420064,
+0x8f43005c, 0x431023, 0x2450ffff, 0x16000016,
+0x2003821, 0x3c040001, 0x24847f4c, 0x240208e2,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e77f98, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x2003821, 0x227102a, 0x54400001,
+0x2203821, 0x8f42005c, 0x471021, 0x305000ff,
+0x32c21000, 0x10400015, 0x24082000, 0x8f49005c,
+0x8f440190, 0x8f450194, 0x8f46005c, 0x73980,
+0xafa80010, 0xafb00014, 0x8f480014, 0x94980,
+0x1201821, 0x1021, 0xa32821, 0xa3482b,
+0x822021, 0x892021, 0x63180, 0xafa80018,
+0x8f420108, 0x10000014, 0x24c60cc0, 0x8f49005c,
+0x8f440190, 0x8f450194, 0x8f46005c, 0x73940,
+0xafa80010, 0xafb00014, 0x8f480014, 0x94940,
+0x1201821, 0x1021, 0xa32821, 0xa3482b,
+0x822021, 0x892021, 0x63140, 0xafa80018,
+0x8f420108, 0x24c64cc0, 0x40f809, 0x2e63021,
+0x54400001, 0xaf50005c, 0x8f43005c, 0x8f420058,
+0x14620019, 0x0, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x2403feff, 0x431024, 0xaf820060, 0x8f420000,
+0x10400004, 0x0, 0xaf80004c, 0x10000002,
+0x0, 0xaf800048, 0x8fbf0028, 0x8fb10024,
+0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
+0x0, 0x27bdffd0, 0xafbf0028, 0xafb10024,
+0xafb00020, 0x8f43006c, 0x8f420068, 0x10620049,
+0x0, 0x8f430068, 0x8f42006c, 0x628823,
+0x6220001, 0x26310400, 0x8f430074, 0x8f42006c,
+0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
+0x10000005, 0x438023, 0x8f420074, 0x8f43006c,
+0x431023, 0x2450ffff, 0x16000016, 0x2005821,
+0x3c040001, 0x24847f4c, 0x2402094b, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e77f98,
+0xc002d3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x2005821, 0x22b102a, 0x54400001, 0x2205821,
+0x8f4a006c, 0x8f49006c, 0x8f440198, 0x8f45019c,
+0x8f46006c, 0xb3940, 0x24084000, 0xafa80010,
+0x94940, 0x1201821, 0x1021, 0x14b5021,
+0x315003ff, 0xafb00014, 0x8f480014, 0xa32821,
+0xa3482b, 0x822021, 0x892021, 0x63140,
+0xafa80018, 0x8f420108, 0x24c66cc0, 0x40f809,
+0x2e63021, 0x54400001, 0xaf50006c, 0x8f43006c,
+0x8f420068, 0x14620019, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060,
+0x8f420000, 0x10400004, 0x0, 0xaf80004c,
+0x10000002, 0x0, 0xaf800048, 0x8fbf0028,
+0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030,
+0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
+0xafb00018, 0x8f4200fc, 0x8f4400f8, 0x8f4300f4,
+0x24420001, 0xaf4200fc, 0x8f900128, 0x14830016,
+0x3c020001, 0x3c040001, 0x24847f4c, 0x240209b3,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e77f98, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x3c020001, 0x8f4300f8, 0x344230c8,
+0x2e21021, 0x54620004, 0x24620008, 0x3c020001,
+0x34422ec8, 0x2e21021, 0x401821, 0xaf4300f8,
+0xac600000, 0x8f4200f4, 0x14620005, 0x3c020001,
+0x26020020, 0xaf820128, 0x1000000f, 0x0,
+0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x401821, 0x8c620004, 0x21140, 0x2021021,
+0xaf820128, 0xac600000, 0x8e030018, 0x30620070,
+0x10400030, 0x30620020, 0x10400004, 0x3c020010,
+0x2c21024, 0x1040000d, 0x0, 0x30620040,
+0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
+0x0, 0x30620010, 0x10400038, 0x3c020040,
+0x2c21024, 0x14400035, 0x0, 0x8f820040,
+0x30420001, 0x14400008, 0x2021, 0x8c030104,
+0x24020001, 0x50620005, 0x24040001, 0x8c020264,
+0x10400003, 0x801021, 0x24040001, 0x801021,
+0x10400007, 0x0, 0x8f42030c, 0x24420001,
+0xaf42030c, 0x8f42030c, 0x10000020, 0x0,
+0x8f820044, 0x34420004, 0xaf820044, 0x8f420308,
+0x24420001, 0xaf420308, 0x8f420308, 0x10000017,
+0x0, 0x3062b08f, 0x14400014, 0x240209e4,
+0x3c040001, 0x24847f4c, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e77f98, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf001c,
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x27bdff98, 0xafbf0060, 0xafbe005c,
+0xafb50058, 0xafb30054, 0xafb20050, 0xafb1004c,
+0xafb00048, 0x8f4200fc, 0x24420001, 0xaf4200fc,
+0x8f880128, 0x25020020, 0xaf820128, 0x8d030018,
+0x30620070, 0x10400030, 0x30620020, 0x10400004,
+0x3c020010, 0x2c21024, 0x1040000d, 0x0,
+0x30620040, 0x10400004, 0x3c020020, 0x2c21024,
+0x10400007, 0x0, 0x30620010, 0x104001c0,
+0x3c020040, 0x2c21024, 0x144001bd, 0x0,
+0x8f820040, 0x30420001, 0x14400008, 0x2021,
+0x8c030104, 0x24020001, 0x50620005, 0x24040001,
+0x8c020264, 0x10400003, 0x801021, 0x24040001,
+0x801021, 0x10400007, 0x0, 0x8f42030c,
+0x24420001, 0xaf42030c, 0x8f42030c, 0x100001a8,
+0x0, 0x8f820044, 0x34420004, 0xaf820044,
+0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000019f, 0x0, 0x30620002, 0x10400160,
+0x3c020800, 0x8d1e001c, 0x1e5702, 0xafaa0034,
+0x950a0016, 0x3c22024, 0xafaa0024, 0x8faa0034,
+0x24020001, 0x15420006, 0x33deffff, 0x1e1140,
+0x3403ecc0, 0x431021, 0x10000010, 0x2e2a821,
+0x24020002, 0x15420005, 0x24020003, 0x1e1140,
+0x24426cc0, 0x10000009, 0x2e2a821, 0x15420005,
+0x1e1180, 0x1e1140, 0x24424cc0, 0x10000003,
+0x2e2a821, 0x571021, 0x24550ce0, 0x96a2000e,
+0x304afffc, 0x30420400, 0x10400003, 0xafaa002c,
+0x100000e1, 0x8821, 0x10800004, 0x8821,
+0x97b10026, 0x100000dd, 0xa6b10012, 0x8eb30018,
+0x966a000c, 0xa7aa003e, 0x97a5003e, 0x2ca305dd,
+0x38a28870, 0x2c420001, 0x621825, 0x10600015,
+0x2021, 0x32c20800, 0x10400015, 0x24020800,
+0x96630014, 0x14620012, 0x3402aaaa, 0x9663000e,
+0x14620007, 0x2821, 0x96630010, 0x24020300,
+0x14620004, 0xa01021, 0x96620012, 0x2c450001,
+0xa01021, 0x54400006, 0x24040016, 0x10000004,
+0x0, 0x24020800, 0x50a20001, 0x2404000e,
+0x108000b9, 0x2649021, 0x92420000, 0x3042000f,
+0x28080, 0x32c20100, 0x10400020, 0x2501821,
+0x3c020020, 0x43102b, 0x1440000e, 0x2402021,
+0x2821, 0x94820000, 0x24840002, 0xa22821,
+0x83102b, 0x1440fffb, 0x30a2ffff, 0x51c02,
+0x622821, 0x51c02, 0x30a2ffff, 0x10000009,
+0x622821, 0x8f470148, 0x8f420110, 0x102842,
+0x3c060020, 0x40f809, 0xafa80040, 0x3045ffff,
+0x8fa80040, 0x50a00001, 0x3405ffff, 0x8faa002c,
+0x354a0002, 0x10000002, 0xafaa002c, 0x2821,
+0x32c20080, 0x10400090, 0xa6a50010, 0x26430009,
+0x3c02001f, 0x3442ffff, 0x43102b, 0x10400003,
+0x0, 0x8f420148, 0x621823, 0x90660000,
+0x30c200ff, 0x38430006, 0x2c630001, 0x38420011,
+0x2c420001, 0x621825, 0x1060007f, 0x24020800,
+0x8821, 0x97a3003e, 0x1462000f, 0x2602021,
+0x96710000, 0x96620002, 0x96630004, 0x96640006,
+0x2228821, 0x2238821, 0x2248821, 0x96620008,
+0x9663000a, 0x9664000c, 0x2228821, 0x2238821,
+0x10000007, 0x2248821, 0x94820000, 0x24840002,
+0x2228821, 0x92102b, 0x1440fffb, 0x0,
+0x111c02, 0x3222ffff, 0x628821, 0x111c02,
+0x3222ffff, 0x628821, 0x32c20200, 0x10400003,
+0x26440006, 0x1000003e, 0x8021, 0x3c05001f,
+0x34a5ffff, 0xa4102b, 0x10400003, 0x0,
+0x8f420148, 0x822023, 0x94820000, 0x30421fff,
+0x10400004, 0x2644000c, 0x96420002, 0x10000030,
+0x508023, 0x96420002, 0x26430014, 0x508023,
+0x3c020020, 0x43102b, 0x1440000a, 0xd08021,
+0x9642000c, 0x2028021, 0x9642000e, 0x96430010,
+0x96440012, 0x2028021, 0x2038021, 0x10000020,
+0x2048021, 0xa4102b, 0x10400003, 0x0,
+0x8f420148, 0x822023, 0x94820000, 0x24840002,
+0x2028021, 0xa4102b, 0x10400003, 0x0,
+0x8f420148, 0x822023, 0x94820000, 0x24840002,
+0x2028021, 0xa4102b, 0x10400003, 0x0,
+0x8f420148, 0x822023, 0x94820000, 0x24840002,
+0x2028021, 0xa4102b, 0x10400003, 0x0,
+0x8f420148, 0x822023, 0x94820000, 0x2028021,
+0x3c020100, 0x2c21024, 0x1040000e, 0x0,
+0x8faa002c, 0x31420004, 0x1040000a, 0x0,
+0x9504000e, 0x2642021, 0xc004445, 0x2484fffc,
+0x3042ffff, 0x2228821, 0x111c02, 0x3222ffff,
+0x628821, 0x8faa0024, 0x1518823, 0x111402,
+0x2228821, 0x2308821, 0x111402, 0x2228821,
+0x3231ffff, 0x52200001, 0x3411ffff, 0x8faa002c,
+0x354a0001, 0xafaa002c, 0xa6b10012, 0x97aa002e,
+0xa6aa000e, 0x8faa002c, 0x31420004, 0x10400002,
+0x24091000, 0x34098000, 0x8f480044, 0x8f4401a0,
+0x8f4501a4, 0xafa90010, 0x8f490044, 0x84140,
+0x1001821, 0xafa90014, 0x8f48000c, 0x2a03021,
+0x24070020, 0xafa80018, 0x8f48010c, 0x1021,
+0xa32821, 0xa3482b, 0x822021, 0x100f809,
+0x892021, 0x1440001f, 0x0, 0x8f820128,
+0x3c040001, 0x24847fe4, 0xafbe0014, 0xafa20010,
+0x8f860124, 0x8f870120, 0x3c050007, 0xc002d3b,
+0x34a59920, 0x3c040001, 0x24847f4c, 0x24020bfa,
+0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001,
+0x24e77f98, 0xc002d3b, 0x3405dead, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f820220, 0x34420004,
+0xaf820220, 0x8f820140, 0x3c030001, 0x431025,
+0xaf820140, 0x8f420368, 0x2442ffff, 0xaf420368,
+0x8f420044, 0x8f430088, 0x24420001, 0x431024,
+0xaf420044, 0x8faa0034, 0x8f440368, 0x24020001,
+0x15420006, 0x24020002, 0x8f42035c, 0x2442ffff,
+0xaf42035c, 0x1000004a, 0x8f42035c, 0x15420006,
+0x0, 0x8f420364, 0x2442ffff, 0xaf420364,
+0x10000043, 0x8f420364, 0x8f420360, 0x2442ffff,
+0xaf420360, 0x8f420360, 0x1000003d, 0x0,
+0x30621000, 0x10400005, 0x30628000, 0x8f420078,
+0x24420001, 0x10000036, 0xaf420078, 0x10400034,
+0x0, 0x8f420078, 0x24420001, 0xaf420078,
+0x8c030240, 0x43102b, 0x1440002d, 0x24070008,
+0x8f440168, 0x8f45016c, 0x8f430044, 0x8f48000c,
+0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x24847f44, 0xafa20014, 0x8f460044,
+0x8f870120, 0x3c050009, 0xc002d3b, 0x34a51300,
+0x1000000b, 0x0, 0x8f420304, 0x24420001,
+0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
+0x3c010001, 0x370821, 0xa02040f2, 0xaf400078,
+0x8f420318, 0x24420001, 0xaf420318, 0x8f420318,
+0x8fbf0060, 0x8fbe005c, 0x8fb50058, 0x8fb30054,
+0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
+0x27bd0068, 0x3e00008, 0x0, 0x8f42013c,
+0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
+0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
+0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
+0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
+0xc002dbf, 0x24060008, 0x8c020204, 0xaf820210,
+0xc004586, 0x0, 0x3c020002, 0x8c428668,
+0x30420002, 0x1040000e, 0x2021, 0x8c060248,
+0x24020002, 0x3c010002, 0xac22866c, 0xc005738,
+0x24050002, 0x2021, 0x8c060248, 0x24020001,
+0x3c010002, 0xac22866c, 0x10000011, 0x24050001,
+0x8c060248, 0x24020004, 0x3c010002, 0xac22866c,
+0xc005738, 0x24050004, 0x3c020002, 0x8c428668,
+0x30420001, 0x10400008, 0x24020001, 0x3c010002,
+0xac22866c, 0x2021, 0x24050001, 0x3c06601b,
+0xc005738, 0x0, 0x3c040002, 0x248480b0,
+0x8f420150, 0x8f430154, 0x3c050008, 0x8f460158,
+0x21640, 0x31940, 0x34630403, 0x431025,
+0x633c0, 0x461025, 0xaf82021c, 0xafa00010,
+0xafa00014, 0x8f86021c, 0x34a50200, 0xc002d3b,
+0x3821, 0x3c010002, 0xac208664, 0x3c010002,
+0xac20867c, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x27bdffe0, 0x3c050008, 0x34a50300, 0xafbf0018,
+0xafa00010, 0xafa00014, 0x8f860200, 0x3c040002,
+0x248480bc, 0xc002d3b, 0x3821, 0x8f420410,
+0x24420001, 0xaf420410, 0x8f420410, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0xafb00018, 0x8f4203a4, 0x24420001,
+0xaf4203a4, 0x8f4203a4, 0x8f900220, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0xafa20014, 0x8f8600c4,
+0x8f8700c8, 0x3c040002, 0x248480c8, 0xc002d3b,
+0x2002821, 0x3c044000, 0x2041024, 0x504000bc,
+0x3c040100, 0x8f4203bc, 0x24420001, 0xaf4203bc,
+0x8f4203bc, 0x8f8700c4, 0x8f8300c8, 0x8f420148,
+0x671823, 0x43102b, 0x10400003, 0x0,
+0x8f420148, 0x621821, 0x10600005, 0x0,
+0x8f42014c, 0x43102b, 0x1040000d, 0x0,
+0x8f8200e0, 0x8f430124, 0xaf42011c, 0xaf430114,
+0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
+0x441025, 0xaf820220, 0x10000104, 0x0,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420004, 0xaf820220, 0x8f8200e0, 0x8f430124,
+0xaf42011c, 0xaf430114, 0x8f8600c8, 0x8f840120,
+0x8f830124, 0x10000005, 0x2821, 0x14620002,
+0x24620020, 0x27624800, 0x401821, 0x1064000c,
+0x30a200ff, 0x8c620018, 0x30420003, 0x1040fff7,
+0x27624fe0, 0x8f4203d0, 0x24050001, 0x24420001,
+0xaf4203d0, 0x8f4203d0, 0x8c660008, 0x30a200ff,
+0x1440005b, 0x0, 0x934205c4, 0x14400058,
+0x0, 0x8f8700c4, 0x8f8800e0, 0x8f8400e4,
+0x2402fff8, 0x1024024, 0x1041023, 0x218c3,
+0x4620001, 0x24630200, 0x10600005, 0x24020001,
+0x1062000a, 0x0, 0x10000021, 0x0,
+0x8f4203c0, 0xe03021, 0x24420001, 0xaf4203c0,
+0x8f4203c0, 0x10000042, 0x0, 0x8f4203c4,
+0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
+0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
+0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
+0x14400033, 0x0, 0x8f42020c, 0x24420001,
+0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
+0xaf8200e4, 0xaf8200e8, 0x10000029, 0x0,
+0x8f4203c8, 0x24420001, 0xaf4203c8, 0x8f4203c8,
+0x8c850000, 0x8f420148, 0xa71823, 0x43102b,
+0x10400003, 0x0, 0x8f420148, 0x621821,
+0x8f42014c, 0x43102b, 0x5440000b, 0xa03021,
+0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+0x24820008, 0xaf8200e4, 0x8f8400e4, 0xaf8400e8,
+0x1488ffeb, 0x0, 0x1488000d, 0x27623000,
+0x14820002, 0x2482fff8, 0x27623ff8, 0x94430006,
+0x3c02001f, 0x3442ffff, 0xc33021, 0x46102b,
+0x10400003, 0x0, 0x8f420148, 0xc23023,
+0xaf8600c8, 0x8f8300c4, 0x8f420148, 0xc31823,
+0x43102b, 0x10400003, 0x0, 0x8f420148,
+0x621821, 0x10600005, 0x0, 0x8f42014c,
+0x43102b, 0x1040000a, 0x3c02fdff, 0x8f820220,
+0x3c0308ff, 0x3463fffb, 0x431024, 0x3c034000,
+0x431025, 0xaf820220, 0x10000070, 0x0,
+0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
+0xaf4303cc, 0x8f4203cc, 0x10000068, 0x0,
+0x2041024, 0x1040000f, 0x3c110200, 0x8f4203a8,
+0x24420001, 0xaf4203a8, 0x8f4203a8, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x441025,
+0xaf820220, 0xc00430b, 0x0, 0x10000057,
+0x0, 0x2111024, 0x50400009, 0x3c110400,
+0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac,
+0xc00430b, 0x0, 0x1000002e, 0x0,
+0x2111024, 0x10400033, 0x3c02b800, 0x8f830224,
+0x24021402, 0x1462001d, 0x3c050008, 0x3c040002,
+0x248480d4, 0xafa00010, 0xafa00014, 0x8f860224,
+0x34a50500, 0xc002d3b, 0x3821, 0x3c040002,
+0x248480a0, 0x240203b3, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070002, 0x24e780e0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8f4203b0,
+0x24420001, 0xaf4203b0, 0x8f4203b0, 0x8f820220,
+0x2002021, 0x34420002, 0xaf820220, 0xc0054be,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x511025, 0xaf820220, 0x10000017,
+0x0, 0x2021024, 0x10400014, 0x240203c7,
+0x3c040002, 0x248480a0, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070002, 0x24e780e0, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf0020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x3c020002, 0x8c42867c,
+0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
+0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
+0xafb00030, 0x3c040002, 0x248480e8, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
+0x24020001, 0x3c010002, 0xac20867c, 0x3c010002,
+0xac228670, 0xc002d3b, 0x3821, 0x3c037fff,
+0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
+0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
+0x10400092, 0x284a024, 0x3c040600, 0x34842000,
+0x8f420004, 0x2821, 0x2403fffd, 0x431024,
+0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
+0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
+0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040002, 0x24848068, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040002, 0x24848074,
+0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
+0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
+0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040002,
+0x2484807c, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002d3b, 0x3c03821, 0x8f4202ec,
+0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
+0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
+0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
+0x3c020002, 0x8c42867c, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040002, 0x248480f4, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
+0x24020001, 0x3c010002, 0xac22867c, 0xc002d3b,
+0x3821, 0x3c020004, 0x2c21024, 0x10400007,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420008, 0xaf820220, 0x3c050002,
+0x8ca5866c, 0x24020001, 0x14a20007, 0x2021,
+0xc0058d7, 0x24050001, 0xac02026c, 0x8c03026c,
+0x10000006, 0x3c020007, 0xc0058d7, 0x2021,
+0xac020268, 0x8c030268, 0x3c020007, 0x621824,
+0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
+0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
+0x3c020098, 0x1000000b, 0x0, 0x14620009,
+0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
+0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
+0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x86102b, 0x50400001, 0x872023, 0xc41023,
+0x24843, 0x125102b, 0x1040001b, 0x91040,
+0x824021, 0x88102b, 0x10400007, 0x1821,
+0x94820000, 0x24840002, 0x621821, 0x88102b,
+0x1440fffb, 0x0, 0x602021, 0xc73023,
+0xa91023, 0x21040, 0xc22821, 0xc5102b,
+0x10400007, 0x1821, 0x94c20000, 0x24c60002,
+0x621821, 0xc5102b, 0x1440fffb, 0x0,
+0x1000000d, 0x832021, 0x51040, 0x822821,
+0x85102b, 0x10400007, 0x1821, 0x94820000,
+0x24840002, 0x621821, 0x85102b, 0x1440fffb,
+0x0, 0x602021, 0x41c02, 0x3082ffff,
+0x622021, 0x41c02, 0x3082ffff, 0x622021,
+0x3e00008, 0x3082ffff, 0x3e00008, 0x0,
+0x802821, 0x30a20001, 0x1040002b, 0x3c03001f,
+0x3463ffff, 0x24a20004, 0x62102b, 0x54400007,
+0x65102b, 0x90a20001, 0x90a40003, 0x90a30000,
+0x90a50002, 0x1000002a, 0x441021, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a40000,
+0x24a50001, 0x65102b, 0x10400003, 0x0,
+0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
+0x21200, 0x822021, 0x65102b, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
+0x24a50001, 0x822021, 0x65102b, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
+0x1000002d, 0x21200, 0x3463ffff, 0x24a20004,
+0x62102b, 0x5440000a, 0x65102b, 0x90a20000,
+0x90a40002, 0x90a30001, 0x90a50003, 0x441021,
+0x21200, 0x651821, 0x10000020, 0x432021,
+0x10400003, 0x0, 0x8f420148, 0xa22823,
+0x90a20000, 0x24a50001, 0x22200, 0x65102b,
+0x10400003, 0x0, 0x8f420148, 0xa22823,
+0x90a20000, 0x24a50001, 0x822021, 0x65102b,
+0x10400003, 0x0, 0x8f420148, 0xa22823,
+0x90a20000, 0x24a50001, 0x21200, 0x822021,
+0x65102b, 0x10400003, 0x0, 0x8f420148,
+0xa22823, 0x90a20000, 0x822021, 0x41c02,
+0x3082ffff, 0x622021, 0x41c02, 0x3082ffff,
+0x622021, 0x3e00008, 0x3082ffff, 0x8f820220,
+0x34420002, 0xaf820220, 0x3c020002, 0x8c42a8b8,
+0x30424000, 0x10400054, 0x24040001, 0x8f820200,
+0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
+0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
+0x1040fff1, 0x0, 0x8f820200, 0x451025,
+0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
+0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
+0x0, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x1040001b, 0x1021, 0x8f830220, 0x24020001,
+0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
+0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
+0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
+0x431024, 0x14400003, 0x0, 0x10000008,
+0x1021, 0x8f820220, 0x34420002, 0xaf820220,
+0x8f830220, 0x24020001, 0x641825, 0xaf830220,
+0x3e00008, 0x0, 0x27bdffe0, 0x2021,
+0x3c050100, 0x24020001, 0xafbf0018, 0xaf80021c,
+0xaf820200, 0xaf820220, 0x27625000, 0xaf8200c0,
+0x27625000, 0xaf8200c4, 0x27625000, 0xaf8200c8,
+0x27625000, 0xaf8200d0, 0x27625000, 0xaf8200d4,
+0x27625000, 0xaf8200d8, 0x27623000, 0xaf8200e0,
+0x27623000, 0xaf8200e4, 0x27623000, 0xaf8200e8,
+0x27622800, 0xaf8200f0, 0x27622800, 0xaf8200f4,
+0x27622800, 0xaf8200f8, 0x418c0, 0x24840001,
+0x3631021, 0xac453004, 0x3631021, 0xac403000,
+0x28820200, 0x1440fff9, 0x418c0, 0x2021,
+0x418c0, 0x24840001, 0x3631021, 0xac402804,
+0x3631021, 0xac402800, 0x28820100, 0x1440fff9,
+0x418c0, 0xaf80023c, 0x24030080, 0x24040100,
+0xac600000, 0x24630004, 0x64102b, 0x5440fffd,
+0xac600000, 0x8f830040, 0x3c02f000, 0x621824,
+0x3c025000, 0x1062000c, 0x43102b, 0x14400006,
+0x3c026000, 0x3c024000, 0x1062000c, 0x24020800,
+0x1000000e, 0x240202a9, 0x10620008, 0x24020800,
+0x1000000a, 0x240202a9, 0x24020700, 0x3c010002,
+0xac228680, 0x10000018, 0x0, 0x3c010002,
+0xac228680, 0x10000014, 0x0, 0x3c040002,
+0x248481c0, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070002, 0x24e781d8, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x3c020002, 0x8c428690, 0x27bdffd0,
+0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
+0x3c010002, 0xac208668, 0x10400005, 0x0,
+0xc0053c3, 0x0, 0x3c010002, 0xac208690,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x0, 0xc0053de, 0x0, 0x24040001,
+0x2821, 0x27a60018, 0x34028000, 0xc004bdc,
+0xa7a20018, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x24050001, 0xc004b9a,
+0x27a60018, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x24050001, 0xc004b9a,
+0x27a60018, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x3c060002, 0x24c687e0,
+0xc004b9a, 0x24050002, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630064, 0x8f820054, 0x621023,
+0x2c420065, 0x1440fffc, 0x24040001, 0x24050003,
+0x3c100002, 0x261087e2, 0xc004b9a, 0x2003021,
+0x97a60018, 0x3c070002, 0x94e787e0, 0x3c040002,
+0x248481f0, 0xafa00014, 0x96020000, 0x3c05000d,
+0x34a50100, 0xc002d3b, 0xafa20010, 0x97a20018,
+0x10400050, 0x24036040, 0x96020000, 0x3042fff0,
+0x1443000d, 0x24020020, 0x3c030002, 0x946387e0,
+0x1462000c, 0x24027830, 0x24020003, 0x3c010002,
+0xac228668, 0x24020005, 0x3c010002, 0xac2287f0,
+0x10000041, 0x0, 0x3c030002, 0x946387e0,
+0x24027830, 0x1462000d, 0x24030010, 0x3c020002,
+0x944287e2, 0x3042fff0, 0x14430008, 0x24020003,
+0x3c010002, 0xac228668, 0x24020006, 0x3c010002,
+0xac2287f0, 0x10000030, 0x0, 0x3c020002,
+0x8c428668, 0x3c030002, 0x946387e0, 0x34420001,
+0x3c010002, 0xac228668, 0x24020015, 0x1462000b,
+0x0, 0x3c020002, 0x944287e2, 0x3042fff0,
+0x3843f420, 0x2c630001, 0x3842f430, 0x2c420001,
+0x621825, 0x1460001c, 0x24020003, 0x3c030002,
+0x946387e0, 0x24027810, 0x14620017, 0x24020002,
+0x3c020002, 0x944287e2, 0x3042fff0, 0x14400012,
+0x24020002, 0x10000010, 0x24020004, 0x3c020002,
+0x8c428668, 0x34420008, 0x3c010002, 0xac228668,
+0x1000005f, 0x24020004, 0x3c020002, 0x8c428668,
+0x34420004, 0x3c010002, 0xac228668, 0x100000af,
+0x0, 0x24020001, 0x3c010002, 0xac2287fc,
+0x3c020002, 0x8c428668, 0x30420002, 0x144000b2,
+0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
+0x8f820054, 0x24030008, 0x3c010002, 0xac23866c,
+0x10000002, 0x248401f4, 0x8f820054, 0x821023,
+0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
+0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
+0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
+0x1440fffc, 0x8021, 0x24120001, 0x24110009,
+0xc004a53, 0x0, 0x3c010002, 0xac328688,
+0xc004b1d, 0x0, 0x3c020002, 0x8c428688,
+0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
+0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
+0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
+0x0, 0x8f820220, 0x24040001, 0x34420002,
+0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
+0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820224, 0x14440005, 0x34028000, 0x42040,
+0xa4102b, 0x1040fff0, 0x34028000, 0x1082ff9f,
+0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
+0x3c010002, 0xac22866c, 0x8021, 0x24120009,
+0x3c11ffff, 0x36313f7f, 0xc004a53, 0x0,
+0x24020001, 0x3c010002, 0xac228688, 0xc004b1d,
+0x0, 0x3c020002, 0x8c428688, 0x1452fffb,
+0x0, 0x8f820044, 0x511024, 0x34425080,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
+0x1440fffc, 0x0, 0x8f820044, 0x511024,
+0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x2463000a, 0x8f820054, 0x621023,
+0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
+0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
+0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+0x14440005, 0x34028000, 0x42040, 0xa4102b,
+0x1040fff0, 0x34028000, 0x1082ff4f, 0x26100001,
+0x2e020064, 0x1440ffb0, 0x0, 0x3c020002,
+0x8c428668, 0x30420004, 0x14400007, 0x3c09fff0,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060002,
+0x8cc68668, 0x3c040002, 0x248481f0, 0x24020001,
+0x3c010002, 0xac228670, 0x8f820054, 0x3c070002,
+0x8ce787fc, 0x3c030002, 0x946387e0, 0x3c080002,
+0x950887e2, 0x3c05000d, 0x34a50100, 0x3c010002,
+0xac20866c, 0x491021, 0x3c010002, 0xac2287ec,
+0xafa30010, 0xc002d3b, 0xafa80014, 0x8fbf002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0030, 0x27bdffe8, 0x3c050002, 0x8ca5866c,
+0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
+0x3c020002, 0x8c42a8bc, 0x30428000, 0x10400005,
+0x3c04000f, 0x3c030002, 0x8c6387fc, 0x10000005,
+0x34844240, 0x3c040004, 0x3c030002, 0x8c6387fc,
+0x348493e0, 0x24020005, 0x14620016, 0x0,
+0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
+0x8c42a8b8, 0x30428000, 0x10400005, 0x3c04001e,
+0x3c030002, 0x8c6387fc, 0x10000005, 0x34848480,
+0x3c04000f, 0x3c030002, 0x8c6387fc, 0x34844240,
+0x24020005, 0x14620003, 0x0, 0x3c04007a,
+0x34841200, 0x3c020002, 0x8c4287ec, 0x8f830054,
+0x441021, 0x431023, 0x44102b, 0x1440004e,
+0x0, 0x3c020002, 0x8c428674, 0x1440004a,
+0x0, 0x3c010002, 0xac208684, 0x10c00026,
+0x0, 0x3c090002, 0x8d298668, 0x24070001,
+0x3c044000, 0x3c080002, 0x2508a8bc, 0x250afffc,
+0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
+0xa91024, 0x10400011, 0x0, 0x14a70009,
+0x0, 0x8d020000, 0x441024, 0x1040000b,
+0x0, 0x3c010002, 0xac258684, 0x10000007,
+0x0, 0x8d420000, 0x441024, 0x10400003,
+0x0, 0x3c010002, 0xac278684, 0x3c020002,
+0x8c428684, 0x6182b, 0x2c420001, 0x431024,
+0x5440ffe4, 0x52842, 0x8f820054, 0x3c030002,
+0x8c638684, 0x3c010002, 0xac2287ec, 0x1060003b,
+0x24020005, 0x3c030002, 0x8c6387fc, 0x3c010002,
+0xac25866c, 0x14620012, 0x24020001, 0x3c020002,
+0x8c42a8b8, 0x3c032000, 0x34635000, 0x431024,
+0x14400006, 0x24020001, 0x3c010002, 0xac2087d8,
+0x3c010002, 0xac22866c, 0x24020001, 0x3c010002,
+0xac2286f0, 0x3c010002, 0xac228678, 0x24020001,
+0x3c010002, 0xac228670, 0x3c020002, 0x8c428684,
+0x1040001e, 0x0, 0x3c020002, 0x8c428670,
+0x10400008, 0x24020001, 0x3c010002, 0xac208670,
+0xaee204b8, 0x3c010002, 0xac2086e8, 0x3c010002,
+0xac2286a0, 0x8ee304b8, 0x24020008, 0x10620005,
+0x24020001, 0xc0047b3, 0x0, 0x1000000b,
+0x0, 0x3c030002, 0x8c63866c, 0x10620007,
+0x2402000e, 0x3c030002, 0x8c63a850, 0x10620003,
+0x0, 0xc0054be, 0x8f840220, 0x8fbf0010,
+0x3e00008, 0x27bd0018, 0x27bdffd8, 0x3c03fdff,
+0x3c040002, 0x8c84866c, 0x3c020002, 0x8c428694,
+0x3463ffff, 0x283a024, 0x14820006, 0xafbf0020,
+0x8ee304b8, 0x3c020002, 0x8c428698, 0x10620006,
+0x0, 0x8ee204b8, 0x3c010002, 0xac248694,
+0x3c010002, 0xac228698, 0x3c030002, 0x8c63866c,
+0x24020002, 0x106201cc, 0x2c620003, 0x10400005,
+0x24020001, 0x1062000a, 0x0, 0x1000027d,
+0x0, 0x24020004, 0x106200eb, 0x24020008,
+0x1062014e, 0x24020001, 0x10000276, 0x0,
+0x8ee204b8, 0x2443ffff, 0x2c620008, 0x10400273,
+0x31080, 0x3c010002, 0x220821, 0x8c228210,
+0x400008, 0x0, 0x3c030002, 0x8c6387fc,
+0x24020005, 0x14620012, 0x0, 0x3c020002,
+0x8c428678, 0x10400009, 0x24020003, 0xc004a53,
+0x0, 0x24020002, 0xaee204b8, 0x3c010002,
+0xac208678, 0x10000002, 0x0, 0xaee204b8,
+0x3c010002, 0xac20860c, 0x10000258, 0x0,
+0xc004a53, 0x0, 0x3c020002, 0x8c428678,
+0x3c010002, 0xac20860c, 0x144001a8, 0x24020002,
+0x100001f1, 0x24020007, 0x3c030002, 0x8c6387fc,
+0x24020005, 0x14620003, 0x24020001, 0x3c010002,
+0xac22869c, 0xc004c1d, 0x0, 0x3c030002,
+0x8c63869c, 0x100001a3, 0x24020011, 0x3c050002,
+0x8ca5866c, 0x3c060002, 0x8cc6a8bc, 0xc005738,
+0x2021, 0x24020005, 0x3c010002, 0xac208678,
+0x10000236, 0xaee204b8, 0x3c040002, 0x248481fc,
+0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x3c040002,
+0x248481c0, 0x240204b0, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070002, 0x24e781d8, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x10000217,
+0x0, 0x24040001, 0x2405001a, 0x8f820220,
+0x27a60018, 0x3c03f700, 0x431025, 0xaf820220,
+0xc004b9a, 0x0, 0x97a60018, 0x30c20200,
+0x104001a1, 0x3c05000c, 0x3c040002, 0x24848208,
+0x34a50111, 0x3c020002, 0x8c42866c, 0x3c030002,
+0x8c6387d8, 0x3821, 0xafa20010, 0xc002d3b,
+0xafa30014, 0x2021, 0x2821, 0xc005400,
+0x24064040, 0x1000018e, 0x24020002, 0x8f820220,
+0x3c030004, 0x431024, 0x14400197, 0x24020007,
+0x8f830054, 0x3c020002, 0x8c4287e4, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020001,
+0x3c010002, 0xac228670, 0x3c020002, 0x8c42a8bc,
+0x30425000, 0x104001e5, 0x0, 0x8f820220,
+0x30428000, 0x1040019f, 0x0, 0x10000197,
+0x0, 0x3c050002, 0x8ca5866c, 0xc0058d7,
+0x2021, 0xc005b59, 0x2021, 0x3c030002,
+0x8c63a8b4, 0x46101d3, 0x24020001, 0x3c020008,
+0x621024, 0x10400006, 0x0, 0x8f820214,
+0x3c03ffff, 0x431024, 0x10000005, 0x3442251f,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
+0xaf820214, 0x8f820220, 0x3c030200, 0x34420002,
+0xaf820220, 0x24020008, 0xaee204b8, 0x8f820220,
+0x283a025, 0x3c030004, 0x431024, 0x14400016,
+0x0, 0x3c020002, 0x8c42a8bc, 0x30425000,
+0x1040000d, 0x0, 0x8f820220, 0x30428000,
+0x10400006, 0x0, 0x8f820220, 0x3c03ffff,
+0x34637fff, 0x10000003, 0x431024, 0x8f820220,
+0x34428000, 0xaf820220, 0x8f820220, 0x3c03f700,
+0x431025, 0xaf820220, 0x3c030002, 0x8c6387fc,
+0x24020005, 0x1462000a, 0x0, 0x3c020002,
+0x944287e2, 0x24429fbc, 0x2c420004, 0x10400004,
+0x24040018, 0x24050002, 0xc005400, 0x24060020,
+0xc0043c9, 0x0, 0x3c010002, 0xac2086ec,
+0x10000192, 0x0, 0x8ee204b8, 0x2443ffff,
+0x2c620008, 0x1040018d, 0x31080, 0x3c010002,
+0x220821, 0x8c228230, 0x400008, 0x0,
+0xc00430b, 0x0, 0x3c010002, 0xac208670,
+0xaf800204, 0x3c010002, 0xac20a8a0, 0xc004a53,
+0x0, 0x24020001, 0x3c010002, 0xac228688,
+0x1000010f, 0x24020002, 0xc004b1d, 0x0,
+0x3c030002, 0x8c638688, 0x100000d6, 0x24020009,
+0x3c020002, 0x8c42a8b8, 0x30424000, 0x10400004,
+0x0, 0x8f820044, 0x10000006, 0x3442f080,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0x3442a080, 0xaf820044, 0x8f830054, 0x100000fc,
+0x24020004, 0x8f830054, 0x3c020002, 0x8c4287e4,
+0x2463d8f0, 0x431023, 0x2c422710, 0x1440015b,
+0x24020005, 0x100000c6, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
+0x3c010002, 0xac20a8a0, 0x100000e7, 0x0,
+0x8f830054, 0x3c020002, 0x8c4287e4, 0x2463fff6,
+0x431023, 0x2c42000a, 0x14400148, 0x24020007,
+0x100000e9, 0x0, 0xc0044a8, 0x0,
+0x10400140, 0x24020001, 0x8f820214, 0x3c03ffff,
+0x3c040002, 0x8c8487d8, 0x431024, 0x3442241f,
+0xaf820214, 0x24020008, 0x10800005, 0xaee204b8,
+0x3c020002, 0x8c428708, 0x1040004e, 0x24020001,
+0x8f820220, 0x3c030008, 0x431024, 0x10400054,
+0x3c020200, 0x10000063, 0x0, 0x8ee204b8,
+0x2443ffff, 0x2c620007, 0x10400128, 0x31080,
+0x3c010002, 0x220821, 0x8c228250, 0x400008,
+0x0, 0xc004b1d, 0x0, 0x3c030002,
+0x8c638688, 0x1000007f, 0x24020009, 0x3c020002,
+0x8c42a8b8, 0x30424000, 0x10400003, 0x3c0200c8,
+0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
+0x8f830054, 0x100000aa, 0x24020004, 0x8f830054,
+0x3c020002, 0x8c4287e4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400109, 0x24020005, 0x10000074,
+0x0, 0x8f830054, 0x3c020002, 0x8c4287e4,
+0x2463fff6, 0x431023, 0x2c42000a, 0x144000ff,
+0x24020007, 0x100000a0, 0x0, 0xc0044a8,
+0x0, 0x104000f7, 0x24020001, 0x8f820214,
+0x3c03ffff, 0x3c040002, 0x8c8487d8, 0x431024,
+0x3442241f, 0xaf820214, 0x24020008, 0x1080000f,
+0xaee204b8, 0x3c020002, 0x8c428708, 0x1440000b,
+0x0, 0x8f820220, 0x34420002, 0xaf820220,
+0x24020001, 0x3c010002, 0xac22a850, 0xc0054be,
+0x8f840220, 0x10000017, 0x0, 0x8f820220,
+0x3c030008, 0x431024, 0x14400012, 0x3c020200,
+0x282a025, 0x2402000e, 0x3c010002, 0xac22a850,
+0xc005b59, 0x2021, 0x8f820220, 0x34420002,
+0xaf820220, 0xc0043c9, 0x0, 0x3c050002,
+0x8ca5866c, 0xc0058d7, 0x2021, 0x100000cb,
+0x0, 0x3c020002, 0x8c428708, 0x104000c7,
+0x0, 0x3c020002, 0x8c428704, 0x2442ffff,
+0x3c010002, 0xac228704, 0x144000c0, 0x24020002,
+0x3c010002, 0xac208708, 0x3c010002, 0xac228704,
+0x100000ba, 0x0, 0x8ee204b8, 0x2443ffff,
+0x2c620007, 0x104000b5, 0x31080, 0x3c010002,
+0x220821, 0x8c228270, 0x400008, 0x0,
+0x3c020002, 0x8c428678, 0x10400019, 0x24020005,
+0xc004a53, 0x0, 0x24020002, 0xaee204b8,
+0x3c010002, 0xac208678, 0x100000a4, 0x0,
+0xc004f82, 0x0, 0x3c030002, 0x8c6386a0,
+0x24020006, 0x1462009d, 0x24020003, 0x1000009b,
+0xaee204b8, 0x3c050002, 0x8ca5866c, 0x3c060002,
+0x8cc6a8b8, 0xc005738, 0x2021, 0x24020005,
+0x10000092, 0xaee204b8, 0x24040001, 0x2405001a,
+0x8f820220, 0x27a60018, 0x3c03f700, 0x431025,
+0xaf820220, 0xc004b9a, 0x0, 0x97a60018,
+0x30c20200, 0x1040001c, 0x3c05000c, 0x3c040002,
+0x24848208, 0x34a50112, 0x3c020002, 0x8c42866c,
+0x3c030002, 0x8c6387d8, 0x3821, 0xafa20010,
+0xc002d3b, 0xafa30014, 0x2021, 0x2821,
+0xc005400, 0x24064040, 0x3c020002, 0x8c4287d8,
+0x10400006, 0x2021, 0x2821, 0xc005400,
+0x24061000, 0x1000006d, 0x0, 0x24020002,
+0x1000006a, 0xaee204b8, 0x8f830054, 0x24020006,
+0xaee204b8, 0x3c010002, 0xac2387e4, 0x10000063,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x10400003, 0x24020007, 0x1000005c, 0xaee204b8,
+0x8f830054, 0x3c020002, 0x8c4287e4, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020001,
+0x3c010002, 0xac228670, 0x3c020002, 0x8c42a8b8,
+0x30425000, 0x1040004d, 0x0, 0x8f820220,
+0x30428000, 0x10400007, 0x0, 0x8f820220,
+0x3c03ffff, 0x34637fff, 0x431024, 0x10000043,
+0xaf820220, 0x8f820220, 0x34428000, 0xaf820220,
+0x1000003e, 0x0, 0x3c050002, 0x8ca5866c,
+0xc0058d7, 0x2021, 0xc005b59, 0x2021,
+0x3c020002, 0x8c42a8b0, 0x4410032, 0x24020001,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
+0xaf820214, 0x24020008, 0xaee204b8, 0x8f820220,
+0x34420002, 0xaf820220, 0x8f820220, 0x3c030004,
+0x431024, 0x14400016, 0x0, 0x3c020002,
+0x8c42a8b8, 0x30425000, 0x1040000d, 0x0,
+0x8f820220, 0x30428000, 0x10400006, 0x0,
+0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
+0x431024, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x3c020002, 0x944287e2, 0x24429fbc, 0x2c420004,
+0x10400004, 0x24040018, 0x24050002, 0xc005400,
+0x24060020, 0xc0043c9, 0x0, 0x10000003,
+0x0, 0x3c010002, 0xac228670, 0x8fbf0020,
+0x3e00008, 0x27bd0028, 0x8f820200, 0x8f820220,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820200,
+0x3c050002, 0x8ca5866c, 0x34420004, 0xaf820200,
+0x24020002, 0x10a2004d, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x0, 0x100000b6,
+0x0, 0x24020004, 0x10a20075, 0x24020008,
+0x10a20089, 0x3c02f0ff, 0x100000af, 0x0,
+0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040002,
+0x8c8487fc, 0x621824, 0x3c020700, 0x621825,
+0x24020e00, 0x2484fffb, 0x2c840002, 0xaf830050,
+0xaf850200, 0xaf850220, 0xaf820238, 0x14800006,
+0x0, 0x8f820044, 0x3c03ffff, 0x34633f7f,
+0x431024, 0xaf820044, 0x3c030002, 0x8c6387fc,
+0x24020005, 0x14620004, 0x0, 0x8f820044,
+0x34425000, 0xaf820044, 0x3c020002, 0x8c42865c,
+0x3c030002, 0x8c6387fc, 0x34420022, 0x2463fffc,
+0x2c630002, 0xaf820200, 0x1460000c, 0x0,
+0x3c020002, 0x8c428680, 0x3c030002, 0x8c638664,
+0x3c040002, 0x8c848660, 0x34428000, 0x621825,
+0x641825, 0x1000000a, 0x34620002, 0x3c020002,
+0x8c428664, 0x3c030002, 0x8c638680, 0x3c040002,
+0x8c848660, 0x431025, 0x441025, 0x34420002,
+0xaf820220, 0x1000002f, 0x24020001, 0x24020e01,
+0xaf820238, 0x8f830050, 0x3c02f0ff, 0x3442ffff,
+0x3c040002, 0x8c8487d8, 0x621824, 0x3c020d00,
+0x621825, 0x24020001, 0xaf830050, 0xaf820200,
+0xaf820220, 0x10800005, 0x3c033f00, 0x3c020002,
+0x8c428654, 0x10000004, 0x34630070, 0x3c020002,
+0x8c428654, 0x34630072, 0x431025, 0xaf820200,
+0x3c030002, 0x8c638658, 0x3c02f700, 0x621825,
+0x3c020002, 0x8c428664, 0x3c040002, 0x8c848680,
+0x3c050002, 0x8ca587fc, 0x431025, 0x441025,
+0xaf820220, 0x24020005, 0x14a20006, 0x24020001,
+0x8f820044, 0x2403afff, 0x431024, 0xaf820044,
+0x24020001, 0xaf820238, 0x1000003f, 0x0,
+0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040002,
+0x8c8487d8, 0x621824, 0x3c020a00, 0x621825,
+0x24020001, 0xaf830050, 0xaf820200, 0xaf820220,
+0x1080001f, 0x0, 0x3c020002, 0x8c428708,
+0x1440001b, 0x3c033f00, 0x3c020002, 0x8c428654,
+0x1000001b, 0x346300e0, 0x8f830050, 0x3c040002,
+0x8c8487d8, 0x3442ffff, 0x621824, 0xaf830050,
+0x1080000f, 0x0, 0x3c020002, 0x8c428708,
+0x1440000b, 0x3c043f00, 0x3c030002, 0x8c638654,
+0x348400e0, 0x24020001, 0xaf820200, 0xaf820220,
+0x641825, 0xaf830200, 0x10000008, 0x3c05f700,
+0x3c020002, 0x8c428654, 0x3c033f00, 0x346300e2,
+0x431025, 0xaf820200, 0x3c05f700, 0x34a58000,
+0x3c030002, 0x8c638658, 0x3c020002, 0x8c428664,
+0x3c040002, 0x8c848680, 0x651825, 0x431025,
+0x441025, 0xaf820220, 0x3e00008, 0x0,
+0x3c030002, 0x8c638688, 0x3c020002, 0x8c42868c,
+0x27bdffe0, 0x10620003, 0xafbf0018, 0x3c010002,
+0xac23868c, 0x24020002, 0x1062003c, 0x2c620003,
+0x10400005, 0x24020001, 0x10620008, 0x24020004,
+0x10000055, 0x0, 0x24020009, 0x1062003f,
+0x240209e3, 0x10000050, 0x0, 0x3c030002,
+0x8c63866c, 0x10620008, 0x24020008, 0x14620010,
+0x240209ca, 0x3c0200c8, 0x344201fb, 0xaf820238,
+0x1000001e, 0x0, 0x24020e01, 0xaf820238,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0x34420080, 0xaf820044, 0x10000014, 0x0,
+0x3c040002, 0x248481c0, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070002, 0x24e781d8, 0xc002d3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8f830054,
+0x24020002, 0x3c010002, 0xac228688, 0x3c010002,
+0xac2387e8, 0x10000034, 0x0, 0x8f830054,
+0x3c020002, 0x8c4287e8, 0x2463d8f0, 0x431023,
+0x2c422710, 0x1440002c, 0x24020009, 0x3c010002,
+0xac228688, 0x10000028, 0x0, 0x3c040002,
+0x248481c0, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070002, 0x24e781d8, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x3c040002, 0x248481c0,
+0x240209e9, 0xafa20010, 0xafa00014, 0x8f860144,
+0x3c070002, 0x24e781d8, 0xc002d3b, 0x3405dead,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820140, 0x3c030001,
+0x431025, 0xaf820140, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x27bdffd8, 0xafb20018, 0x809021,
+0xafb3001c, 0xa09821, 0xafb10014, 0xc08821,
+0xafb00010, 0x8021, 0xafbf0020, 0xa6200000,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0x2501024,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x2501024, 0x24100010,
+0x2701024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x2701024,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x0,
+0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8,
+0xafb10014, 0x808821, 0xafb20018, 0xa09021,
+0xafb3001c, 0xc09821, 0xafb00010, 0x8021,
+0xafbf0020, 0xc00539d, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0x24100010,
+0x2301024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x2301024,
+0x24100010, 0x2501024, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x2501024, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x34108000, 0x96620000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fff8, 0x0, 0xc0053de,
+0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018,
+0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028,
+0x3c040002, 0x8c84869c, 0x3c020002, 0x8c4286e4,
+0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10820003,
+0xafb00018, 0x3c010002, 0xac2486e4, 0x3c030002,
+0x8c6387fc, 0x24020005, 0x14620005, 0x2483ffff,
+0xc004f82, 0x0, 0x1000034d, 0x0,
+0x2c620013, 0x1040034a, 0x31080, 0x3c010002,
+0x220821, 0x8c2282a8, 0x400008, 0x0,
+0xc0053de, 0x8021, 0x34028000, 0xa7a20010,
+0x27b10010, 0xc00539d, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc00539d, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x1000030f, 0x24020002,
+0x27b10010, 0xa7a00010, 0x8021, 0xc00539d,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc00539d, 0x2021, 0xc00539d,
+0x24040001, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc00539d,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x0,
+0x97a20010, 0x30428000, 0x144002dd, 0x24020003,
+0x100002d9, 0x0, 0x24021200, 0xa7a20010,
+0x27b10010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0xc00539d, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0xc00539d,
+0x24040001, 0xc00539d, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fff8,
+0x0, 0xc0053de, 0x0, 0x8f830054,
+0x10000296, 0x24020004, 0x8f830054, 0x3c020002,
+0x8c4287f8, 0x2463ff9c, 0x431023, 0x2c420064,
+0x1440029f, 0x24020002, 0x3c030002, 0x8c6387fc,
+0x10620298, 0x2c620003, 0x14400297, 0x24020011,
+0x24020003, 0x10620005, 0x24020004, 0x10620292,
+0x2402000f, 0x10000290, 0x24020011, 0x1000028e,
+0x24020005, 0x24020014, 0xa7a20010, 0x27b10010,
+0x8021, 0xc00539d, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020012, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020012, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x34108000, 0x96220000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fff8, 0x0, 0xc0053de,
+0x0, 0x8f830054, 0x10000248, 0x24020006,
+0x8f830054, 0x3c020002, 0x8c4287f8, 0x2463ff9c,
+0x431023, 0x2c420064, 0x14400251, 0x24020007,
+0x1000024d, 0x0, 0x24020006, 0xa7a20010,
+0x27b10010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020013, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020013, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x8f830054, 0x10000207,
+0x24020008, 0x8f830054, 0x3c020002, 0x8c4287f8,
+0x2463ff9c, 0x431023, 0x2c420064, 0x14400210,
+0x24020009, 0x1000020c, 0x0, 0x27b10010,
+0xa7a00010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020018, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0x97a20010, 0x27b10010,
+0x34420001, 0xa7a20010, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020018, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x8f830054, 0x10000193,
+0x2402000a, 0x8f830054, 0x3c020002, 0x8c4287f8,
+0x2463ff9c, 0x431023, 0x2c420064, 0x1440019c,
+0x2402000b, 0x10000198, 0x0, 0x27b10010,
+0xa7a00010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020017, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020017, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0x97a20010, 0x27b10010,
+0x34420700, 0xa7a20010, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020017, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020017, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x8f830054, 0x1000011f,
+0x2402000c, 0x8f830054, 0x3c020002, 0x8c4287f8,
+0x2463ff9c, 0x431023, 0x2c420064, 0x14400128,
+0x24020012, 0x10000124, 0x0, 0x27b10010,
+0xa7a00010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020014, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020014, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0x97a20010, 0x27b10010,
+0x34420010, 0xa7a20010, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020014, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020014, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x8f830054, 0x100000ab,
+0x24020013, 0x8f830054, 0x3c020002, 0x8c4287f8,
+0x2463ff9c, 0x431023, 0x2c420064, 0x144000b4,
+0x2402000d, 0x100000b0, 0x0, 0x27b10010,
+0xa7a00010, 0x8021, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020018, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0x97a20010, 0x27b10010,
+0x3042fffe, 0xa7a20010, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020018, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x96220000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x8f830054, 0x10000037,
+0x2402000e, 0x24020840, 0xa7a20010, 0x27b10010,
+0x8021, 0xc00539d, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020013, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020013, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x34108000, 0x96220000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fff8, 0x0, 0xc0053de,
+0x0, 0x8f830054, 0x24020010, 0x3c010002,
+0xac22869c, 0x3c010002, 0xac2387f8, 0x1000000c,
+0x0, 0x8f830054, 0x3c020002, 0x8c4287f8,
+0x2463ff9c, 0x431023, 0x2c420064, 0x14400004,
+0x0, 0x24020011, 0x3c010002, 0xac22869c,
+0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x3c030002, 0x8c63866c, 0x27bdffc8,
+0x24020002, 0xafbf0034, 0xafb20030, 0xafb1002c,
+0x14620005, 0xafb00028, 0x3c120002, 0x8e52a8b8,
+0x10000003, 0x0, 0x3c120002, 0x8e52a8bc,
+0x3c030002, 0x8c6386a0, 0x3c020002, 0x8c4286e8,
+0x50620004, 0x2463ffff, 0x3c010002, 0xac2386e8,
+0x2463ffff, 0x2c620006, 0x1040037c, 0x31080,
+0x3c010002, 0x220821, 0x8c228300, 0x400008,
+0x0, 0x2021, 0x2821, 0xc005400,
+0x34068000, 0x24040010, 0x24050002, 0x24060002,
+0x24020002, 0xc005400, 0xa7a20018, 0x24020002,
+0x3c010002, 0xac2286a0, 0x10000368, 0x0,
+0x27b10018, 0xa7a00018, 0x8021, 0xc00539d,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc00539d, 0x2021, 0xc00539d,
+0x24040001, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc00539d,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x0,
+0x97a20018, 0x30428000, 0x14400004, 0x24020003,
+0x3c010002, 0xac2286a0, 0x24020003, 0x3c010002,
+0xac2286a0, 0x1000032d, 0x0, 0x24040010,
+0x24050002, 0x24060002, 0x24020002, 0xc005400,
+0xa7a20018, 0x3c030002, 0x8c6386ec, 0x24020001,
+0x146201e1, 0x8021, 0x27b10018, 0xa7a00018,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x32020018,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x8021,
+0x27b10018, 0xa7a00018, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020018, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0x24040018, 0x2821,
+0xc005400, 0x24060404, 0xa7a0001a, 0xc00539d,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc00539d, 0x2021, 0xc00539d,
+0x24040001, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020018,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020018, 0xc0053de,
+0x34108000, 0xc0053de, 0x0, 0xc00537d,
+0x0, 0x50400005, 0x108042, 0x97a2001a,
+0x501025, 0xa7a2001a, 0x108042, 0x1600fff7,
+0x0, 0xc0053de, 0x8021, 0xa7a0001a,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x32020018,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x8021,
+0xa7a0001c, 0xc00539d, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc00539d,
+0x2021, 0xc00539d, 0x24040001, 0xc00539d,
+0x24040001, 0xc00539d, 0x2021, 0x24100010,
+0xc00539d, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0x24100010, 0x3202001e, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fffa, 0x3202001e, 0xc0053de, 0x34108000,
+0xc0053de, 0x0, 0xc00537d, 0x0,
+0x50400005, 0x108042, 0x97a2001c, 0x501025,
+0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
+0xc0053de, 0x8021, 0xa7a0001c, 0xc00539d,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc00539d, 0x2021, 0xc00539d,
+0x24040001, 0xc00539d, 0x24040001, 0xc00539d,
+0x2021, 0x24100010, 0xc00539d, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0x24100010,
+0x3202001e, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x3202001e,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x8021,
+0x24020002, 0xa7a2001e, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0x24100010, 0xc00539d, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0x24100010, 0x3202001e,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x3202001e, 0xc00539d,
+0x24040001, 0xc00539d, 0x2021, 0x34108000,
+0x97a2001e, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fff8,
+0x0, 0xc0053de, 0x8021, 0xa7a00020,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0xc00539d,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0x24100010, 0x3202001e, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x3202001e, 0xc0053de, 0x34108000, 0xc0053de,
+0x0, 0xc00537d, 0x0, 0x50400005,
+0x108042, 0x97a20020, 0x501025, 0xa7a20020,
+0x108042, 0x1600fff7, 0x0, 0xc0053de,
+0x8021, 0xa7a00020, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0xc00539d, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0x24100010, 0x3202001e,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x3202001e, 0xc0053de,
+0x34108000, 0xc0053de, 0x0, 0xc00537d,
+0x0, 0x50400005, 0x108042, 0x97a20020,
+0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
+0x0, 0xc0053de, 0x8021, 0xa7a00022,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0x24100010, 0xc00539d,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0x24100010, 0xc00539d, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x34108000, 0x97a20022,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fff8, 0x0,
+0xc0053de, 0x0, 0x24040018, 0x24050002,
+0xc005400, 0x24060004, 0x3c100002, 0x8e1086f0,
+0x24020001, 0x1602011e, 0x0, 0x3c020002,
+0x944287e2, 0x3c010002, 0xac2086f0, 0x24429fbc,
+0x2c420004, 0x1040000c, 0x24040009, 0x24050001,
+0xc005400, 0x24060400, 0x24040018, 0x24050001,
+0xc005400, 0x24060020, 0x24040018, 0x24050001,
+0xc005400, 0x24062000, 0x3c024000, 0x2421024,
+0x10400126, 0x3c022000, 0x2421024, 0x10400005,
+0x0, 0x3c010002, 0xac3087d8, 0x10000003,
+0x0, 0x3c010002, 0xac2087d8, 0x3c030002,
+0x8c6387f0, 0x24020005, 0x146200f9, 0x0,
+0x3c020002, 0x8c4287d8, 0x10400067, 0x3c020004,
+0x2421024, 0x10400011, 0xa7a00018, 0x3c020008,
+0x2421024, 0x10400002, 0x24020200, 0xa7a20018,
+0x3c020010, 0x2421024, 0x10400004, 0x0,
+0x97a20018, 0x34420100, 0xa7a20018, 0x97a60018,
+0x24040009, 0x10000004, 0x2821, 0x24040009,
+0x2821, 0x3021, 0xc005400, 0x0,
+0x24020001, 0xa7a2001a, 0x3c020008, 0x2421024,
+0x1040000c, 0x3c020002, 0x2421024, 0x10400002,
+0x24020101, 0xa7a2001a, 0x3c020001, 0x2421024,
+0x10400005, 0x3c020010, 0x97a2001a, 0x34420040,
+0xa7a2001a, 0x3c020010, 0x2421024, 0x1040000e,
+0x3c020002, 0x2421024, 0x10400005, 0x3c020001,
+0x97a2001a, 0x34420080, 0xa7a2001a, 0x3c020001,
+0x2421024, 0x10400005, 0x3c0300a0, 0x97a2001a,
+0x34420020, 0xa7a2001a, 0x3c0300a0, 0x2431024,
+0x54430004, 0x3c020020, 0x97a2001a, 0x1000000c,
+0x34420400, 0x2421024, 0x50400004, 0x3c020080,
+0x97a2001a, 0x10000006, 0x34420800, 0x2421024,
+0x10400004, 0x0, 0x97a2001a, 0x34420c00,
+0xa7a2001a, 0x97a6001a, 0x24040004, 0xc005400,
+0x2821, 0x3c020004, 0x2421024, 0x10400004,
+0xa7a0001c, 0x32425000, 0x14400004, 0x0,
+0x32424000, 0x10400005, 0x2021, 0xc00531e,
+0x2402021, 0x10000096, 0x0, 0x97a6001c,
+0x2821, 0x34c61200, 0xc005400, 0xa7a6001c,
+0x1000008f, 0x0, 0x2421024, 0x10400004,
+0xa7a00018, 0x32425000, 0x14400004, 0x0,
+0x32424000, 0x10400005, 0x3c020010, 0xc00531e,
+0x2402021, 0x10000019, 0xa7a0001a, 0x2421024,
+0x10400004, 0x0, 0x97a20018, 0x10000004,
+0xa7a20018, 0x97a20018, 0x34420100, 0xa7a20018,
+0x3c020001, 0x2421024, 0x10400004, 0x0,
+0x97a20018, 0x10000004, 0xa7a20018, 0x97a20018,
+0x34422000, 0xa7a20018, 0x97a60018, 0x2021,
+0xc005400, 0x2821, 0xa7a0001a, 0x8021,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0xc00539d, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc0053de, 0x34108000, 0xc0053de,
+0x0, 0xc00537d, 0x0, 0x50400005,
+0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
+0x108042, 0x1600fff7, 0x0, 0xc0053de,
+0x8021, 0xa7a0001a, 0xc00539d, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc00539d, 0x2021, 0xc00539d, 0x24040001,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc00539d, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0xc00539d, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0xc0053de,
+0x34108000, 0xc0053de, 0x0, 0xc00537d,
+0x0, 0x50400005, 0x108042, 0x97a2001a,
+0x501025, 0xa7a2001a, 0x108042, 0x1600fff7,
+0x0, 0xc0053de, 0x0, 0x3c040002,
+0x248482f4, 0x97a60018, 0x97a7001a, 0x3c020002,
+0x8c42866c, 0x3c030002, 0x8c6387d8, 0x3c05000d,
+0x34a50205, 0xafa20010, 0xc002d3b, 0xafa30014,
+0x8f830054, 0x24020004, 0x3c010002, 0xac2286a0,
+0x3c010002, 0xac2387f4, 0x10000018, 0x0,
+0x8f830054, 0x3c020002, 0x8c4287f4, 0x2463ff9c,
+0x431023, 0x2c420064, 0x14400010, 0x0,
+0x8f820220, 0x24030005, 0x3c010002, 0xac2386a0,
+0x3c03f700, 0x431025, 0xaf820220, 0x10000007,
+0x0, 0x24020006, 0x3c010002, 0xac2286a0,
+0x24020011, 0x3c010002, 0xac22869c, 0x8fbf0034,
+0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
+0x27bd0038, 0x27bdffd8, 0xafb00018, 0x808021,
+0xafb1001c, 0x8821, 0x32024000, 0x10400013,
+0xafbf0020, 0x3c020010, 0x2021024, 0x2c420001,
+0x21023, 0x30434100, 0x3c020001, 0x2021024,
+0x14400006, 0x34714000, 0x3c020002, 0x2021024,
+0x14400002, 0x34716000, 0x34714040, 0x2021,
+0x2821, 0x10000036, 0x2203021, 0x32021000,
+0x10400035, 0x2021, 0x2821, 0xc005400,
+0x24060040, 0x24040018, 0x2821, 0xc005400,
+0x24060c00, 0x24040017, 0x2821, 0xc005400,
+0x24060400, 0x24040016, 0x2821, 0xc005400,
+0x24060006, 0x24040017, 0x2821, 0xc005400,
+0x24062500, 0x24040016, 0x2821, 0xc005400,
+0x24060006, 0x24040017, 0x2821, 0xc005400,
+0x24064600, 0x24040016, 0x2821, 0xc005400,
+0x24060006, 0x24040017, 0x2821, 0xc005400,
+0x24066700, 0x24040016, 0x2821, 0xc005400,
+0x24060006, 0x2404001f, 0x2821, 0xc005400,
+0x24060010, 0x24040009, 0x2821, 0xc005400,
+0x24061500, 0x24040009, 0x2821, 0x24061d00,
+0xc005400, 0x0, 0x3c040002, 0x24848318,
+0x3c05000e, 0x34a50100, 0x2003021, 0x2203821,
+0xafa00010, 0xc002d3b, 0xafa00014, 0x8fbf0020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+0x8f850044, 0x8f820044, 0x3c030001, 0x431025,
+0x3c030008, 0xaf820044, 0x8f840054, 0x8f820054,
+0xa32824, 0x10000002, 0x24840001, 0x8f820054,
+0x821023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x3e00008, 0xa01021,
+0x8f830044, 0x3c02fff0, 0x3442ffff, 0x42480,
+0x621824, 0x3c020002, 0x822025, 0x641825,
+0xaf830044, 0x8f820044, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
+0x3c030001, 0x431025, 0xaf820044, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0x0, 0x8f820044, 0x2403ff7f,
+0x431024, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
+0x34420080, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
+0x0, 0x8f820044, 0x3c03fff0, 0x3463ffff,
+0x431024, 0xaf820044, 0x8f820044, 0x3c030001,
+0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x3e00008, 0x0, 0x27bdffc8,
+0xafb30024, 0x809821, 0xafbe002c, 0xa0f021,
+0xafb20020, 0xc09021, 0x33c2ffff, 0xafbf0030,
+0xafb50028, 0xafb1001c, 0xafb00018, 0x14400034,
+0xa7b20010, 0x3271ffff, 0x27b20010, 0x8021,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x2301024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x2301024,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x34108000, 0x96420000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x12000075, 0x0, 0x1000fff6, 0x0,
+0x3275ffff, 0x27b10010, 0xa7a00010, 0x8021,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x24040001,
+0xc00539d, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x2b01024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x2b01024,
+0xc0053de, 0x34108000, 0xc0053de, 0x0,
+0xc00537d, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc0053de, 0x0,
+0x33c5ffff, 0x24020001, 0x54a20004, 0x24020002,
+0x97a20010, 0x10000006, 0x521025, 0x14a20006,
+0x3271ffff, 0x97a20010, 0x121827, 0x431024,
+0xa7a20010, 0x3271ffff, 0x27b20010, 0x8021,
+0xc00539d, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0xc00539d, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc00539d,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x2301024, 0x10400002, 0x2021, 0x24040001,
+0xc00539d, 0x108042, 0x1600fffa, 0x2301024,
+0xc00539d, 0x24040001, 0xc00539d, 0x2021,
+0x34108000, 0x96420000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc00539d, 0x108042,
+0x1600fff8, 0x0, 0xc0053de, 0x0,
+0x8fbf0030, 0x8fbe002c, 0x8fb50028, 0x8fb30024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0038, 0x27bdffe8, 0xafbf0010, 0x8ee304b8,
+0x24020008, 0x146201f1, 0x0, 0x3c020002,
+0x8c4287d8, 0x14400006, 0x0, 0x8f840224,
+0xc00430b, 0x0, 0x100001e8, 0x0,
+0x8f820220, 0x3c030008, 0x431024, 0x10400029,
+0x24020001, 0x8f840224, 0x8f820220, 0x3c030400,
+0x431024, 0x10400007, 0x0, 0x3c010002,
+0xac20a860, 0x3c010002, 0xac20a880, 0x1000000b,
+0x0, 0x3c030002, 0x2463a860, 0x8c620000,
+0x24420001, 0xac620000, 0x2c420002, 0x14400003,
+0x24020001, 0x3c010002, 0xac22a880, 0x3c020002,
+0x8c42a880, 0x10400007, 0x30820040, 0x10400005,
+0x24020001, 0x3c010002, 0xac22a884, 0x10000003,
+0x0, 0x3c010002, 0xac20a884, 0x3c010002,
+0xac24a85c, 0x3c010002, 0xac20a890, 0x1000000b,
+0x0, 0x3c010002, 0xac22a890, 0x3c010002,
+0xac20a880, 0x3c010002, 0xac20a860, 0x3c010002,
+0xac20a884, 0x3c010002, 0xac20a85c, 0x3c030002,
+0x8c63a850, 0x3c020002, 0x8c42a854, 0x50620004,
+0x2463ffff, 0x3c010002, 0xac23a854, 0x2463ffff,
+0x2c62000e, 0x104001a1, 0x31080, 0x3c010002,
+0x220821, 0x8c228338, 0x400008, 0x0,
+0x24020002, 0x3c010002, 0xac20a880, 0x3c010002,
+0xac20a860, 0x3c010002, 0xac20a85c, 0x3c010002,
+0xac20a884, 0x3c010002, 0xac20a878, 0x3c010002,
+0xac20a870, 0xaf800224, 0x3c010002, 0xac22a850,
+0x3c020002, 0x8c42a890, 0x14400053, 0x3c02fdff,
+0x3442ffff, 0xc00430b, 0x282a024, 0xaf800204,
+0x8f820200, 0x2403fffd, 0x431024, 0xaf820200,
+0x3c010002, 0xac20a8a0, 0x8f830054, 0x3c020002,
+0x8c42a878, 0x24040001, 0x3c010002, 0xac24a88c,
+0x24420001, 0x3c010002, 0xac22a878, 0x2c420004,
+0x3c010002, 0xac23a874, 0x14400007, 0x24020003,
+0x3c010002, 0xac248670, 0x3c010002, 0xac20a878,
+0x1000016a, 0x0, 0x3c010002, 0xac22a850,
+0x10000166, 0x0, 0x8f830054, 0x3c020002,
+0x8c42a874, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400003, 0x24020004, 0x3c010002, 0xac22a850,
+0x3c020002, 0x8c42a890, 0x14400023, 0x3c02fdff,
+0x3442ffff, 0x10000155, 0x282a024, 0x3c040002,
+0x8c8487dc, 0x3c010002, 0xac20a868, 0xc0056b7,
+0x0, 0x3c020002, 0x8c42a89c, 0xaf820204,
+0x3c020002, 0x8c42a890, 0x14400013, 0x3c03fdff,
+0x8f820204, 0x3463ffff, 0x30420030, 0x14400138,
+0x283a024, 0x3c030002, 0x8c63a89c, 0x24020005,
+0x3c010002, 0xac22a850, 0x3c010002, 0xac23a8a0,
+0x1000013a, 0x0, 0x3c020002, 0x8c42a890,
+0x10400011, 0x3c02fdff, 0x3c020002, 0x8c428700,
+0x24420001, 0x3c010002, 0xac228700, 0x2c420002,
+0x1440012e, 0x24020001, 0x3c010002, 0xac228708,
+0x3c010002, 0xac208700, 0x3c010002, 0xac228670,
+0x10000126, 0x0, 0x3c030002, 0x8c63a880,
+0x3442ffff, 0x10600121, 0x282a024, 0x3c020002,
+0x8c42a85c, 0x1040011d, 0x0, 0x3c010002,
+0xac22a888, 0x24020003, 0x3c010002, 0xac22a860,
+0x100000bd, 0x24020006, 0x3c010002, 0xac20a868,
+0x8f820204, 0x34420040, 0xaf820204, 0x3c020002,
+0x8c42a8a0, 0x24030007, 0x3c010002, 0xac23a850,
+0x34420040, 0x3c010002, 0xac22a8a0, 0x3c020002,
+0x8c42a880, 0x10400005, 0x0, 0x3c020002,
+0x8c42a85c, 0x104000f7, 0x24020002, 0x3c050002,
+0x24a5a860, 0x8ca20000, 0x2c424e21, 0x104000f1,
+0x24020002, 0x3c020002, 0x8c42a884, 0x104000f7,
+0x2404ffbf, 0x3c020002, 0x8c42a85c, 0x3c030002,
+0x8c63a888, 0x441024, 0x641824, 0x10430005,
+0x24020001, 0x3c010002, 0xac22a850, 0x100000eb,
+0x0, 0x24020003, 0xaca20000, 0x24020008,
+0x3c010002, 0xac22a850, 0x3c020002, 0x8c42a88c,
+0x1040000d, 0x24020001, 0x3c040002, 0x8c84a85c,
+0xc0056c4, 0x0, 0x3c020002, 0x8c42a8a8,
+0x14400005, 0x24020001, 0x3c020002, 0x8c42a8a4,
+0x10400007, 0x24020001, 0x3c010002, 0xac228670,
+0x3c010002, 0xac20a878, 0x100000d0, 0x0,
+0x3c020002, 0x8c42a870, 0x3c030002, 0x8c63a85c,
+0x2c420001, 0x210c0, 0x30630008, 0x3c010002,
+0xac22a870, 0x3c010002, 0xac23a86c, 0x8f830054,
+0x24020009, 0x3c010002, 0xac22a850, 0x3c010002,
+0xac23a874, 0x100000bd, 0x0, 0x8f830054,
+0x3c020002, 0x8c42a874, 0x2463d8f0, 0x431023,
+0x2c422710, 0x144000a2, 0x0, 0x3c020002,
+0x8c42a880, 0x10400005, 0x0, 0x3c020002,
+0x8c42a85c, 0x104000a3, 0x24020002, 0x3c030002,
+0x2463a860, 0x8c620000, 0x2c424e21, 0x1040009d,
+0x24020002, 0x3c020002, 0x8c42a88c, 0x1040000e,
+0x0, 0x3c020002, 0x8c42a85c, 0x3c010002,
+0xac20a88c, 0x30420080, 0x1040002f, 0x2402000c,
+0x8f820204, 0x30420080, 0x1440000c, 0x24020003,
+0x10000029, 0x2402000c, 0x3c020002, 0x8c42a85c,
+0x30420080, 0x14400005, 0x24020003, 0x8f820204,
+0x30420080, 0x1040001f, 0x24020003, 0xac620000,
+0x2402000a, 0x3c010002, 0xac22a850, 0x3c040002,
+0x2484a898, 0x8c820000, 0x3c030002, 0x8c63a870,
+0x431025, 0xaf820204, 0x8c830000, 0x3c040002,
+0x8c84a870, 0x2402000b, 0x3c010002, 0xac22a850,
+0x641825, 0x3c010002, 0xac23a8a0, 0x3c050002,
+0x24a5a860, 0x8ca20000, 0x2c424e21, 0x10400069,
+0x24020002, 0x3c020002, 0x8c42a890, 0x10400006,
+0x0, 0x2402000c, 0x3c010002, 0xac22a850,
+0x1000006a, 0x0, 0x3c020002, 0x8c42a880,
+0x10400066, 0x0, 0x3c040002, 0x8c84a85c,
+0x10800057, 0x30820008, 0x3c030002, 0x8c63a86c,
+0x1062005e, 0x24020003, 0x3c010002, 0xac24a888,
+0xaca20000, 0x24020006, 0x3c010002, 0xac22a850,
+0x10000056, 0x0, 0x8f820200, 0x34420002,
+0xaf820200, 0x8f830054, 0x2402000d, 0x3c010002,
+0xac22a850, 0x3c010002, 0xac23a874, 0x8f830054,
+0x3c020002, 0x8c42a874, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400032, 0x0, 0x3c020002,
+0x8c42a890, 0x10400021, 0x2402000e, 0x3c030002,
+0x8c63a8a4, 0x3c010002, 0xac22a850, 0x14600015,
+0x0, 0xc0043c9, 0x0, 0x3c050002,
+0x8ca5866c, 0xc0058d7, 0x2021, 0x3c030002,
+0x8c63866c, 0x24020004, 0x14620005, 0x2403fffb,
+0x3c020002, 0x8c428668, 0x10000003, 0x2403fff7,
+0x3c020002, 0x8c428668, 0x431024, 0x3c010002,
+0xac228668, 0x8f830224, 0x3c020200, 0x3c010002,
+0xac23a8ac, 0x10000021, 0x282a025, 0x3c020002,
+0x8c42a880, 0x10400005, 0x0, 0x3c020002,
+0x8c42a85c, 0x1040000f, 0x24020002, 0x3c020002,
+0x8c42a860, 0x2c424e21, 0x1040000a, 0x24020002,
+0x3c020002, 0x8c42a880, 0x10400010, 0x0,
+0x3c020002, 0x8c42a85c, 0x1440000c, 0x0,
+0x24020002, 0x3c010002, 0xac22a850, 0x10000007,
+0x0, 0x3c020002, 0x8c42a880, 0x10400003,
+0x0, 0xc00430b, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010,
+0x3e00008, 0x27bd0018, 0x3c030002, 0x2463a8a8,
+0x8c620000, 0x10400005, 0x34422000, 0x3c010002,
+0xac22a89c, 0x10000003, 0xac600000, 0x3c010002,
+0xac24a89c, 0x3e00008, 0x0, 0x27bdffe0,
+0x30820030, 0xafbf0018, 0x3c010002, 0xac22a8a4,
+0x1440006b, 0x3c02ffff, 0x34421f0e, 0x821024,
+0x14400065, 0x24020030, 0x30822000, 0x10400061,
+0x30838000, 0x31a02, 0x30820001, 0x21200,
+0x3c040002, 0x8c8487dc, 0x621825, 0x331c2,
+0x3c030002, 0x2463870c, 0x30828000, 0x21202,
+0x30840001, 0x42200, 0x441025, 0x239c2,
+0x61080, 0x431021, 0x471021, 0x90430000,
+0x24020001, 0x10620027, 0x0, 0x10600007,
+0x24020002, 0x10620014, 0x24020003, 0x1062002f,
+0x3c05000f, 0x1000003b, 0x0, 0x8f820200,
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+0x3c010002, 0xac20a8c4, 0x3c010002, 0xac20a8cc,
+0x10000037, 0x0, 0x8f820200, 0x34420100,
+0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820220, 0x24020100, 0x3c010002,
+0xac22a8c4, 0x3c010002, 0xac20a8cc, 0x10000028,
+0x0, 0x8f820200, 0x2403feff, 0x431024,
+0xaf820200, 0x8f820220, 0x3c030001, 0x431025,
+0xaf820220, 0x3c010002, 0xac20a8c4, 0x3c010002,
+0xac23a8cc, 0x1000001a, 0x0, 0x8f820200,
+0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x24020100, 0x3c010002,
+0xac22a8c4, 0x3c010002, 0xac23a8cc, 0x1000000c,
+0x0, 0x34a5ffff, 0x3c040002, 0x24848370,
+0xafa30010, 0xc002d3b, 0xafa00014, 0x10000004,
+0x0, 0x24020030, 0x3c010002, 0xac22a8a8,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffc8,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040002, 0x24848398,
+0x3c050009, 0x3c020002, 0x8c42866c, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+0xa7a0001a, 0xafb00014, 0xc002d3b, 0xafa20010,
+0x24020002, 0x12620086, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x1000017b,
+0x0, 0x24020004, 0x126200fc, 0x24020008,
+0x126200fb, 0x3c02ffec, 0x10000174, 0x0,
+0x3c020002, 0x8c428668, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010002, 0x310821, 0xac30a8bc, 0x3c024000,
+0x2021024, 0x10400050, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030002, 0x246386a4,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010002, 0x310821,
+0xac22a8c0, 0x10000005, 0x3c020080, 0x3c010002,
+0x310821, 0xac20a8c0, 0x3c020080, 0x2021024,
+0x10400007, 0x121940, 0x3c020001, 0x3c010002,
+0x230821, 0xac22a8c8, 0x10000005, 0x0,
+0x121140, 0x3c010002, 0x220821, 0xac20a8c8,
+0x94e40000, 0x3c030002, 0x8c6387fc, 0x24020005,
+0x10620010, 0xa7a40018, 0x32024000, 0x10400002,
+0x34824000, 0xa7a20018, 0x24040001, 0x94e20002,
+0x24050004, 0x24e60002, 0x34420001, 0xc004bdc,
+0xa4e20002, 0x24040001, 0x2821, 0xc004bdc,
+0x27a60018, 0x3c020002, 0x8c42866c, 0x24110001,
+0x3c010002, 0xac318678, 0x14530004, 0x32028000,
+0xc00430b, 0x0, 0x32028000, 0x10400123,
+0x0, 0xc00430b, 0x0, 0x3c030002,
+0x8c6387fc, 0x24020005, 0x1062011c, 0x24020002,
+0x3c010002, 0xac318670, 0x3c010002, 0xac22866c,
+0x10000116, 0x0, 0x24040001, 0x24050004,
+0x27b0001a, 0xc004bdc, 0x2003021, 0x24040001,
+0x2821, 0xc004bdc, 0x2003021, 0x3c020002,
+0x511021, 0x8c42a8b4, 0x3c040002, 0x8c84866c,
+0x3c03bfff, 0x3463ffff, 0x3c010002, 0xac338678,
+0x431024, 0x3c010002, 0x310821, 0xac22a8b4,
+0x109300fc, 0x0, 0x100000fc, 0x0,
+0x3c022000, 0x2021024, 0x10400005, 0x24020001,
+0x3c010002, 0xac2287d8, 0x10000004, 0x128940,
+0x3c010002, 0xac2087d8, 0x128940, 0x3c010002,
+0x310821, 0xac30a8b8, 0x3c024000, 0x2021024,
+0x14400015, 0x0, 0x3c020002, 0x8c4287d8,
+0x10400006, 0x24040004, 0x24050001, 0xc005400,
+0x24062000, 0x24020001, 0xaee204b8, 0x3c020002,
+0x511021, 0x8c42a8b0, 0x3c03bfff, 0x3463ffff,
+0x431024, 0x3c010002, 0x310821, 0xac22a8b0,
+0x100000d4, 0x0, 0x3c020002, 0x8c4287d8,
+0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
+0x3c020020, 0x3c020002, 0x8c4287dc, 0x24030100,
+0x3c010002, 0x310821, 0xac23a8c4, 0x3c030001,
+0x3c010002, 0x310821, 0xac23a8cc, 0x10000015,
+0x34420400, 0x2021024, 0x10400008, 0x24030100,
+0x3c020002, 0x8c4287dc, 0x3c010002, 0x310821,
+0xac23a8c4, 0x1000000b, 0x34420800, 0x3c020080,
+0x2021024, 0x1040002e, 0x3c030001, 0x3c020002,
+0x8c4287dc, 0x3c010002, 0x310821, 0xac23a8cc,
+0x34420c00, 0x3c010002, 0xac2287dc, 0x10000025,
+0x24040001, 0x3c020020, 0x2021024, 0x10400006,
+0x24020100, 0x3c010002, 0x310821, 0xac22a8c4,
+0x10000005, 0x3c020080, 0x3c010002, 0x310821,
+0xac20a8c4, 0x3c020080, 0x2021024, 0x10400007,
+0x121940, 0x3c020001, 0x3c010002, 0x230821,
+0xac22a8cc, 0x10000006, 0x24040001, 0x121140,
+0x3c010002, 0x220821, 0xac20a8cc, 0x24040001,
+0x2821, 0x27b0001e, 0xc004b9a, 0x2003021,
+0x24040001, 0x2821, 0xc004b9a, 0x2003021,
+0x24040001, 0x24050001, 0x27b0001c, 0xc004b9a,
+0x2003021, 0x24040001, 0x24050001, 0xc004b9a,
+0x2003021, 0x1000007b, 0x0, 0x3c02ffec,
+0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
+0x121140, 0x3c010002, 0x220821, 0xac30a8b8,
+0x3c022000, 0x2021024, 0x10400009, 0x0,
+0x3c020002, 0x8c428708, 0x14400005, 0x24020001,
+0x3c010002, 0xac2287d8, 0x10000004, 0x3c024000,
+0x3c010002, 0xac2087d8, 0x3c024000, 0x2021024,
+0x1440001d, 0x24020e01, 0x3c030002, 0x8c6387d8,
+0xaf820238, 0x3c010002, 0xac208684, 0x10600005,
+0x24022020, 0x3c010002, 0xac2287dc, 0x24020001,
+0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
+0x431021, 0x8c42a8b0, 0x3c050002, 0x8ca5866c,
+0x3484ffff, 0x441024, 0x3c010002, 0x230821,
+0xac22a8b0, 0x24020001, 0x10a20048, 0x0,
+0x10000044, 0x0, 0x3c020002, 0x8c4287d8,
+0x1040001f, 0x24022000, 0x3c010002, 0xac2287dc,
+0x3c0300a0, 0x2031024, 0x14430006, 0x121140,
+0x3402a000, 0x3c010002, 0xac2287dc, 0x10000030,
+0x0, 0x3c030002, 0x621821, 0x8c63a8b8,
+0x3c020020, 0x621024, 0x10400005, 0x24022001,
+0x3c010002, 0xac2287dc, 0x10000025, 0x0,
+0x3c020080, 0x621024, 0x10400021, 0x3402a001,
+0x3c010002, 0xac2287dc, 0x1000001d, 0x0,
+0x3c020020, 0x2021024, 0x10400007, 0x121940,
+0x24020100, 0x3c010002, 0x230821, 0xac22a8c4,
+0x10000006, 0x3c020080, 0x121140, 0x3c010002,
+0x220821, 0xac20a8c4, 0x3c020080, 0x2021024,
+0x10400007, 0x121940, 0x3c020001, 0x3c010002,
+0x230821, 0xac22a8cc, 0x10000005, 0x0,
+0x121140, 0x3c010002, 0x220821, 0xac20a8cc,
+0x3c030002, 0x8c63866c, 0x24020001, 0x10620003,
+0x0, 0xc00430b, 0x0, 0x8fbf0030,
+0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
+0x9821, 0xafb50040, 0xa821, 0xafb10034,
+0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
+0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
+0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
+0x10a20131, 0xa7a0001c, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x3c024000, 0x1000025f,
+0x2201021, 0x24020004, 0x10a2020c, 0x24020008,
+0x10a2020a, 0x2201021, 0x10000258, 0x0,
+0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
+0x8c63a8bc, 0x621024, 0x14400009, 0x24040001,
+0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
+0x300821, 0xac31a8b4, 0x10000248, 0x2201021,
+0x24050001, 0xc004b9a, 0x27a60018, 0x24040001,
+0x24050001, 0xc004b9a, 0x27a60018, 0x97a20018,
+0x30420004, 0x104000da, 0x3c114000, 0x3c020002,
+0x8c4287fc, 0x2443ffff, 0x2c620006, 0x104000da,
+0x31080, 0x3c010002, 0x220821, 0x8c2283b0,
+0x400008, 0x0, 0x24040001, 0x24050011,
+0x27b0001a, 0xc004b9a, 0x2003021, 0x24040001,
+0x24050011, 0xc004b9a, 0x2003021, 0x97a3001a,
+0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
+0x30628000, 0x104000ab, 0x3c130001, 0x100000a9,
+0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
+0xc004b9a, 0x2003021, 0x24040001, 0x24050014,
+0xc004b9a, 0x2003021, 0x97a3001a, 0x30621000,
+0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
+0x10400098, 0x3c130001, 0x10000096, 0x3c130002,
+0x24040001, 0x24050019, 0x27b0001c, 0xc004b9a,
+0x2003021, 0x24040001, 0x24050019, 0xc004b9a,
+0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
+0x10620027, 0x28620401, 0x1040000e, 0x24020200,
+0x1062001f, 0x28620201, 0x10400005, 0x24020100,
+0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
+0x24020300, 0x50620019, 0x3c130002, 0x10000019,
+0x24040001, 0x24020600, 0x1062000d, 0x28620601,
+0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
+0x10000010, 0x24040001, 0x24020700, 0x1462000d,
+0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
+0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
+0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
+0x24040001, 0x24050018, 0x27b0001e, 0xc004b9a,
+0x2003021, 0x24040001, 0x24050018, 0xc004b9a,
+0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
+0x3c060002, 0xc23021, 0x8cc6a8b4, 0x97a20022,
+0x3c100002, 0x261083a4, 0x2002021, 0xafa20010,
+0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002d3b,
+0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
+0x8f840054, 0x24030001, 0x24020002, 0x3c010002,
+0xac238670, 0x3c010002, 0xac22866c, 0x3c010002,
+0xac238678, 0x3c010002, 0xac2386f0, 0x3c010002,
+0xac2487ec, 0x10000050, 0x2b38825, 0x1662003a,
+0x3c028000, 0x3c020002, 0x8c4286ec, 0x1440001f,
+0x24040018, 0x2021, 0x2821, 0xc005400,
+0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
+0x10000002, 0x24630032, 0x8f820054, 0x621023,
+0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
+0x24020001, 0x3c010002, 0xac2286ec, 0x3c010002,
+0xac228670, 0x3c010002, 0xac22866c, 0x3c010002,
+0xac228678, 0x3c010002, 0xac2286f0, 0x3c010002,
+0xac2387ec, 0x1000002c, 0x0, 0x2821,
+0xc005400, 0x24060404, 0x2021, 0x2405001e,
+0x27a60018, 0x24020002, 0xc004bdc, 0xa7a20018,
+0x2021, 0x2821, 0x27a60018, 0xc004bdc,
+0xa7a00018, 0x24040018, 0x24050002, 0xc005400,
+0x24060004, 0x3c028000, 0x2221025, 0x2b31825,
+0x10000015, 0x438825, 0x2221025, 0x2751825,
+0x438825, 0x2002021, 0x97a6001c, 0x3c070002,
+0x8ce7866c, 0x3c05000c, 0x34a50326, 0xafb30010,
+0xc002d3b, 0xafb10014, 0x10000007, 0x0,
+0x3c110002, 0x2308821, 0x8e31a8bc, 0x3c027fff,
+0x3442ffff, 0x2228824, 0x3c020002, 0x8c42867c,
+0x1040001e, 0x0, 0x3c020002, 0x8c4287d8,
+0x10400002, 0x3c022000, 0x2228825, 0x8fa8002c,
+0x81140, 0x3c010002, 0x220821, 0x8c22a8c0,
+0x10400003, 0x3c020020, 0x10000005, 0x2228825,
+0x3c02ffdf, 0x3442ffff, 0x2228824, 0x8fa8002c,
+0x81140, 0x3c010002, 0x220821, 0x8c22a8c8,
+0x10400003, 0x3c020080, 0x10000004, 0x2228825,
+0x3c02ff7f, 0x3442ffff, 0x2228824, 0x8fa8002c,
+0x81140, 0x3c010002, 0x220821, 0xac31a8b4,
+0x10000136, 0x2201021, 0x8fa8002c, 0x8f140,
+0x3c030002, 0x7e1821, 0x8c63a8b8, 0x3c024000,
+0x621024, 0x14400009, 0x24040001, 0x3c027fff,
+0x3442ffff, 0x628824, 0x3c010002, 0x3e0821,
+0xac31a8b0, 0x10000125, 0x2201021, 0x2821,
+0xc004b9a, 0x27a60018, 0x24040001, 0x2821,
+0xc004b9a, 0x27a60018, 0x24040001, 0x24050001,
+0x27b20020, 0xc004b9a, 0x2403021, 0x24040001,
+0x24050001, 0xc004b9a, 0x2403021, 0x24040001,
+0x24050004, 0x27b1001e, 0xc004b9a, 0x2203021,
+0x24040001, 0x24050004, 0xc004b9a, 0x2203021,
+0x24040001, 0x24050005, 0x27b00022, 0xc004b9a,
+0x2003021, 0x24040001, 0x24050005, 0xc004b9a,
+0x2003021, 0x24040001, 0x24050010, 0xc004b9a,
+0x27a60018, 0x24040001, 0x24050010, 0xc004b9a,
+0x27a60018, 0x24040001, 0x2405000a, 0xc004b9a,
+0x2403021, 0x24040001, 0x2405000a, 0xc004b9a,
+0x2403021, 0x24040001, 0x24050018, 0xc004b9a,
+0x2203021, 0x24040001, 0x24050018, 0xc004b9a,
+0x2203021, 0x24040001, 0x24050001, 0xc004b9a,
+0x27a60018, 0x24040001, 0x24050001, 0xc004b9a,
+0x27a60018, 0x97a20018, 0x30420004, 0x10400067,
+0x3c114000, 0x3c030002, 0x8c6387f0, 0x24020005,
+0x14620068, 0x24040001, 0x24050019, 0x27b0001c,
+0xc004b9a, 0x2003021, 0x24040001, 0x24050019,
+0xc004b9a, 0x2003021, 0x97a2001c, 0x30430700,
+0x24020400, 0x10620027, 0x28620401, 0x1040000e,
+0x24020200, 0x1062001f, 0x28620201, 0x10400005,
+0x24020100, 0x5062001e, 0x3c130001, 0x1000001e,
+0x3c020004, 0x24020300, 0x50620019, 0x3c130002,
+0x10000019, 0x3c020004, 0x24020600, 0x1062000d,
+0x28620601, 0x10400005, 0x24020500, 0x5062000b,
+0x3c130002, 0x10000010, 0x3c020004, 0x24020700,
+0x1462000d, 0x3c020004, 0x3c130004, 0x1000000a,
+0x3c150008, 0x10000006, 0x3c130004, 0x10000005,
+0x3c150008, 0x3c130001, 0x10000002, 0x3c150008,
+0x3c150010, 0x3c020004, 0x12620018, 0x3c028000,
+0x8f820054, 0x24100001, 0x3c010002, 0xac308670,
+0x3c010002, 0xac30866c, 0x3c010002, 0xac308678,
+0x3c010002, 0xac3086f0, 0x3c010002, 0xac2287ec,
+0x3c020001, 0x16620023, 0x2758825, 0x2021,
+0x2821, 0xc005400, 0x34068000, 0x3c010002,
+0xac3086ec, 0x1000001b, 0x0, 0x2221025,
+0x2b31825, 0x438825, 0x97a6001c, 0x3c020002,
+0x8c4287d8, 0x3c070002, 0x8ce7866c, 0x3c040002,
+0x248483a4, 0xafa20010, 0x97a2001e, 0x3c05000c,
+0x34a50323, 0x3c010002, 0xac2086ec, 0xc002d3b,
+0xafa20014, 0x10000007, 0x0, 0x3c110002,
+0x23e8821, 0x8e31a8b0, 0x3c027fff, 0x3442ffff,
+0x2228824, 0x3c020002, 0x8c42867c, 0x10400069,
+0x0, 0x3c020002, 0x8c4287d8, 0x10400002,
+0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0x8c22a8c4, 0x10400003,
+0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0x8c22a8cc, 0x10400003,
+0x3c020080, 0x1000004f, 0x2228825, 0x3c02ff7f,
+0x3442ffff, 0x1000004b, 0x2228824, 0x8fa8002c,
+0x82940, 0x3c030002, 0x651821, 0x8c63a8b8,
+0x3c024000, 0x621024, 0x14400008, 0x3c027fff,
+0x3442ffff, 0x628824, 0x3c010002, 0x250821,
+0xac31a8b0, 0x10000041, 0x2201021, 0x3c020002,
+0x8c42867c, 0x10400034, 0x3c11c00c, 0x3c020002,
+0x8c428708, 0x3c04c00c, 0x34842000, 0x3c030002,
+0x8c6387d8, 0x2102b, 0x21023, 0x441024,
+0x10600003, 0x518825, 0x3c022000, 0x2228825,
+0x3c020002, 0x451021, 0x8c42a8c4, 0x10400003,
+0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf,
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0x8c22a8cc, 0x10400003,
+0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
+0x3442ffff, 0x2228824, 0x3c020002, 0x8c4286f4,
+0x10400002, 0x3c020800, 0x2228825, 0x3c020002,
+0x8c4286f8, 0x10400002, 0x3c020400, 0x2228825,
+0x3c020002, 0x8c4286fc, 0x10400006, 0x3c020100,
+0x10000004, 0x2228825, 0x3c027fff, 0x3442ffff,
+0x628824, 0x8fa8002c, 0x81140, 0x3c010002,
+0x220821, 0xac31a8b0, 0x2201021, 0x8fbf0048,
+0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
+0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
+0x27bdffd0, 0xafb20028, 0x809021, 0xafbf002c,
+0xafb10024, 0xafb00020, 0x8f840200, 0x3c100002,
+0x8e10866c, 0x8f860220, 0x24020002, 0x1202005e,
+0x2e020003, 0x10400005, 0x24020001, 0x1202000a,
+0x121940, 0x10000114, 0x0, 0x24020004,
+0x120200c6, 0x24020008, 0x120200c5, 0x128940,
+0x1000010d, 0x0, 0x3c050002, 0xa32821,
+0x8ca5a8bc, 0x3c100002, 0x2038021, 0x8e10a8b4,
+0x3c024000, 0xa21024, 0x10400038, 0x3c020008,
+0x2021024, 0x10400020, 0x34840002, 0x3c020002,
+0x431021, 0x8c42a8c0, 0x10400005, 0x34840020,
+0x34840100, 0x3c020020, 0x10000006, 0x2028025,
+0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff,
+0x2028024, 0x121140, 0x3c010002, 0x220821,
+0x8c22a8c8, 0x10400005, 0x3c020001, 0xc23025,
+0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe,
+0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff,
+0x1000000f, 0x2028024, 0x2402fedf, 0x822024,
+0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f,
+0x3442ffff, 0x2028024, 0x3c010002, 0x230821,
+0xac20a8c0, 0x3c010002, 0x230821, 0xac20a8c8,
+0xaf840200, 0xaf860220, 0x8f820220, 0x34420002,
+0xaf820220, 0x1000000b, 0x121140, 0x3c02bfff,
+0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd,
+0x621824, 0xaf830200, 0xc00430b, 0x0,
+0x121140, 0x3c010002, 0x220821, 0xac30a8b4,
+0x100000bd, 0x0, 0x3c020002, 0x8c4287d8,
+0x1040006e, 0x24050004, 0x24040001, 0xc004b9a,
+0x27a60018, 0x24040001, 0x24050005, 0xc004b9a,
+0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040002,
+0x2484870c, 0x30630c00, 0x31a82, 0x30420c00,
+0x21282, 0xa7a2001a, 0x21080, 0x441021,
+0x431021, 0xa7a30018, 0x90480000, 0x24020001,
+0x3103ffff, 0x1062002b, 0x28620002, 0x10400005,
+0x0, 0x10600009, 0x0, 0x10000041,
+0x0, 0x10700014, 0x24020003, 0x1062002f,
+0x0, 0x1000003b, 0x0, 0x8f820200,
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+0x3c010002, 0xac20a8c4, 0x3c010002, 0xac20a8cc,
+0x10000035, 0x0, 0x8f820200, 0x34420100,
+0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820220, 0x24020100, 0x3c010002,
+0xac22a8c4, 0x3c010002, 0xac20a8cc, 0x10000026,
+0x0, 0x8f820200, 0x2403feff, 0x431024,
+0xaf820200, 0x8f820220, 0x3c030001, 0x431025,
+0xaf820220, 0x3c010002, 0xac20a8c4, 0x3c010002,
+0xac23a8cc, 0x10000018, 0x0, 0x8f820200,
+0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x24020100, 0x3c010002,
+0xac22a8c4, 0x3c010002, 0xac23a8cc, 0x1000000a,
+0x0, 0x3c040002, 0x248483c8, 0x97a6001a,
+0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
+0xc002d3b, 0xafa00014, 0x8f820200, 0x34420002,
+0xaf820200, 0x1000004c, 0x0, 0x128940,
+0x3c050002, 0xb12821, 0x8ca5a8b8, 0x3c100002,
+0x2118021, 0x8e10a8b0, 0x3c024000, 0xa21024,
+0x14400011, 0x0, 0x3c020002, 0x8c4287d8,
+0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002,
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00430b,
+0x2028024, 0x3c010002, 0x310821, 0xac30a8b0,
+0x10000031, 0x0, 0x3c020002, 0x8c4287d8,
+0x10400005, 0x3c020020, 0x3c020002, 0x8c428708,
+0x10400025, 0x3c020020, 0xa21024, 0x10400007,
+0x34840020, 0x24020100, 0x3c010002, 0x310821,
+0xac22a8c4, 0x10000006, 0x34840100, 0x3c010002,
+0x310821, 0xac20a8c4, 0x2402feff, 0x822024,
+0x3c020080, 0xa21024, 0x10400007, 0x121940,
+0x3c020001, 0x3c010002, 0x230821, 0xac22a8cc,
+0x10000008, 0xc23025, 0x121140, 0x3c010002,
+0x220821, 0xac20a8cc, 0x3c02fffe, 0x3442ffff,
+0xc23024, 0xaf840200, 0xaf860220, 0x8f820220,
+0x34420002, 0xaf820220, 0x121140, 0x3c010002,
+0x220821, 0xac30a8b0, 0x8fbf002c, 0x8fb20028,
+0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030,
+0x1821, 0x308400ff, 0x2405ffdf, 0x2406ffbf,
+0x641007, 0x30420001, 0x10400004, 0x0,
+0x8f820044, 0x10000003, 0x34420040, 0x8f820044,
+0x461024, 0xaf820044, 0x8f820044, 0x34420020,
+0xaf820044, 0x8f820044, 0x451024, 0xaf820044,
+0x24630001, 0x28620008, 0x5440ffee, 0x641007,
+0x3e00008, 0x0, 0x2c820008, 0x1040001b,
+0x0, 0x2405ffdf, 0x2406ffbf, 0x41880,
+0x3c020002, 0x2442871c, 0x621821, 0x24640004,
+0x90620000, 0x10400004, 0x0, 0x8f820044,
+0x10000003, 0x34420040, 0x8f820044, 0x461024,
+0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f820044, 0x451024, 0xaf820044, 0x24630001,
+0x64102b, 0x1440ffee, 0x0, 0x3e00008,
+0x0, 0x0 };
+static u_int32_t tigon2FwRodata[] = {
+0x24486561,
+0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72,
+0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66,
+0x77322f63, 0x6f6d6d6f, 0x6e2f6677, 0x6d61696e,
+0x2e632c76, 0x20312e31, 0x2e322e34, 0x35203139,
+0x39392f30, 0x312f3234, 0x2030303a, 0x31303a35,
+0x35207368, 0x75616e67, 0x20457870, 0x20240000,
+0x65767452, 0x6e674600, 0x51657674, 0x46000000,
+0x51657674, 0x505f4600, 0x4d657674, 0x526e6746,
+0x0, 0x4d516576, 0x74460000, 0x4d516576,
+0x505f4600, 0x5173436f, 0x6e495f46, 0x0,
+0x5173436f, 0x6e734600, 0x51725072, 0x6f644600,
+0x6261644d, 0x656d537a, 0x0, 0x2a50414e,
+0x49432a00, 0x66776d61, 0x696e2e63, 0x0,
+0x68775665, 0x72000000, 0x62616448, 0x77566572,
+0x0, 0x2a2a4441, 0x574e5f41, 0x0,
+0x74785278, 0x4266537a, 0x0, 0x62664174,
+0x6e4d726b, 0x0, 0x7265645a, 0x6f6e6531,
+0x0, 0x70636943, 0x6f6e6600, 0x67656e43,
+0x6f6e6600, 0x2a646d61, 0x5244666c, 0x0,
+0x72636246, 0x6c616773, 0x0, 0x62616452,
+0x78526362, 0x0, 0x676c6f62, 0x466c6773,
+0x0, 0x2b5f6469, 0x73705f6c, 0x6f6f7000,
+0x2b65765f, 0x68616e64, 0x6c657200, 0x63616e74,
+0x31446d61, 0x0, 0x2b715f64, 0x6d615f74,
+0x6f5f6e69, 0x635f636b, 0x73756d00, 0x2b685f73,
+0x656e645f, 0x64617461, 0x5f726561, 0x64795f63,
+0x6b73756d, 0x0, 0x2b685f64, 0x6d615f72,
+0x645f6173, 0x73697374, 0x5f636b73, 0x756d0000,
+0x74436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
+0x6f5f6e69, 0x63000000, 0x2b685f73, 0x656e645f,
+0x64617461, 0x5f726561, 0x64790000, 0x2b685f64,
+0x6d615f72, 0x645f6173, 0x73697374, 0x0,
+0x74436b73, 0x6d4f6666, 0x0, 0x2b685f73,
+0x656e645f, 0x62645f72, 0x65616479, 0x0,
+0x68737453, 0x52696e67, 0x0, 0x62616453,
+0x52696e67, 0x0, 0x6e696353, 0x52696e67,
+0x0, 0x77446d61, 0x416c6c41, 0x0,
+0x2b715f64, 0x6d615f74, 0x6f5f686f, 0x73745f63,
+0x6b73756d, 0x0, 0x2b685f6d, 0x61635f72,
+0x785f636f, 0x6d705f63, 0x6b73756d, 0x0,
+0x2b685f64, 0x6d615f77, 0x725f6173, 0x73697374,
+0x5f636b73, 0x756d0000, 0x72436b73, 0x6d4f6e00,
+0x2b715f64, 0x6d615f74, 0x6f5f686f, 0x73740000,
+0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d700000,
+0x2b685f64, 0x6d615f77, 0x725f6173, 0x73697374,
+0x0, 0x72436b73, 0x6d4f6666, 0x0,
+0x2b685f72, 0x6563765f, 0x62645f72, 0x65616479,
+0x0, 0x2b685f72, 0x6563765f, 0x6a756d62,
+0x6f5f6264, 0x5f726561, 0x64790000, 0x2b685f72,
+0x6563765f, 0x6d696e69, 0x5f62645f, 0x72656164,
+0x79000000, 0x2b6d685f, 0x636f6d6d, 0x616e6400,
+0x2b685f74, 0x696d6572, 0x0, 0x2b685f64,
+0x6f5f7570, 0x64617465, 0x5f74785f, 0x636f6e73,
+0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
+0x5f72785f, 0x70726f64, 0x0, 0x2b636b73,
+0x756d3136, 0x0, 0x2b706565, 0x6b5f6d61,
+0x635f7278, 0x5f776100, 0x2b706565, 0x6b5f6d61,
+0x635f7278, 0x0, 0x2b646571, 0x5f6d6163,
+0x5f727800, 0x2b685f6d, 0x61635f72, 0x785f6174,
+0x746e0000, 0x62616452, 0x6574537a, 0x0,
+0x72784264, 0x4266537a, 0x0, 0x2b6e756c,
+0x6c5f6861, 0x6e646c65, 0x72000000, 0x66774f70,
+0x4661696c, 0x0, 0x2b685f75, 0x70646174,
+0x655f6c65, 0x64340000, 0x2b685f75, 0x70646174,
+0x655f6c65, 0x64360000, 0x2b685f75, 0x70646174,
+0x655f6c65, 0x64320000, 0x696e7453, 0x74617465,
+0x0, 0x2a2a696e, 0x69744370, 0x0,
+0x23736372, 0x65616d00, 0x69537461, 0x636b4572,
+0x0, 0x70726f62, 0x654d656d, 0x0,
+0x2a2a4441, 0x574e5f42, 0x0, 0x2b73775f,
+0x646d615f, 0x61737369, 0x73745f70, 0x6c75735f,
+0x74696d65, 0x72000000, 0x2b267072, 0x656c6f61,
+0x645f7772, 0x5f646573, 0x63720000, 0x2b267072,
+0x656c6f61, 0x645f7264, 0x5f646573, 0x63720000,
+0x2b685f68, 0x665f7469, 0x6d657200, 0x24486561,
+0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72,
+0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66,
+0x77322f63, 0x6f6d6d6f, 0x6e2f7469, 0x6d65722e,
+0x632c7620, 0x312e312e, 0x322e3335, 0x20313939,
+0x392f3031, 0x2f323720, 0x31393a30, 0x393a3530,
+0x20686179, 0x65732045, 0x78702024, 0x0,
+0x65767452, 0x6e674600, 0x51657674, 0x46000000,
+0x51657674, 0x505f4600, 0x4d657674, 0x526e6746,
+0x0, 0x4d516576, 0x74460000, 0x4d516576,
+0x505f4600, 0x5173436f, 0x6e495f46, 0x0,
+0x5173436f, 0x6e734600, 0x51725072, 0x6f644600,
+0x2a50414e, 0x49432a00, 0x6d61632e, 0x68000000,
+0x74696d65, 0x722e6300, 0x542d446d, 0x61526432,
+0x0, 0x542d446d, 0x61526431, 0x0,
+0x542d446d, 0x61526442, 0x0, 0x542d446d,
+0x61577232, 0x0, 0x542d446d, 0x61577231,
+0x0, 0x542d446d, 0x61577242, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
+0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
+0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
+0x67204578, 0x70202400, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
+0x0, 0x3f636d64, 0x48737453, 0x0,
+0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
+0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
+0x0, 0x3f636d64, 0x45727200, 0x8b08,
+0x92e4, 0x92e4, 0x9264, 0x8ff4,
+0x92b8, 0x92e4, 0x8bf4, 0x8c64,
+0x8df8, 0x8ee0, 0x8ea8, 0x92e4,
+0x8cd4, 0x8fa0, 0x92e4, 0x8fb0,
+0x8c18, 0x8c88, 0x24486561, 0x6465723a,
+0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73,
+0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63,
+0x6f6d6d6f, 0x6e2f6d63, 0x6173742e, 0x632c7620,
+0x312e312e, 0x322e3820, 0x31393938, 0x2f31322f,
+0x30382030, 0x323a3336, 0x3a333620, 0x73687561,
+0x6e672045, 0x78702024, 0x0, 0x65767452,
+0x6e674600, 0x51657674, 0x46000000, 0x51657674,
+0x505f4600, 0x4d657674, 0x526e6746, 0x0,
+0x4d516576, 0x74460000, 0x4d516576, 0x505f4600,
+0x5173436f, 0x6e495f46, 0x0, 0x5173436f,
+0x6e734600, 0x51725072, 0x6f644600, 0x6164644d,
+0x63447570, 0x0, 0x6164644d, 0x6346756c,
+0x0, 0x64656c4d, 0x634e6f45, 0x0,
+0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563,
+0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e,
+0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f646d,
+0x612e632c, 0x7620312e, 0x312e322e, 0x32342031,
+0x3939382f, 0x31322f32, 0x31203030, 0x3a33333a,
+0x30392073, 0x6875616e, 0x67204578, 0x70202400,
+0x65767452, 0x6e674600, 0x51657674, 0x46000000,
+0x51657674, 0x505f4600, 0x4d657674, 0x526e6746,
+0x0, 0x4d516576, 0x74460000, 0x4d516576,
+0x505f4600, 0x5173436f, 0x6e495f46, 0x0,
+0x5173436f, 0x6e734600, 0x51725072, 0x6f644600,
+0x7377446d, 0x614f6666, 0x0, 0x31446d61,
+0x4f6e0000, 0x7377446d, 0x614f6e00, 0x2a50414e,
+0x49432a00, 0x646d612e, 0x63000000, 0x2372446d,
+0x6141544e, 0x0, 0x72446d61, 0x41544e30,
+0x0, 0x72446d61, 0x41544e31, 0x0,
+0x72446d61, 0x34476200, 0x2377446d, 0x6141544e,
+0x0, 0x77446d61, 0x41544e30, 0x0,
+0x77446d61, 0x41544e31, 0x0, 0x77446d61,
+0x34476200, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
+0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
+0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x24486561, 0x6465723a,
+0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73,
+0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63,
+0x6f6d6d6f, 0x6e2f6461, 0x74612e63, 0x2c762031,
+0x2e312e32, 0x2e313220, 0x31393939, 0x2f30312f,
+0x32302031, 0x393a3439, 0x3a353120, 0x73687561,
+0x6e672045, 0x78702024, 0x0, 0x46575f56,
+0x45525349, 0x4f4e3a20, 0x58585800, 0x46575f43,
+0x4f4d5049, 0x4c455f54, 0x494d453a, 0x20585858,
+0x0, 0x46575f43, 0x4f4d5049, 0x4c455f42,
+0x593a2058, 0x58580000, 0x46575f43, 0x4f4d5049,
+0x4c455f48, 0x4f53543a, 0x20585858, 0x0,
+0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
+0x4e3a2058, 0x58580000, 0x46575f43, 0x4f4d5049,
+0x4c45523a, 0x20585858, 0x0, 0x0,
+0x12041100, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
+0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
+0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
+0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
+0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
+0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x2a50414e, 0x49432a00,
+0x6d61632e, 0x68000000, 0x73656e64, 0x2e630000,
+0x69736e74, 0x54637055, 0x0, 0x24486561,
+0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72,
+0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66,
+0x77322f63, 0x6f6d6d6f, 0x6e2f7265, 0x63762e63,
+0x2c762031, 0x2e312e32, 0x2e353320, 0x31393939,
+0x2f30312f, 0x31362030, 0x323a3535, 0x3a343320,
+0x73687561, 0x6e672045, 0x78702024, 0x0,
+0x65767452, 0x6e674600, 0x51657674, 0x46000000,
+0x51657674, 0x505f4600, 0x4d657674, 0x526e6746,
+0x0, 0x4d516576, 0x74460000, 0x4d516576,
+0x505f4600, 0x5173436f, 0x6e495f46, 0x0,
+0x5173436f, 0x6e734600, 0x51725072, 0x6f644600,
+0x2a50414e, 0x49432a00, 0x6d61632e, 0x68000000,
+0x724d6163, 0x43686b30, 0x0, 0x72784672,
+0x6d324c67, 0x0, 0x72784e6f, 0x53744264,
+0x0, 0x72784e6f, 0x4d694264, 0x0,
+0x72784e6f, 0x4a6d4264, 0x0, 0x72656376,
+0x2e630000, 0x7278436b, 0x446d6146, 0x0,
+0x72785144, 0x6d457846, 0x0, 0x72785144,
+0x6d614600, 0x72785144, 0x4c426446, 0x0,
+0x72785144, 0x6d426446, 0x0, 0x72784372,
+0x63506164, 0x0, 0x72536d51, 0x446d6146,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
+0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
+0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
+0x70202400, 0x65767452, 0x6e674600, 0x51657674,
+0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+0x526e6746, 0x0, 0x4d516576, 0x74460000,
+0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+0x0, 0x5173436f, 0x6e734600, 0x51725072,
+0x6f644600, 0x2a50414e, 0x49432a00, 0x6d61632e,
+0x68000000, 0x6d616354, 0x68726573, 0x0,
+0x23744d61, 0x6341544e, 0x0, 0x23724d61,
+0x6341544e, 0x0, 0x72656d41, 0x73737274,
+0x0, 0x6d61632e, 0x63000000, 0x6c696e6b,
+0x444f574e, 0x0, 0x6c696e6b, 0x55500000,
+0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563,
+0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e,
+0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f636b,
+0x73756d2e, 0x632c7620, 0x312e312e, 0x322e3920,
+0x31393939, 0x2f30312f, 0x31342030, 0x303a3033,
+0x3a343820, 0x73687561, 0x6e672045, 0x78702024,
+0x0, 0x65767452, 0x6e674600, 0x51657674,
+0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+0x526e6746, 0x0, 0x4d516576, 0x74460000,
+0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+0x0, 0x5173436f, 0x6e734600, 0x51725072,
+0x6f644600, 0x2a50414e, 0x49432a00, 0x6d61632e,
+0x68000000, 0x2a50414e, 0x49432a00, 0x2e2e2f63,
+0x6f6d6d6f, 0x6e2f6d61, 0x632e6800, 0x2e2e2f2e,
+0x2e2f2e2e, 0x2f636f6d, 0x6d6f6e2f, 0x6c696e6b,
+0x2e630000, 0x50726f62, 0x65506879, 0x0,
+0x6c6e6b41, 0x53535254, 0x0, 0x6e6f4863,
+0x644c6b00, 0x11f8c, 0x1200c, 0x12040,
+0x1206c, 0x120e8, 0x12160, 0x121c8,
+0x12940, 0x12324, 0x1235c, 0x12374,
+0x123b8, 0x123e0, 0x12404, 0x1242c,
+0x12940, 0x12324, 0x124b8, 0x124d0,
+0x12500, 0x123e0, 0x12528, 0x12550,
+0x0, 0x12684, 0x126b4, 0x126d8,
+0x12940, 0x126fc, 0x127b8, 0x1284c,
+0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f63,
+0x6f6d6d6f, 0x6e2f6d61, 0x632e6800, 0x130e4,
+0x131b4, 0x1328c, 0x1335c, 0x133b8,
+0x13494, 0x134bc, 0x13598, 0x135c0,
+0x13768, 0x13790, 0x13938, 0x13b30,
+0x13dc8, 0x13cd8, 0x13dc8, 0x13df4,
+0x13960, 0x13b08, 0x7273745f, 0x676d6969,
+0x0, 0x13e88, 0x13ec4, 0x13fb0,
+0x14c04, 0x14c48, 0x14c60, 0x7365746c,
+0x6f6f7000, 0x2a50414e, 0x49432a00, 0x2e2e2f63,
+0x6f6d6d6f, 0x6e2f6d61, 0x632e6800, 0x15454,
+0x15494, 0x1552c, 0x15570, 0x155dc,
+0x1566c, 0x156a0, 0x1572c, 0x157d0,
+0x158a0, 0x158e0, 0x1596c, 0x15990,
+0x15aa8, 0x646f4261, 0x73655067, 0x0,
+0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f63,
+0x6f6d6d6f, 0x6e2f6d61, 0x632e6800, 0x73746d61,
+0x634c4e4b, 0x0, 0x6765746d, 0x636c6e6b,
+0x0, 0x167cc, 0x167cc, 0x1647c,
+0x164c8, 0x16514, 0x167cc, 0x7365746d,
+0x61636163, 0x74000000, 0x0 };
+static u_int32_t tigon2FwData[] = {
+0x1,
+0x1, 0x1, 0xc001fc, 0x3ffc,
+0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
+0x43205600, 0x0, 0x416c7465, 0x6f6e2041,
+0x63654e49, 0x43205600, 0x42424242, 0x1ffffc,
+0x1fff7c, 0x0, 0x0, 0x0,
+0x60cf00, 0x60, 0xcf000000, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x3,
+0x0, 0x1, 0x0, 0x0,
+0x0, 0x1, 0x0, 0x1,
+0x0, 0x0, 0x1, 0x1,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x1000000, 0x21000000, 0x12000140,
+0x0, 0x0, 0x20000000, 0x120000a0,
+0x0, 0x12000060, 0x12000180, 0x120001e0,
+0x0, 0x0, 0x0, 0x1,
+0x0, 0x0, 0x0, 0x0,
+0x2, 0x0, 0x0, 0x30001,
+0x1, 0x30201, 0x1010101, 0x1010100,
+0x10100, 0x1010001, 0x10001, 0x1000101,
+0x101, 0x0, 0x0 };
diff --git a/sys/pci/uhci_pci.c b/sys/pci/uhci_pci.c
new file mode 100644
index 0000000..db3d5c6
--- /dev/null
+++ b/sys/pci/uhci_pci.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@carlstedt.se) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Universal Host Controller Interface
+ *
+ * UHCI spec: http://www.intel.com/
+ */
+
+/* The low level controller code for UHCI has been split into
+ * PCI probes and UHCI specific code. This was done to facilitate the
+ * sharing of code between *BSD's
+ */
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+#if defined(__FreeBSD__)
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#endif
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dev/usb/uhcireg.h>
+#include <dev/usb/uhcivar.h>
+
+#define PCI_UHCI_VENDORID_INTEL 0x8086
+#define PCI_UHCI_VENDORID_VIA 0x1106
+
+#define PCI_UHCI_DEVICEID_PIIX3 0x70208086
+static const char *uhci_device_piix3 = "Intel 82371SB (PIIX3) USB controller";
+
+#define PCI_UHCI_DEVICEID_PIIX4 0x71128086
+#define PCI_UHCI_DEVICEID_PIIX4E 0x71128086 /* no separate stepping */
+static const char *uhci_device_piix4 = "Intel 82371AB/EB (PIIX4) USB controller";
+
+#define PCI_UHCI_DEVICEID_ICH 0x24128086
+static const char *uhci_device_ich = "Intel 82801AA (ICH) USB controller";
+
+#define PCI_UHCI_DEVICEID_ICH0 0x24228086
+static const char *uhci_device_ich0 = "Intel 82801AB (ICH0) USB controller";
+
+#define PCI_UHCI_DEVICEID_ICH2_A 0x24428086
+static const char *uhci_device_ich2_a = "Intel 82801BA/BAM (ICH2) USB controller USB-A";
+
+#define PCI_UHCI_DEVICEID_ICH2_B 0x24448086
+static const char *uhci_device_ich2_b = "Intel 82801BA/BAM (ICH2) USB controller USB-B";
+
+#define PCI_UHCI_DEVICEID_ICH3_A 0x24828086
+static const char *uhci_device_ich3_a = "Intel 82801CA/CAM (ICH3) USB controller USB-A";
+
+#define PCI_UHCI_DEVICEID_ICH3_B 0x24848086
+static const char *uhci_device_ich3_b = "Intel 82801CA/CAM (ICH3) USB controller USB-B";
+
+#define PCI_UHCI_DEVICEID_440MX 0x719a8086
+static const char *uhci_device_440mx = "Intel 82443MX USB controller";
+
+#define PCI_UHCI_DEVICEID_460GX 0x76028086
+static const char *uhci_device_460gx = "Intel 82372FB/82468GX USB controller";
+
+#define PCI_UHCI_DEVICEID_VT83C572 0x30381106
+static const char *uhci_device_vt83c572 = "VIA 83C572 USB controller";
+
+static const char *uhci_device_generic = "UHCI (generic) USB controller";
+
+#define PCI_UHCI_BASE_REG 0x20
+
+
+static int uhci_pci_attach(device_t self);
+static int uhci_pci_detach(device_t self);
+static int uhci_pci_suspend(device_t self);
+static int uhci_pci_resume(device_t self);
+
+
+static int
+uhci_pci_suspend(device_t self)
+{
+ uhci_softc_t *sc = device_get_softc(self);
+ int err;
+
+ err = bus_generic_suspend(self);
+ if (err)
+ return err;
+ uhci_power(PWR_SUSPEND, sc);
+
+ return 0;
+}
+
+static int
+uhci_pci_resume(device_t self)
+{
+ uhci_softc_t *sc = device_get_softc(self);
+
+ uhci_power(PWR_RESUME, sc);
+ bus_generic_resume(self);
+
+ return 0;
+}
+
+static const char *
+uhci_pci_match(device_t self)
+{
+ u_int32_t device_id = pci_get_devid(self);
+
+ if (device_id == PCI_UHCI_DEVICEID_PIIX3) {
+ return (uhci_device_piix3);
+ } else if (device_id == PCI_UHCI_DEVICEID_PIIX4) {
+ return (uhci_device_piix4);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH) {
+ return (uhci_device_ich);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH0) {
+ return (uhci_device_ich0);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH2_A) {
+ return (uhci_device_ich2_a);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH2_B) {
+ return (uhci_device_ich2_b);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH3_A) {
+ return (uhci_device_ich3_a);
+ } else if (device_id == PCI_UHCI_DEVICEID_ICH3_B) {
+ return (uhci_device_ich3_b);
+ } else if (device_id == PCI_UHCI_DEVICEID_440MX) {
+ return (uhci_device_440mx);
+ } else if (device_id == PCI_UHCI_DEVICEID_460GX) {
+ return (uhci_device_460gx);
+ } else if (device_id == PCI_UHCI_DEVICEID_VT83C572) {
+ return (uhci_device_vt83c572);
+ } else {
+ if (pci_get_class(self) == PCIC_SERIALBUS
+ && pci_get_subclass(self) == PCIS_SERIALBUS_USB
+ && pci_get_progif(self) == PCI_INTERFACE_UHCI) {
+ return (uhci_device_generic);
+ }
+ }
+
+ return NULL; /* dunno... */
+}
+
+static int
+uhci_pci_probe(device_t self)
+{
+ const char *desc = uhci_pci_match(self);
+
+ if (desc) {
+ device_set_desc(self, desc);
+ return 0;
+ } else {
+ return ENXIO;
+ }
+}
+
+static int
+uhci_pci_attach(device_t self)
+{
+ uhci_softc_t *sc = device_get_softc(self);
+ int rid;
+ int err;
+
+ rid = PCI_UHCI_BASE_REG;
+ sc->io_res = bus_alloc_resource(self, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->io_res) {
+ device_printf(self, "Could not map ports\n");
+ return ENXIO;
+ }
+ sc->iot = rman_get_bustag(sc->io_res);
+ sc->ioh = rman_get_bushandle(sc->io_res);
+
+ /* disable interrupts */
+ bus_space_write_2(sc->iot, sc->ioh, UHCI_INTR, 0);
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid,
+ 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(self, "Could not allocate irq\n");
+ uhci_pci_detach(self);
+ return ENXIO;
+ }
+ sc->sc_bus.bdev = device_add_child(self, "usb", -1);
+ if (!sc->sc_bus.bdev) {
+ device_printf(self, "Could not add USB device\n");
+ uhci_pci_detach(self);
+ return ENOMEM;
+ }
+ device_set_ivars(sc->sc_bus.bdev, sc);
+
+ switch (pci_get_devid(self)) {
+ case PCI_UHCI_DEVICEID_PIIX3:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_piix3);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_PIIX4:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_piix4);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH0:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich0);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH2_A:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich2_a);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH2_B:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich2_b);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH3_A:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich3_a);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_ICH3_B:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_ich3_b);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_440MX:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_440mx);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_460GX:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_460gx);
+ sprintf(sc->sc_vendor, "Intel");
+ break;
+ case PCI_UHCI_DEVICEID_VT83C572:
+ device_set_desc(sc->sc_bus.bdev, uhci_device_vt83c572);
+ sprintf(sc->sc_vendor, "VIA");
+ break;
+ default:
+ device_printf(self, "(New UHCI DeviceId=0x%08x)\n",
+ pci_get_devid(self));
+ device_set_desc(sc->sc_bus.bdev, uhci_device_generic);
+ sprintf(sc->sc_vendor, "(0x%08x)", pci_get_devid(self));
+ }
+
+ switch (pci_read_config(self, PCI_USBREV, 4) & PCI_USBREV_MASK) {
+ case PCI_USBREV_PRE_1_0:
+ sc->sc_bus.usbrev = USBREV_PRE_1_0;
+ break;
+ case PCI_USBREV_1_0:
+ sc->sc_bus.usbrev = USBREV_1_0;
+ break;
+ default:
+ sc->sc_bus.usbrev = USBREV_UNKNOWN;
+ break;
+ }
+
+ err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
+ (driver_intr_t *) uhci_intr, sc, &sc->ih);
+ if (err) {
+ device_printf(self, "Could not setup irq, %d\n", err);
+ sc->ih = NULL;
+ uhci_pci_detach(self);
+ return ENXIO;
+ }
+ /*
+ * Set the PIRQD enable bit and switch off all the others. We don't
+ * want legacy support to interfere with us XXX Does this also mean
+ * that the BIOS won't touch the keyboard anymore if it is connected
+ * to the ports of the root hub?
+ */
+#ifdef UHCI_DEBUG
+ if (pci_read_config(self, PCI_LEGSUP, 4) != PCI_LEGSUP_USBPIRQDEN)
+ device_printf(self, "LegSup = 0x%08x\n",
+ pci_read_config(self, PCI_LEGSUP, 4));
+#endif
+ pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 4);
+
+ err = uhci_init(sc);
+ if (!err)
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+
+ if (err) {
+ device_printf(self, "USB init failed\n");
+ uhci_pci_detach(self);
+ return EIO;
+ }
+ return 0; /* success */
+}
+
+int
+uhci_pci_detach(device_t self)
+{
+ uhci_softc_t *sc = device_get_softc(self);
+
+ /*
+ * XXX This function is not yet complete and should not be added
+ * method list.
+ */
+#if 0
+ if uhci_init
+ was successful
+ we should call something like uhci_deinit
+#endif
+
+ /*
+ * disable interrupts that might have been switched on in
+ * uhci_init.
+ */
+ if (sc->iot && sc->ioh)
+ bus_space_write_2(sc->iot, sc->ioh, UHCI_INTR, 0);
+
+ if (sc->irq_res && sc->ih) {
+ int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
+
+ if (err)
+ /* XXX or should we panic? */
+ device_printf(self, "Could not tear down irq, %d\n",
+ err);
+ sc->ih = NULL;
+ }
+ if (sc->sc_bus.bdev) {
+ device_delete_child(self, sc->sc_bus.bdev);
+ sc->sc_bus.bdev = NULL;
+ }
+ if (sc->irq_res) {
+ bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
+ sc->irq_res = NULL;
+ }
+ if (sc->io_res) {
+ bus_release_resource(self, SYS_RES_IOPORT, PCI_UHCI_BASE_REG,
+ sc->io_res);
+ sc->io_res = NULL;
+ sc->iot = 0;
+ sc->ioh = 0;
+ }
+ return 0;
+}
+
+
+static device_method_t uhci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uhci_pci_probe),
+ DEVMETHOD(device_attach, uhci_pci_attach),
+ DEVMETHOD(device_suspend, uhci_pci_suspend),
+ DEVMETHOD(device_resume, uhci_pci_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0}
+};
+
+static driver_t uhci_driver = {
+ "uhci",
+ uhci_methods,
+ sizeof(uhci_softc_t),
+};
+
+static devclass_t uhci_devclass;
+
+DRIVER_MODULE(uhci, pci, uhci_driver, uhci_devclass, 0, 0);
diff --git a/sys/pci/viapm.c b/sys/pci/viapm.c
new file mode 100644
index 0000000..d18f64d
--- /dev/null
+++ b/sys/pci/viapm.c
@@ -0,0 +1,924 @@
+/*-
+ * Copyright (c) 2001 Alcove - Nicolas Souchu
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/uio.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/clock.h> /* for DELAY */
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include <dev/smbus/smbconf.h>
+#include <dev/smbus/smbus.h>
+
+#include "iicbb_if.h"
+#include "smbus_if.h"
+
+#define VIAPM_DEBUG(x) if (viapm_debug) (x)
+
+#ifdef DEBUG
+static int viapm_debug = 1;
+#else
+static int viapm_debug = 0;
+#endif
+
+#define VIA_586B_PMU_ID 0x30401106
+#define VIA_596A_PMU_ID 0x30501106
+#define VIA_596B_PMU_ID 0x30511106
+#define VIA_686A_PMU_ID 0x30571106
+#define VIA_8233_PMU_ID 0x30741106
+
+#define VIAPM_INB(port) \
+ ((u_char)bus_space_read_1(viapm->st, viapm->sh, port))
+#define VIAPM_OUTB(port,val) \
+ (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)val))
+
+#define VIAPM_TYP_UNKNOWN 0
+#define VIAPM_TYP_586B_3040E 1
+#define VIAPM_TYP_586B_3040F 2
+#define VIAPM_TYP_596B 3
+#define VIAPM_TYP_686A 4
+#define VIAPM_TYP_8233 5
+
+struct viapm_softc {
+ int type;
+ u_int32_t base;
+ bus_space_tag_t st;
+ bus_space_handle_t sh;
+ int iorid;
+ int irqrid;
+ struct resource *iores;
+ struct resource *irqres;
+ void *irqih;
+
+ device_t iicbb;
+ device_t smbus;
+};
+
+static devclass_t viapm_devclass;
+static devclass_t viapropm_devclass;
+
+/*
+ * VT82C586B definitions
+ */
+
+#define VIAPM_586B_REVID 0x08
+
+#define VIAPM_586B_3040E_BASE 0x20
+#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */
+
+#define VIAPM_586B_3040F_BASE 0x48
+#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */
+
+#define VIAPM_586B_OEM_REV_E 0x00
+#define VIAPM_586B_OEM_REV_F 0x01
+#define VIAPM_586B_PROD_REV_A 0x10
+
+#define VIAPM_586B_BA_MASK 0x0000ff00
+
+#define GPIO_DIR 0x40
+#define GPIO_VAL 0x42
+#define EXTSMI_VAL 0x44
+
+#define VIAPM_SCL 0x02 /* GPIO1_VAL */
+#define VIAPM_SDA 0x04 /* GPIO2_VAL */
+
+/*
+ * VIAPRO common definitions
+ */
+
+#define VIAPM_PRO_BA_MASK 0x0000fff0
+#define VIAPM_PRO_SMBCTRL 0xd2
+#define VIAPM_PRO_REVID 0xd6
+
+/*
+ * VT82C686A definitions
+ */
+
+#define VIAPM_PRO_BASE 0x90
+
+#define SMBHST 0x0
+#define SMBHSL 0x1
+#define SMBHCTRL 0x2
+#define SMBHCMD 0x3
+#define SMBHADDR 0x4
+#define SMBHDATA0 0x5
+#define SMBHDATA1 0x6
+#define SMBHBLOCK 0x7
+
+#define SMBSST 0x1
+#define SMBSCTRL 0x8
+#define SMBSSDWCMD 0x9
+#define SMBSEVENT 0xa
+#define SMBSDATA 0xc
+
+#define SMBHST_RESERVED 0xef /* reserved bits */
+#define SMBHST_FAILED 0x10 /* failed bus transaction */
+#define SMBHST_COLLID 0x08 /* bus collision */
+#define SMBHST_ERROR 0x04 /* device error */
+#define SMBHST_INTR 0x02 /* command completed */
+#define SMBHST_BUSY 0x01 /* host busy */
+
+#define SMBHCTRL_START 0x40 /* start command */
+#define SMBHCTRL_PROTO 0x1c /* command protocol mask */
+#define SMBHCTRL_QUICK 0x00
+#define SMBHCTRL_SENDRECV 0x04
+#define SMBHCTRL_BYTE 0x08
+#define SMBHCTRL_WORD 0x0c
+#define SMBHCTRL_BLOCK 0x14
+#define SMBHCTRL_KILL 0x02 /* stop the current transaction */
+#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */
+
+#define SMBSCTRL_ENABLE 0x01 /* enable slave */
+
+
+/*
+ * VIA8233 definitions
+ */
+
+#define VIAPM_8233_BASE 0xD0
+
+static int
+viapm_586b_probe(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ u_int32_t l;
+ u_int16_t s;
+ u_int8_t c;
+
+ switch (pci_get_devid(dev)) {
+ case VIA_586B_PMU_ID:
+
+ bzero(viapm, sizeof(struct viapm_softc));
+
+ l = pci_read_config(dev, VIAPM_586B_REVID, 1);
+ switch (l) {
+ case VIAPM_586B_OEM_REV_E:
+ viapm->type = VIAPM_TYP_586B_3040E;
+ viapm->iorid = VIAPM_586B_3040E_BASE;
+
+ /* Activate IO block access */
+ s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
+ pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
+ break;
+
+ case VIAPM_586B_OEM_REV_F:
+ case VIAPM_586B_PROD_REV_A:
+ default:
+ viapm->type = VIAPM_TYP_586B_3040F;
+ viapm->iorid = VIAPM_586B_3040F_BASE;
+
+ /* Activate IO block access */
+ c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
+ pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
+ break;
+ }
+
+ viapm->base = pci_read_config(dev, viapm->iorid, 4) &
+ VIAPM_586B_BA_MASK;
+
+ /*
+ * We have to set the I/O resources by hand because it is
+ * described outside the viapmope of the traditional maps
+ */
+ if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
+ viapm->base, 256)) {
+ device_printf(dev, "could not set bus resource\n");
+ return ENXIO;
+ }
+ device_set_desc(dev, "VIA VT82C586B Power Management Unit");
+ return 0;
+
+ default:
+ break;
+ }
+
+ return ENXIO;
+}
+
+
+static int
+viapm_pro_probe(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+#ifdef VIAPM_BASE_ADDR
+ u_int32_t l;
+#endif
+ u_int32_t base_cfgreg;
+ char *desc;
+
+ switch (pci_get_devid(dev)) {
+ case VIA_596A_PMU_ID:
+ desc = "VIA VT82C596A Power Management Unit";
+ viapm->type = VIAPM_TYP_596B;
+ base_cfgreg = VIAPM_PRO_BASE;
+ goto viapro;
+
+ case VIA_596B_PMU_ID:
+ desc = "VIA VT82C596B Power Management Unit";
+ viapm->type = VIAPM_TYP_596B;
+ base_cfgreg = VIAPM_PRO_BASE;
+ goto viapro;
+
+ case VIA_686A_PMU_ID:
+ desc = "VIA VT82C686A Power Management Unit";
+ viapm->type = VIAPM_TYP_686A;
+ base_cfgreg = VIAPM_PRO_BASE;
+ goto viapro;
+
+ case VIA_8233_PMU_ID:
+ desc = "VIA VT8233 Power Management Unit";
+ viapm->type = VIAPM_TYP_UNKNOWN;
+ base_cfgreg = VIAPM_8233_BASE;
+ goto viapro;
+
+ viapro:
+
+#ifdef VIAPM_BASE_ADDR
+ /* force VIAPM I/O base address */
+
+ /* enable the SMBus controller function */
+ l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
+ pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
+
+ /* write the base address */
+ pci_write_config(dev, base_cfgreg,
+ VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
+#endif
+
+ viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
+
+ /*
+ * We have to set the I/O resources by hand because it is
+ * described outside the viapmope of the traditional maps
+ */
+ viapm->iorid = base_cfgreg;
+ if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
+ viapm->base, 16)) {
+ device_printf(dev, "could not set bus resource 0x%x\n",
+ viapm->base);
+ return ENXIO;
+ }
+
+ if (1 || bootverbose) {
+ device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
+ }
+
+ device_set_desc(dev, desc);
+ return 0;
+
+ default:
+ break;
+ }
+
+ return ENXIO;
+}
+
+static int
+viapm_pro_attach(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ u_int32_t l;
+
+ if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) {
+ device_printf(dev, "could not allocate bus space\n");
+ goto error;
+ }
+ viapm->st = rman_get_bustag(viapm->iores);
+ viapm->sh = rman_get_bushandle(viapm->iores);
+
+#if notyet
+ /* force irq 9 */
+ l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
+ pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
+
+ viapm->irqrid = 0;
+ if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
+ &viapm->irqrid, 9, 9, 1,
+ RF_SHAREABLE | RF_ACTIVE))) {
+ device_printf(dev, "could not allocate irq\n");
+ goto error;
+ }
+
+ if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
+ (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
+ device_printf(dev, "could not setup irq\n");
+ goto error;
+ }
+#endif
+
+ if (1 | bootverbose) {
+ l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
+ device_printf(dev, "SMBus revision code 0x%x\n", l);
+ }
+
+ viapm->smbus = device_add_child(dev, "smbus", -1);
+
+ /* probe and attach the smbus */
+ bus_generic_attach(dev);
+
+ /* disable slave function */
+ VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
+
+ /* enable the SMBus controller function */
+ l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
+ pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
+
+#if notyet
+ /* enable interrupts */
+ VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
+#endif
+
+ return 0;
+
+error:
+ if (viapm->iores)
+ bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
+#if notyet
+ if (viapm->irqres)
+ bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
+#endif
+
+ return ENXIO;
+}
+
+static int
+viapm_586b_attach(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+
+ if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) {
+ device_printf(dev, "could not allocate bus resource\n");
+ return ENXIO;
+ }
+ viapm->st = rman_get_bustag(viapm->iores);
+ viapm->sh = rman_get_bushandle(viapm->iores);
+
+ VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
+
+ /* add generic bit-banging code */
+ if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
+ goto error;
+
+ bus_generic_attach(dev);
+
+ return 0;
+
+error:
+ if (viapm->iores)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ viapm->iorid, viapm->iores);
+ return ENXIO;
+}
+
+static int
+viapm_586b_detach(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ bus_generic_detach(dev);
+ if (viapm->iicbb) {
+ device_delete_child(dev, viapm->iicbb);
+ }
+
+ if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
+ viapm->iorid, viapm->iores)))
+ return (error);
+
+ return 0;
+}
+
+static int
+viapm_pro_detach(device_t dev)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ bus_generic_detach(dev);
+ if (viapm->smbus) {
+ device_delete_child(dev, viapm->smbus);
+ }
+
+ if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
+ viapm->iorid, viapm->iores)))
+ return (error);
+
+#if notyet
+ if ((error = bus_release_resource(dev, SYS_RES_IRQ,
+ viapm->irqrid, viapm->irqres))
+ return (error);
+#endif
+
+ return 0;
+}
+
+static int
+viabb_callback(device_t dev, int index, caddr_t *data)
+{
+ return 0;
+}
+
+static void
+viabb_setscl(device_t dev, int ctrl)
+{
+ struct viapm_softc *viapm = device_get_softc(dev);
+ u_char val;
+
+ val = VIAPM_INB(GPIO_VAL);
+
+ if (ctrl)
+ val |= VIAPM_SCL;
+ else
+ val &= ~VIAPM_SCL;
+
+ VIAPM_OUTB(GPIO_VAL, val);
+
+ return;
+}
+
+static void
+viabb_setsda(device_t dev, int data)
+{
+ struct viapm_softc *viapm = device_get_softc(dev);
+ u_char val;
+
+ val = VIAPM_INB(GPIO_VAL);
+
+ if (data)
+ val |= VIAPM_SDA;
+ else
+ val &= ~VIAPM_SDA;
+
+ VIAPM_OUTB(GPIO_VAL, val);
+
+ return;
+}
+
+static int
+viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ /* reset bus */
+ viabb_setsda(dev, 1);
+ viabb_setscl(dev, 1);
+
+ return (IIC_ENOADDR);
+}
+
+static int
+viabb_getscl(device_t dev)
+{
+ struct viapm_softc *viapm = device_get_softc(dev);
+
+ return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
+}
+
+static int
+viabb_getsda(device_t dev)
+{
+ struct viapm_softc *viapm = device_get_softc(dev);
+
+ return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
+}
+
+static int
+viapm_abort(struct viapm_softc *viapm)
+{
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
+ DELAY(10);
+
+ return (0);
+}
+
+static int
+viapm_clear(struct viapm_softc *viapm)
+{
+ VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
+ SMBHST_ERROR | SMBHST_INTR);
+ DELAY(10);
+
+ return (0);
+}
+
+static int
+viapm_busy(struct viapm_softc *viapm)
+{
+ u_char sts;
+
+ sts = VIAPM_INB(SMBHST);
+
+ VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
+
+ return (sts & SMBHST_BUSY);
+}
+
+/*
+ * Poll the SMBus controller
+ */
+static int
+viapm_wait(struct viapm_softc *viapm)
+{
+ int count = 10000;
+ u_char sts = 0;
+ int error;
+
+ /* wait for command to complete and SMBus controller is idle */
+ while(count--) {
+ DELAY(10);
+ sts = VIAPM_INB(SMBHST);
+
+ /* check if the controller is processing a command */
+ if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
+ break;
+ }
+
+ VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
+
+ error = SMB_ENOERR;
+
+ if (!count)
+ error |= SMB_ETIMEOUT;
+
+ if (sts & SMBHST_FAILED)
+ error |= SMB_EABORT;
+
+ if (sts & SMBHST_COLLID)
+ error |= SMB_ENOACK;
+
+ if (sts & SMBHST_ERROR)
+ error |= SMB_EBUSERR;
+
+ if (error != SMB_ENOERR)
+ viapm_abort(viapm);
+
+ viapm_clear(viapm);
+
+ return (error);
+}
+
+static int
+viasmb_callback(device_t dev, int index, caddr_t *data)
+{
+ int error = 0;
+
+ switch (index) {
+ case SMB_REQUEST_BUS:
+ case SMB_RELEASE_BUS:
+ /* ok, bus allocation accepted */
+ break;
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+static int
+viasmb_quick(device_t dev, u_char slave, int how)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ switch (how) {
+ case SMB_QWRITE:
+ VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
+ VIAPM_OUTB(SMBHADDR, slave & ~LSB);
+ break;
+ case SMB_QREAD:
+ VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
+ VIAPM_OUTB(SMBHADDR, slave | LSB);
+ break;
+ default:
+ panic("%s: unknown QUICK command (%x)!", __FUNCTION__,
+ how);
+ }
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
+
+ error = viapm_wait(viapm);
+
+ return (error);
+}
+
+static int
+viasmb_sendb(device_t dev, u_char slave, char byte)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
+ VIAPM_OUTB(SMBHCMD, byte);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
+
+ error = viapm_wait(viapm);
+
+ VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
+
+ return (error);
+}
+
+static int
+viasmb_recvb(device_t dev, u_char slave, char *byte)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave | LSB);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
+
+ if ((error = viapm_wait(viapm)) == SMB_ENOERR)
+ *byte = VIAPM_INB(SMBHDATA0);
+
+ VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
+
+ return (error);
+}
+
+static int
+viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+ VIAPM_OUTB(SMBHDATA0, byte);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
+
+ error = viapm_wait(viapm);
+
+ VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
+
+ return (error);
+}
+
+static int
+viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave | LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
+
+ if ((error = viapm_wait(viapm)) == SMB_ENOERR)
+ *byte = VIAPM_INB(SMBHDATA0);
+
+ VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
+
+ return (error);
+}
+
+static int
+viasmb_writew(device_t dev, u_char slave, char cmd, short word)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+ VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
+ VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
+
+ error = viapm_wait(viapm);
+
+ VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
+
+ return (error);
+}
+
+static int
+viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ int error;
+ u_char high, low;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ VIAPM_OUTB(SMBHADDR, slave | LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
+
+ if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
+ low = VIAPM_INB(SMBHDATA0);
+ high = VIAPM_INB(SMBHDATA1);
+
+ *word = ((high & 0xff) << 8) | (low & 0xff);
+ }
+
+ VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
+
+ return (error);
+}
+
+static int
+viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ remain = count;
+ while (remain) {
+ len = min(remain, 32);
+
+ VIAPM_OUTB(SMBHADDR, slave & ~LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+ VIAPM_OUTB(SMBHDATA0, len);
+ i = VIAPM_INB(SMBHCTRL);
+
+ /* fill the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]);
+ DELAY(2);
+ }
+ VIAPM_OUTB(SMBHCMD, cmd);
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
+
+ if ((error = viapm_wait(viapm)) != SMB_ENOERR)
+ goto error;
+
+ remain -= len;
+ }
+
+error:
+ VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+
+}
+
+static int
+viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ viapm_clear(viapm);
+ if (viapm_busy(viapm))
+ return (EBUSY);
+
+ remain = count;
+ while (remain) {
+ VIAPM_OUTB(SMBHADDR, slave | LSB);
+ VIAPM_OUTB(SMBHCMD, cmd);
+ VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
+
+ if ((error = viapm_wait(viapm)) != SMB_ENOERR)
+ goto error;
+
+ len = VIAPM_INB(SMBHDATA0);
+ i = VIAPM_INB(SMBHCTRL); /* reset counter */
+
+ len = min(len, remain);
+
+ /* read the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ buf[count-remain+i] = VIAPM_INB(SMBHBLOCK);
+ DELAY(2);
+ }
+
+ remain -= len;
+ }
+error:
+ VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static device_method_t viapm_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, viapm_586b_probe),
+ DEVMETHOD(device_attach, viapm_586b_attach),
+ DEVMETHOD(device_detach, viapm_586b_detach),
+
+ /* iicbb interface */
+ DEVMETHOD(iicbb_callback, viabb_callback),
+ DEVMETHOD(iicbb_setscl, viabb_setscl),
+ DEVMETHOD(iicbb_setsda, viabb_setsda),
+ DEVMETHOD(iicbb_getscl, viabb_getscl),
+ DEVMETHOD(iicbb_getsda, viabb_getsda),
+ DEVMETHOD(iicbb_reset, viabb_reset),
+
+ { 0, 0 }
+};
+
+static driver_t viapm_driver = {
+ "viapm",
+ viapm_methods,
+ sizeof(struct viapm_softc),
+};
+
+static device_method_t viapropm_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, viapm_pro_probe),
+ DEVMETHOD(device_attach, viapm_pro_attach),
+ DEVMETHOD(device_detach, viapm_pro_detach),
+
+ /* smbus interface */
+ DEVMETHOD(smbus_callback, viasmb_callback),
+ DEVMETHOD(smbus_quick, viasmb_quick),
+ DEVMETHOD(smbus_sendb, viasmb_sendb),
+ DEVMETHOD(smbus_recvb, viasmb_recvb),
+ DEVMETHOD(smbus_writeb, viasmb_writeb),
+ DEVMETHOD(smbus_readb, viasmb_readb),
+ DEVMETHOD(smbus_writew, viasmb_writew),
+ DEVMETHOD(smbus_readw, viasmb_readw),
+ DEVMETHOD(smbus_bwrite, viasmb_bwrite),
+ DEVMETHOD(smbus_bread, viasmb_bread),
+
+ { 0, 0 }
+};
+
+static driver_t viapropm_driver = {
+ "viapropm",
+ viapropm_methods,
+ sizeof(struct viapm_softc),
+};
+
+DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
+DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
+
+MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
+MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(viapm, 1);
diff --git a/sys/pci/xmaciireg.h b/sys/pci/xmaciireg.h
new file mode 100644
index 0000000..137f47ee
--- /dev/null
+++ b/sys/pci/xmaciireg.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Registers and data structures for the XaQti Corporation XMAC II
+ * Gigabit Ethernet MAC. Datasheet is available from http://www.xaqti.com.
+ * The XMAC can be programmed for 16-bit or 32-bit register access modes.
+ * The SysKonnect gigabit ethernet adapters use 16-bit mode, so that's
+ * how the registers are laid out here.
+ */
+
+#define XM_DEVICEID 0x00E0AE20
+#define XM_XAQTI_OUI 0x00E0AE
+
+#define XM_XMAC_REV(x) (((x) & 0x000000E0) >> 5)
+
+#define XM_XMAC_REV_B2 0x0
+#define XM_XMAC_REV_C1 0x1
+
+#define XM_MMUCMD 0x0000
+#define XM_POFF 0x0008
+#define XM_BURST 0x000C
+#define XM_VLAN_TAGLEV1 0x0010
+#define XM_VLAN_TAGLEV2 0x0014
+#define XM_TXCMD 0x0020
+#define XM_TX_RETRYLIMIT 0x0024
+#define XM_TX_SLOTTIME 0x0028
+#define XM_TX_IPG 0x003C
+#define XM_RXCMD 0x0030
+#define XM_PHY_ADDR 0x0034
+#define XM_PHY_DATA 0x0038
+#define XM_GPIO 0x0040
+#define XM_IMR 0x0044
+#define XM_ISR 0x0048
+#define XM_HWCFG 0x004C
+#define XM_TX_LOWAT 0x0060
+#define XM_TX_HIWAT 0x0062
+#define XM_TX_REQTHRESH_LO 0x0064
+#define XM_TX_REQTHRESH_HI 0x0066
+#define XM_TX_REQTHRESH XM_TX_REQTHRESH_LO
+#define XM_PAUSEDST0 0x0068
+#define XM_PAUSEDST1 0x006A
+#define XM_PAUSEDST2 0x006C
+#define XM_CTLPARM_LO 0x0070
+#define XM_CTLPARM_HI 0x0072
+#define XM_CTLPARM XM_CTLPARM_LO
+#define XM_OPCODE_PAUSE_TIMER 0x0074
+#define XM_TXSTAT_LIFO 0x0078
+
+/*
+ * Perfect filter registers. The XMAC has a table of 16 perfect
+ * filter entries, spaced 8 bytes apart. This is in addition to
+ * the station address registers, which appear below.
+ */
+#define XM_RXFILT_BASE 0x0080
+#define XM_RXFILT_END 0x0107
+#define XM_RXFILT_MAX 16
+#define XM_RXFILT_ENTRY(ent) (XM_RXFILT_BASE + ((ent * 8)))
+
+/* Primary station address. */
+#define XM_PAR0 0x0108
+#define XM_PAR1 0x010A
+#define XM_PAR2 0x010C
+
+/* 64-bit multicast hash table registers */
+#define XM_MAR0 0x0110
+#define XM_MAR1 0x0112
+#define XM_MAR2 0x0114
+#define XM_MAR3 0x0116
+#define XM_RX_LOWAT 0x0118
+#define XM_RX_HIWAT 0x011A
+#define XM_RX_REQTHRESH_LO 0x011C
+#define XM_RX_REQTHRESH_HI 0x011E
+#define XM_RX_REQTHRESH XM_RX_REQTHRESH_LO
+#define XM_DEVID_LO 0x0120
+#define XM_DEVID_HI 0x0122
+#define XM_DEVID XM_DEVID_LO
+#define XM_MODE_LO 0x0124
+#define XM_MODE_HI 0x0126
+#define XM_MODE XM_MODE_LO
+#define XM_LASTSRC0 0x0128
+#define XM_LASTSRC1 0x012A
+#define XM_LASTSRC2 0x012C
+#define XM_TSTAMP_READ 0x0130
+#define XM_TSTAMP_LOAD 0x0134
+#define XM_STATS_CMD 0x0200
+#define XM_RXCNT_EVENT_LO 0x0204
+#define XM_RXCNT_EVENT_HI 0x0206
+#define XM_RXCNT_EVENT XM_RXCNT_EVENT_LO
+#define XM_TXCNT_EVENT_LO 0x0208
+#define XM_TXCNT_EVENT_HI 0x020A
+#define XM_TXCNT_EVENT XM_TXCNT_EVENT_LO
+#define XM_RXCNT_EVMASK_LO 0x020C
+#define XM_RXCNT_EVMASK_HI 0x020E
+#define XM_RXCNT_EVMASK XM_RXCNT_EVMASK_LO
+#define XM_TXCNT_EVMASK_LO 0x0210
+#define XM_TXCNT_EVMASK_HI 0x0212
+#define XM_TXCNT_EVMASK XM_TXCNT_EVMASK_LO
+
+/* Statistics command register */
+#define XM_STATCMD_CLR_TX 0x0001
+#define XM_STATCMD_CLR_RX 0x0002
+#define XM_STATCMD_COPY_TX 0x0004
+#define XM_STATCMD_COPY_RX 0x0008
+#define XM_STATCMD_SNAP_TX 0x0010
+#define XM_STATCMD_SNAP_RX 0x0020
+
+/* TX statistics registers */
+#define XM_TXSTATS_PKTSOK 0x280
+#define XM_TXSTATS_BYTESOK_HI 0x284
+#define XM_TXSTATS_BYTESOK_LO 0x288
+#define XM_TXSTATS_BCASTSOK 0x28C
+#define XM_TXSTATS_MCASTSOK 0x290
+#define XM_TXSTATS_UCASTSOK 0x294
+#define XM_TXSTATS_GIANTS 0x298
+#define XM_TXSTATS_BURSTCNT 0x29C
+#define XM_TXSTATS_PAUSEPKTS 0x2A0
+#define XM_TXSTATS_MACCTLPKTS 0x2A4
+#define XM_TXSTATS_SINGLECOLS 0x2A8
+#define XM_TXSTATS_MULTICOLS 0x2AC
+#define XM_TXSTATS_EXCESSCOLS 0x2B0
+#define XM_TXSTATS_LATECOLS 0x2B4
+#define XM_TXSTATS_DEFER 0x2B8
+#define XM_TXSTATS_EXCESSDEFER 0x2BC
+#define XM_TXSTATS_UNDERRUN 0x2C0
+#define XM_TXSTATS_CARRIERSENSE 0x2C4
+#define XM_TXSTATS_UTILIZATION 0x2C8
+#define XM_TXSTATS_64 0x2D0
+#define XM_TXSTATS_65_127 0x2D4
+#define XM_TXSTATS_128_255 0x2D8
+#define XM_TXSTATS_256_511 0x2DC
+#define XM_TXSTATS_512_1023 0x2E0
+#define XM_TXSTATS_1024_MAX 0x2E4
+
+/* RX statistics registers */
+#define XM_RXSTATS_PKTSOK 0x300
+#define XM_RXSTATS_BYTESOK_HI 0x304
+#define XM_RXSTATS_BYTESOK_LO 0x308
+#define XM_RXSTATS_BCASTSOK 0x30C
+#define XM_RXSTATS_MCASTSOK 0x310
+#define XM_RXSTATS_UCASTSOK 0x314
+#define XM_RXSTATS_PAUSEPKTS 0x318
+#define XM_RXSTATS_MACCTLPKTS 0x31C
+#define XM_RXSTATS_BADPAUSEPKTS 0x320
+#define XM_RXSTATS_BADMACCTLPKTS 0x324
+#define XM_RXSTATS_BURSTCNT 0x328
+#define XM_RXSTATS_MISSEDPKTS 0x32C
+#define XM_RXSTATS_FRAMEERRS 0x330
+#define XM_RXSTATS_OVERRUN 0x334
+#define XM_RXSTATS_JABBER 0x338
+#define XM_RXSTATS_CARRLOSS 0x33C
+#define XM_RXSTATS_INRNGLENERR 0x340
+#define XM_RXSTATS_SYMERR 0x344
+#define XM_RXSTATS_SHORTEVENT 0x348
+#define XM_RXSTATS_RUNTS 0x34C
+#define XM_RXSTATS_GIANTS 0x350
+#define XM_RXSTATS_CRCERRS 0x354
+#define XM_RXSTATS_CEXTERRS 0x35C
+#define XM_RXSTATS_UTILIZATION 0x360
+#define XM_RXSTATS_64 0x368
+#define XM_RXSTATS_65_127 0x36C
+#define XM_RXSTATS_128_255 0x370
+#define XM_RXSTATS_256_511 0x374
+#define XM_RXSTATS_512_1023 0x378
+#define XM_RXSTATS_1024_MAX 0x37C
+
+#define XM_MMUCMD_TX_ENB 0x0001
+#define XM_MMUCMD_RX_ENB 0x0002
+#define XM_MMUCMD_GMIILOOP 0x0004
+#define XM_MMUCMD_RATECTL 0x0008
+#define XM_MMUCMD_GMIIFDX 0x0010
+#define XM_MMUCMD_NO_MGMT_PRMB 0x0020
+#define XM_MMUCMD_SIMCOL 0x0040
+#define XM_MMUCMD_FORCETX 0x0080
+#define XM_MMUCMD_LOOPENB 0x0200
+#define XM_MMUCMD_IGNPAUSE 0x0400
+#define XM_MMUCMD_PHYBUSY 0x0800
+#define XM_MMUCMD_PHYDATARDY 0x1000
+
+#define XM_TXCMD_AUTOPAD 0x0001
+#define XM_TXCMD_NOCRC 0x0002
+#define XM_TXCMD_NOPREAMBLE 0x0004
+#define XM_TXCMD_NOGIGAMODE 0x0008
+#define XM_TXCMD_SAMPLELINE 0x0010
+#define XM_TXCMD_ENCBYPASS 0x0020
+#define XM_TXCMD_XMITBK2BK 0x0040
+#define XM_TXCMD_FAIRSHARE 0x0080
+
+#define XM_RXCMD_DISABLE_CEXT 0x0001
+#define XM_RXCMD_STRIPPAD 0x0002
+#define XM_RXCMD_SAMPLELINE 0x0004
+#define XM_RXCMD_SELFRX 0x0008
+#define XM_RXCMD_STRIPFCS 0x0010
+#define XM_RXCMD_TRANSPARENT 0x0020
+#define XM_RXCMD_IPGCAPTURE 0x0040
+#define XM_RXCMD_BIGPKTOK 0x0080
+#define XM_RXCMD_LENERROK 0x0100
+
+#define XM_GPIO_GP0_SET 0x0001
+#define XM_GPIO_RESETSTATS 0x0004
+#define XM_GPIO_RESETMAC 0x0008
+#define XM_GPIO_FORCEINT 0x0020
+#define XM_GPIO_ANEGINPROG 0x0040
+
+#define XM_IMR_RX_EOF 0x0001
+#define XM_IMR_TX_EOF 0x0002
+#define XM_IMR_TX_UNDERRUN 0x0004
+#define XM_IMR_RX_OVERRUN 0x0008
+#define XM_IMR_TX_STATS_OFLOW 0x0010
+#define XM_IMR_RX_STATS_OFLOW 0x0020
+#define XM_IMR_TSTAMP_OFLOW 0x0040
+#define XM_IMR_AUTONEG_DONE 0x0080
+#define XM_IMR_NEXTPAGE_RDY 0x0100
+#define XM_IMR_PAGE_RECEIVED 0x0200
+#define XM_IMR_LP_REQCFG 0x0400
+#define XM_IMR_GP0_SET 0x0800
+#define XM_IMR_FORCEINTR 0x1000
+#define XM_IMR_TX_ABORT 0x2000
+#define XM_IMR_LINKEVENT 0x4000
+
+#define XM_INTRS \
+ (~(XM_IMR_GP0_SET|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN))
+
+#define XM_ISR_RX_EOF 0x0001
+#define XM_ISR_TX_EOF 0x0002
+#define XM_ISR_TX_UNDERRUN 0x0004
+#define XM_ISR_RX_OVERRUN 0x0008
+#define XM_ISR_TX_STATS_OFLOW 0x0010
+#define XM_ISR_RX_STATS_OFLOW 0x0020
+#define XM_ISR_TSTAMP_OFLOW 0x0040
+#define XM_ISR_AUTONEG_DONE 0x0080
+#define XM_ISR_NEXTPAGE_RDY 0x0100
+#define XM_ISR_PAGE_RECEIVED 0x0200
+#define XM_ISR_LP_REQCFG 0x0400
+#define XM_ISR_GP0_SET 0x0800
+#define XM_ISR_FORCEINTR 0x1000
+#define XM_ISR_TX_ABORT 0x2000
+#define XM_ISR_LINKEVENT 0x4000
+
+#define XM_HWCFG_GENEOP 0x0008
+#define XM_HWCFG_SIGSTATCKH 0x0004
+#define XM_HWCFG_GMIIMODE 0x0001
+
+#define XM_MODE_FLUSH_RXFIFO 0x00000001
+#define XM_MODE_FLUSH_TXFIFO 0x00000002
+#define XM_MODE_BIGENDIAN 0x00000004
+#define XM_MODE_RX_PROMISC 0x00000008
+#define XM_MODE_RX_NOBROAD 0x00000010
+#define XM_MODE_RX_NOMULTI 0x00000020
+#define XM_MODE_RX_NOUNI 0x00000040
+#define XM_MODE_RX_BADFRAMES 0x00000080
+#define XM_MODE_RX_CRCERRS 0x00000100
+#define XM_MODE_RX_GIANTS 0x00000200
+#define XM_MODE_RX_INRANGELEN 0x00000400
+#define XM_MODE_RX_RUNTS 0x00000800
+#define XM_MODE_RX_MACCTL 0x00001000
+#define XM_MODE_RX_USE_PERFECT 0x00002000
+#define XM_MODE_RX_USE_STATION 0x00004000
+#define XM_MODE_RX_USE_HASH 0x00008000
+#define XM_MODE_RX_ADDRPAIR 0x00010000
+#define XM_MODE_PAUSEONHI 0x00020000
+#define XM_MODE_PAUSEONLO 0x00040000
+#define XM_MODE_TIMESTAMP 0x00080000
+#define XM_MODE_SENDPAUSE 0x00100000
+#define XM_MODE_SENDCONTINUOUS 0x00200000
+#define XM_MODE_LE_STATUSWORD 0x00400000
+#define XM_MODE_AUTOFIFOPAUSE 0x00800000
+#define XM_MODE_EXPAUSEGEN 0x02000000
+#define XM_MODE_RX_INVERSE 0x04000000
+
+#define XM_RXSTAT_MACCTL 0x00000001
+#define XM_RXSTAT_ERRFRAME 0x00000002
+#define XM_RXSTAT_CRCERR 0x00000004
+#define XM_RXSTAT_GIANT 0x00000008
+#define XM_RXSTAT_RUNT 0x00000010
+#define XM_RXSTAT_FRAMEERR 0x00000020
+#define XM_RXSTAT_INRANGEERR 0x00000040
+#define XM_RXSTAT_CARRIERERR 0x00000080
+#define XM_RXSTAT_COLLERR 0x00000100
+#define XM_RXSTAT_802_3 0x00000200
+#define XM_RXSTAT_CARREXTERR 0x00000400
+#define XM_RXSTAT_BURSTMODE 0x00000800
+#define XM_RXSTAT_UNICAST 0x00002000
+#define XM_RXSTAT_MULTICAST 0x00004000
+#define XM_RXSTAT_BROADCAST 0x00008000
+#define XM_RXSTAT_VLAN_LEV1 0x00010000
+#define XM_RXSTAT_VLAN_LEV2 0x00020000
+#define XM_RXSTAT_LEN 0xFFFC0000
+
+/*
+ * XMAC PHY registers, indirectly accessed through
+ * XM_PHY_ADDR and XM_PHY_REG.
+ */
+
+#define XM_PHY_BMCR 0x0000 /* control */
+#define XM_PHY_BMSR 0x0001 /* status */
+#define XM_PHY_VENID 0x0002 /* vendor id */
+#define XM_PHY_DEVID 0x0003 /* device id */
+#define XM_PHY_ANAR 0x0004 /* autoneg advertisenemt */
+#define XM_PHY_LPAR 0x0005 /* link partner ability */
+#define XM_PHY_ANEXP 0x0006 /* autoneg expansion */
+#define XM_PHY_NEXTP 0x0007 /* nextpage */
+#define XM_PHY_LPNEXTP 0x0008 /* link partner's nextpage */
+#define XM_PHY_EXTSTS 0x000F /* extented status */
+#define XM_PHY_RESAB 0x0010 /* resolved ability */
+
+#define XM_BMCR_DUPLEX 0x0100
+#define XM_BMCR_RENEGOTIATE 0x0200
+#define XM_BMCR_AUTONEGENBL 0x1000
+#define XM_BMCR_LOOPBACK 0x4000
+#define XM_BMCR_RESET 0x8000
+
+#define XM_BMSR_EXTCAP 0x0001
+#define XM_BMSR_LINKSTAT 0x0004
+#define XM_BMSR_AUTONEGABLE 0x0008
+#define XM_BMSR_REMFAULT 0x0010
+#define XM_BMSR_AUTONEGDONE 0x0020
+#define XM_BMSR_EXTSTAT 0x0100
+
+#define XM_VENID_XAQTI 0xD14C
+#define XM_DEVID_XMAC 0x0002
+
+#define XM_ANAR_FULLDUPLEX 0x0020
+#define XM_ANAR_HALFDUPLEX 0x0040
+#define XM_ANAR_PAUSEBITS 0x0180
+#define XM_ANAR_REMFAULTBITS 0x1800
+#define XM_ANAR_ACK 0x4000
+#define XM_ANAR_NEXTPAGE 0x8000
+
+#define XM_LPAR_FULLDUPLEX 0x0020
+#define XM_LPAR_HALFDUPLEX 0x0040
+#define XM_LPAR_PAUSEBITS 0x0180
+#define XM_LPAR_REMFAULTBITS 0x1800
+#define XM_LPAR_ACK 0x4000
+#define XM_LPAR_NEXTPAGE 0x8000
+
+#define XM_PAUSE_NOPAUSE 0x0000
+#define XM_PAUSE_SYMPAUSE 0x0080
+#define XM_PAUSE_ASYMPAUSE 0x0100
+#define XM_PAUSE_BOTH 0x0180
+
+#define XM_REMFAULT_LINKOK 0x0000
+#define XM_REMFAULT_LINKFAIL 0x0800
+#define XM_REMFAULT_OFFLINE 0x1000
+#define XM_REMFAULT_ANEGERR 0x1800
+
+#define XM_ANEXP_GOTPAGE 0x0002
+#define XM_ANEXP_NEXTPAGE_SELF 0x0004
+#define XM_ANEXP_NEXTPAGE_LP 0x0008
+
+#define XM_NEXTP_MESSAGE 0x07FF
+#define XM_NEXTP_TOGGLE 0x0800
+#define XM_NEXTP_ACK2 0x1000
+#define XM_NEXTP_MPAGE 0x2000
+#define XM_NEXTP_ACK1 0x4000
+#define XM_NEXTP_NPAGE 0x8000
+
+#define XM_LPNEXTP_MESSAGE 0x07FF
+#define XM_LPNEXTP_TOGGLE 0x0800
+#define XM_LPNEXTP_ACK2 0x1000
+#define XM_LPNEXTP_MPAGE 0x2000
+#define XM_LPNEXTP_ACK1 0x4000
+#define XM_LPNEXTP_NPAGE 0x8000
+
+#define XM_EXTSTS_HALFDUPLEX 0x4000
+#define XM_EXTSTS_FULLDUPLEX 0x8000
+
+#define XM_RESAB_PAUSEMISMATCH 0x0008
+#define XM_RESAB_ABLMISMATCH 0x0010
+#define XM_RESAB_FDMODESEL 0x0020
+#define XM_RESAB_HDMODESEL 0x0040
+#define XM_RESAB_PAUSEBITS 0x0180
diff --git a/sys/pci/xrpu.c b/sys/pci/xrpu.c
new file mode 100644
index 0000000..dc21896
--- /dev/null
+++ b/sys/pci/xrpu.c
@@ -0,0 +1,271 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * A very simple device driver for PCI cards based on Xilinx 6200 series
+ * FPGA/RPU devices. Current Functionality is to allow you to open and
+ * mmap the entire thing into your program.
+ *
+ * Hardware currently supported:
+ * www.vcc.com HotWorks 1 6216 based card.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/timetc.h>
+#include <sys/timepps.h>
+#include <sys/xrpuio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#include "pci_if.h"
+
+/*
+ * Device driver initialization stuff
+ */
+
+static d_open_t xrpu_open;
+static d_close_t xrpu_close;
+static d_ioctl_t xrpu_ioctl;
+static d_mmap_t xrpu_mmap;
+
+#define CDEV_MAJOR 100
+static struct cdevsw xrpu_cdevsw = {
+ /* open */ xrpu_open,
+ /* close */ xrpu_close,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ xrpu_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ xrpu_mmap,
+ /* strategy */ nostrategy,
+ /* name */ "xrpu",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+};
+
+static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
+
+static devclass_t xrpu_devclass;
+
+#define dev2unit(devt) (minor(devt) & 0xff)
+#define dev2pps(devt) ((minor(devt) >> 16)-1)
+
+struct softc {
+ enum { NORMAL, TIMECOUNTER } mode;
+ vm_offset_t virbase, physbase;
+ u_int *virbase62;
+ struct timecounter tc;
+ u_int *trigger, *latch, dummy;
+ struct pps_state pps[XRPU_MAX_PPS];
+ u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
+};
+
+static unsigned
+xrpu_get_timecount(struct timecounter *tc)
+{
+ struct softc *sc = tc->tc_priv;
+
+ sc->dummy += *sc->trigger;
+ return (*sc->latch & tc->tc_counter_mask);
+}
+
+static void
+xrpu_poll_pps(struct timecounter *tc)
+{
+ struct softc *sc = tc->tc_priv;
+ int i, j;
+ unsigned count1, ppscount;
+
+ for (i = 0; i < XRPU_MAX_PPS; i++) {
+ if (sc->assert[i]) {
+ pps_capture(&sc->pps[i]);
+ ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
+ j = 0;
+ do {
+ count1 = ppscount;
+ ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
+ } while (ppscount != count1 && ++j < 5);
+ sc->pps[i].capcount = ppscount;
+ pps_event(&sc->pps[i], PPS_CAPTUREASSERT);
+ }
+ if (sc->clear[i]) {
+ pps_capture(&sc->pps[i]);
+ j = 0;
+ ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
+ do {
+ count1 = ppscount;
+ ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
+ } while (ppscount != count1 && ++j < 5);
+ sc->pps[i].capcount = ppscount;
+ pps_event(&sc->pps[i], PPS_CAPTURECLEAR);
+ }
+ }
+}
+
+static int
+xrpu_open(dev_t dev, int flag, int mode, struct thread *td)
+{
+ struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
+
+ if (!sc)
+ return (ENXIO);
+ dev->si_drv1 = sc;
+ return (0);
+}
+
+static int
+xrpu_close(dev_t dev, int flag, int mode, struct thread *td)
+{
+ return (0);
+}
+
+static int
+xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot)
+{
+ struct softc *sc = dev->si_drv1;
+ if (offset >= 0x1000000)
+ return (-1);
+ return (i386_btop(sc->physbase + offset));
+}
+
+static int
+xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
+{
+ struct softc *sc = dev->si_drv1;
+ int i, error;
+
+ if (sc->mode == TIMECOUNTER) {
+ i = dev2pps(dev);
+ if (i < 0 || i >= XRPU_MAX_PPS)
+ return ENODEV;
+ error = pps_ioctl(cmd, arg, &sc->pps[i]);
+ return (error);
+ }
+
+ if (cmd == XRPU_IOC_TIMECOUNTING) {
+ struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
+
+ /* Name SHALL be zero terminated */
+ xt->xt_name[sizeof xt->xt_name - 1] = '\0';
+ i = strlen(xt->xt_name);
+ sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
+ strcpy(sc->tc.tc_name, xt->xt_name);
+ sc->tc.tc_frequency = xt->xt_frequency;
+ sc->tc.tc_get_timecount = xrpu_get_timecount;
+ sc->tc.tc_poll_pps = xrpu_poll_pps;
+ sc->tc.tc_priv = sc;
+ sc->tc.tc_counter_mask = xt->xt_mask;
+ sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
+ sc->latch = sc->virbase62 + xt->xt_addr_latch;
+
+ for (i = 0; i < XRPU_MAX_PPS; i++) {
+ if (xt->xt_pps[i].xt_addr_assert == 0
+ && xt->xt_pps[i].xt_addr_clear == 0)
+ continue;
+ make_dev(&xrpu_cdevsw, (i+1)<<16,
+ UID_ROOT, GID_WHEEL, 0600, "xpps%d", i);
+ sc->pps[i].ppscap = 0;
+ if (xt->xt_pps[i].xt_addr_assert) {
+ sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
+ sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
+ }
+ if (xt->xt_pps[i].xt_addr_clear) {
+ sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
+ sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
+ }
+ pps_init(&sc->pps[i]);
+ }
+ sc->mode = TIMECOUNTER;
+ tc_init(&sc->tc);
+ return (0);
+ }
+ error = ENOTTY;
+ return (error);
+}
+
+/*
+ * PCI initialization stuff
+ */
+
+static int
+xrpu_probe(device_t self)
+{
+ char *desc;
+
+ desc = NULL;
+ switch (pci_get_devid(self)) {
+ case 0x6216133e:
+ desc = "VCC Hotworks-I xc6216";
+ break;
+ }
+ if (desc == NULL)
+ return ENXIO;
+
+ device_set_desc(self, desc);
+ return 0;
+}
+
+static int
+xrpu_attach(device_t self)
+{
+ struct softc *sc;
+ struct resource *res;
+ int rid, unit;
+
+ unit = device_get_unit(self);
+ sc = device_get_softc(self);
+ sc->mode = NORMAL;
+ rid = PCIR_MAPS;
+ res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res == NULL) {
+ device_printf(self, "Could not map memory\n");
+ return ENXIO;
+ }
+ sc->virbase = (vm_offset_t)rman_get_virtual(res);
+ sc->physbase = rman_get_start(res);
+ sc->virbase62 = (u_int *)(sc->virbase + 0x800000);
+
+ if (bootverbose)
+ printf("Mapped physbase %#lx to virbase %#lx\n",
+ (u_long)sc->physbase, (u_long)sc->virbase);
+
+ make_dev(&xrpu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
+ return 0;
+}
+
+static device_method_t xrpu_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, xrpu_probe),
+ DEVMETHOD(device_attach, xrpu_attach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ {0, 0}
+};
+
+static driver_t xrpu_driver = {
+ "xrpu",
+ xrpu_methods,
+ sizeof(struct softc)
+};
+
+
+DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);
OpenPOWER on IntegriCloud