summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2006-11-17 18:58:32 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2006-11-17 18:58:32 +0000
commit4ac24938b682bf359920d8b998be6869a3266f13 (patch)
tree65a073f4d4beed3082e5d754a45f7be0dcf7a05e /sys/dev/ic
parentd104bc154dd6edf58570f71b885abd39899986c7 (diff)
This is a very initial import for a driver which supports the IEEE 802.11
Broadcom BCM43xx chipset. Device attaches, but has no further functionality yet. The work has been done by Jon Simola <jsimola@gmail.com>, based on the existing bce(4) code. He will continue to work on the driver and try to make further progress. ok deraadt@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/bcw.c1859
-rw-r--r--sys/dev/ic/bcwreg.h277
-rw-r--r--sys/dev/ic/bcwvar.h216
3 files changed, 2352 insertions, 0 deletions
diff --git a/sys/dev/ic/bcw.c b/sys/dev/ic/bcw.c
new file mode 100644
index 00000000000..42e07ecba79
--- /dev/null
+++ b/sys/dev/ic/bcw.c
@@ -0,0 +1,1859 @@
+/* $OpenBSD: bcw.c,v 1.1 2006/11/17 18:58:31 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
+ * Copyright (c) 2003 Clifford Wright. 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.
+ */
+
+/*
+ * Broadcom BCM43xx Wireless network chipsets (broadcom.com)
+ * SiliconBackplane is technology from Sonics, Inc.(sonicsinc.com)
+ *
+ * Cliff Wright cliff@snipe444.org
+ */
+
+/* standard includes, probably some extras */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ic/bcwreg.h>
+#include <dev/ic/bcwvar.h>
+
+#include <uvm/uvm_extern.h>
+
+void bcw_reset(struct bcw_softc *);
+int bcw_init(struct ifnet *);
+void bcw_start(struct ifnet *);
+void bcw_stop(struct ifnet *, int);
+/* Functions copied from bce - */
+void bcw_watchdog(struct ifnet *);
+void bcw_rxintr(struct bcw_softc *);
+void bcw_txintr(struct bcw_softc *);
+//static void bcw_add_mac(struct bcw_softc *, u_int8_t *, unsigned long);
+int bcw_add_rxbuf(struct bcw_softc *, int);
+void bcw_rxdrain(struct bcw_softc *);
+void bcw_set_filter(struct ifnet *);
+void bcw_tick(void *);
+int bcw_ioctl(struct ifnet *, u_long, caddr_t);
+/* 80211 functions copied from iwi */
+int bcw_newstate(struct ieee80211com *, enum ieee80211_state, int);
+int bcw_media_change(struct ifnet *);
+void bcw_media_status(struct ifnet *, struct ifmediareq *);
+/* fashionably new functions */
+int bcw_validatechipaccess(struct bcw_softc *ifp);
+
+/* read/write functions */
+u_int8_t bcw_read8(void *, u_int32_t);
+u_int16_t bcw_read16(void *, u_int32_t);
+u_int32_t bcw_read32(void *, u_int32_t);
+void bcw_write8(void *, u_int32_t, u_int8_t);
+void bcw_write16(void *, u_int32_t, u_int16_t);
+void bcw_write32(void *, u_int32_t, u_int32_t);
+void bcw_barrier(void *, u_int32_t, u_int32_t, int);
+
+
+struct cfdriver bcw_cd = {
+ NULL, "bcw", DV_IFNET
+};
+
+void
+bcw_attach(struct bcw_softc *sc)
+{
+ struct ieee80211com *ic = &sc->bcw_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ struct bcw_regs *regs = &sc->bcw_regs;
+// struct pci_attach_args *pa = &sc->bcw_pa;
+// pci_chipset_tag_t pc = pa->pa_pc;
+// pci_intr_handle_t ih;
+// const char *intrstr = NULL;
+ caddr_t kva;
+ bus_dma_segment_t seg;
+ int rseg;
+// pcireg_t memtype;
+// bus_addr_t memaddr;
+// bus_size_t memsize;
+// int pmreg;
+// pcireg_t pmode;
+ int error;
+ int i,j;
+ u_int32_t sbval;
+ u_int16_t sbval16;
+
+// sc->bcw_pa = *pa;
+// sc->bcw_dmatag = pa->pa_dmat;
+
+ if (sc->bcw_regs.r_read8 == NULL) {
+ sc->bcw_regs.r_read8 = bcw_read8;
+ sc->bcw_regs.r_read16 = bcw_read16;
+ sc->bcw_regs.r_read32 = bcw_read32;
+ sc->bcw_regs.r_write8 = bcw_write8;
+ sc->bcw_regs.r_write16 = bcw_write16;
+ sc->bcw_regs.r_write32 = bcw_write32;
+ sc->bcw_regs.r_barrier = bcw_barrier;
+ }
+
+
+ /*
+ * Reset the chip
+ */
+ bcw_reset(sc);
+
+ /*
+ * Attach to the Backplane and start the card up
+ */
+
+ /*
+ * Should just about everything below here be moved to external files
+ * to keep this file sane? The BCM43xx chips have so many exceptions
+ * based on the version of the chip, the radio, cores and phys that
+ * it would be a huge mess to inline it all here. See the 100 lines
+ * below for an example of just figuring out what the chip id is and
+ * how many cores it has.
+ */
+
+ /*
+ * XXX Can we read BCW_ADDR_SPACE0 and see if it returns a likely
+ * Core? On the 4318 that only has an 802.11 core, it always reads as
+ * some garbage, so if we do a read first we could set a "singlecore"
+ * flag instead of thrashing around trying to select non-existant
+ * cores. Testing requires cards that do have multiple cores. This
+ * would also simplify identifying cards into 3 classes early:
+ * - Multiple Cores without a Chip Common Core
+ * - Multiple Cores with a Chip Common Core
+ * - Single Core
+ */
+
+ sbval = BCW_READ32(regs, BCW_ADDR_SPACE0);
+ if ((sbval & 0xffff0000) != 0x18000000) {
+ DPRINTF(("%s: Trial Core read was 0x%x, single core only?\n",
+ sc->bcw_dev.dv_xname, sbval));
+ //sc->bcw_singlecore=1;
+ }
+
+ /*
+ * Try and change to the ChipCommon Core
+ */
+ for (i = 0; i < 10; i++) {
+ BCW_WRITE32(regs, BCW_ADDR_SPACE0, BCW_CORE_SELECT(0));
+ delay(10);
+ sbval = BCW_READ32(regs, BCW_ADDR_SPACE0);
+ DPRINTF(("%s: Core change read %d = 0x%x\n",
+ sc->bcw_dev.dv_xname,i,sbval));
+ if (sbval == BCW_CORE_SELECT(0)) break;
+ delay(10);
+ }
+// DPRINTF(("\n")); // Pretty print so the debugs start on new lines
+
+ /*
+ * Core ID REG, this is either the default wireless core (0x812) or
+ * a ChipCommon core
+ */
+ sbval = BCW_READ32(regs, BCW_CIR_SBID_HI);
+ DPRINTF(("%s: Got Core ID Reg 0x%x, type is 0x%x\n",
+ sc->bcw_dev.dv_xname, sbval, (sbval & 0x8ff0) >> 4));
+
+ /* If we successfully got a commoncore, and the corerev=4 or >=6
+ get the number of cores from the chipid reg */
+ if (((sbval & 0x00008ff0) >> 4) == BCW_CORE_COMMON) {
+ sc->bcw_havecommon = 1;
+ sbval = BCW_READ32(regs, BCW_CORE_COMMON_CHIPID);
+ sc->bcw_chipid = (sbval & 0x0000ffff);
+ sc->bcw_corerev = ((sbval & 0x00007000) >> 8 | (sbval & 0x0000000f));
+ if ((sc->bcw_corerev == 4) || (sc->bcw_corerev >= 6))
+ sc->bcw_numcores = (sbval & 0x0f000000) >> 24;
+ else
+ switch (sc->bcw_chipid) {
+ case 0x4710:
+ case 0x4610:
+ case 0x4704:
+ sc->bcw_numcores = 9;
+ break;
+ case 0x4310:
+ sc->bcw_numcores = 8;
+ break;
+ case 0x5365:
+ sc->bcw_numcores = 7;
+ break;
+ case 0x4306:
+ sc->bcw_numcores = 6;
+ break;
+ case 0x4307:
+ case 0x4301:
+ sc->bcw_numcores = 5;
+ break;
+ case 0x4402:
+ sc->bcw_numcores = 3;
+ break;
+ default:
+ /* XXX Educated Guess */
+ sc->bcw_numcores = 0;
+ } /* end of switch */
+ } else { /* No CommonCore, set chipid,cores,rev based on product id */
+ sc->bcw_havecommon = 0;
+ switch(sc->bcw_prodid) {
+ case 0x4710:
+ case 0x4711:
+ case 0x4712:
+ case 0x4713:
+ case 0x4714:
+ case 0x4715:
+ sc->bcw_chipid = 0x4710;
+ sc->bcw_numcores = 9;
+ break;
+ case 0x4610:
+ case 0x4611:
+ case 0x4612:
+ case 0x4613:
+ case 0x4614:
+ case 0x4615:
+ sc->bcw_chipid = 0x4610;
+ sc->bcw_numcores = 9;
+ break;
+ case 0x4402:
+ case 0x4403:
+ sc->bcw_chipid = 0x4402;
+ sc->bcw_numcores = 3;
+ break;
+ case 0x4305:
+ case 0x4306:
+ case 0x4307:
+ sc->bcw_chipid = 0x4307;
+ sc->bcw_numcores = 5;
+ break;
+ case 0x4301:
+ sc->bcw_chipid = 0x4301;
+ sc->bcw_numcores = 5;
+ break;
+ default:
+ sc->bcw_chipid = sc->bcw_prodid;
+ /* XXX educated guess */
+ sc->bcw_numcores = 1;
+ } /* end of switch */
+ } /* End of if/else */
+
+ DPRINTF(("%s: ChipID=0x%x, ChipRev=0x%x, NumCores=%d\n",
+ sc->bcw_dev.dv_xname, sc->bcw_chipid,
+ sc->bcw_chiprev, sc->bcw_numcores));
+
+ /* Identify each core */
+ if (sc->bcw_numcores >= 2) { /* Exclude single core chips */
+ for (i = 0; i <= sc->bcw_numcores; i++) {
+ DPRINTF(("%s: Trying core %d - ",
+ sc->bcw_dev.dv_xname, i));
+ BCW_WRITE32(regs, BCW_ADDR_SPACE0, BCW_CORE_SELECT(i));
+ /* loop to see if the selected core shows up */
+ for (j = 0; j < 10; j++) {
+ sbval=BCW_READ32(regs, BCW_ADDR_SPACE0);
+ DPRINTF(("%s: read %d for core %d = 0x%x ",
+ sc->bcw_dev.dv_xname, j, i, sbval));
+ if (sbval == BCW_CORE_SELECT(i)) break;
+ delay(10);
+ }
+ if (j < 10)
+ DPRINTF(("%s: Found core %d of type 0x%x\n",
+ sc->bcw_dev.dv_xname, i,
+ (sbval & 0x00008ff0) >> 4));
+// sc->bcw_core[i].id = (sbval & 0x00008ff0) >> 4;
+ } /* End of For loop */
+ DPRINTF(("\n")); /* Make pretty debug output */
+ }
+
+ /*
+ * Attach cores to the backplane, if we have more than one
+ */
+ // ??? if (!sc->bcw_singlecore) {
+ if (sc->bcw_havecommon == 1) {
+ sbval = BCW_READ32(regs, BCW_PCICR);
+ sbval |= 0x1 << 8; /* XXX hardcoded bitmask of single core */
+ BCW_WRITE32(regs, BCW_PCICR, sbval);
+ }
+
+ /*
+ * Get and display the PHY info from the MIMO
+ */
+ sbval = BCW_READ16(regs, 0x3E0);
+ sc->bcw_phy_version = (sbval&0xf000)>>12;
+ sc->bcw_phy_rev = sbval&0xf;
+ sc->bcw_phy_type = (sbval&0xf00)>>8;
+ DPRINTF(("%s: PHY version %d revision %d ",
+ sc->bcw_dev.dv_xname, sc->bcw_phy_version, sc->bcw_phy_rev));
+ switch (sc->bcw_phy_type) {
+ case BCW_PHY_TYPEA:
+ DPRINTF(("PHY %d (A)\n",sc->bcw_phy_type));
+ break;
+ case BCW_PHY_TYPEB:
+ DPRINTF(("PHY %d (B)\n",sc->bcw_phy_type));
+ break;
+ case BCW_PHY_TYPEG:
+ DPRINTF(("PHY %d (G)\n",sc->bcw_phy_type));
+ break;
+ case BCW_PHY_TYPEN:
+ DPRINTF(("PHY %d (N)\n",sc->bcw_phy_type));
+ break;
+ default:
+ DPRINTF(("Unrecognizeable PHY type %d\n",
+ sc->bcw_phy_type));
+ break;
+ } /* end of switch */
+
+ /*
+ * Query the RadioID register, on a 4317 use a lookup instead
+ * XXX Different PHYs have different radio register layouts, so
+ * a wrapper func should be written.
+ * Getting the RadioID is the only 32bit operation done with the
+ * Radio registers, and requires seperate 16bit reads from the low
+ * and the high data addresses.
+ */
+ if (sc->bcw_chipid != 0x4317) {
+ BCW_WRITE16(regs, BCW_RADIO_CONTROL, BCW_RADIO_ID);
+ sbval=BCW_READ16(regs, BCW_RADIO_DATAHIGH);
+ sbval <<= 16;
+ BCW_WRITE16(regs, BCW_RADIO_CONTROL, BCW_RADIO_ID);
+ sc->bcw_radioid = sbval | BCW_READ16(regs, BCW_RADIO_DATALOW);
+ } else {
+ switch(sc->bcw_corerev) {
+ case 0:
+ sc->bcw_radioid = 0x3205017F;
+ break;
+ case 1:
+ sc->bcw_radioid = 0x4205017f;
+ break;
+ default:
+ sc->bcw_radioid = 0x5205017f;
+ }
+ }
+
+ sc->bcw_radiorev = (sc->bcw_radioid & 0xf0000000) >> 28;
+ sc->bcw_radiotype = (sc->bcw_radioid & 0x0ffff000) >> 12;
+
+ DPRINTF(("%s: Radio Rev %d, Ver 0x%x, Manuf 0x%x\n",
+ sc->bcw_dev.dv_xname, sc->bcw_radiorev, sc->bcw_radiotype,
+ sc->bcw_radioid & 0xfff));
+
+ error = bcw_validatechipaccess(sc);
+ if (error) {
+ printf("%s: failed Chip Access Validation at %d\n",
+ sc->bcw_dev.dv_xname, error);
+ return;
+ }
+
+ /* Test for valid PHY/revision combinations, probably a simpler way */
+ if (sc->bcw_phy_type == BCW_PHY_TYPEA) {
+ switch(sc->bcw_phy_rev) {
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7: break;
+ default:
+ printf("%s: invalid PHY A revision %d\n",
+ sc->bcw_dev.dv_xname, sc->bcw_phy_rev);
+ return;
+ }
+ }
+ if (sc->bcw_phy_type == BCW_PHY_TYPEB) {
+ switch(sc->bcw_phy_rev) {
+ case 2:
+ case 4:
+ case 7: break;
+ default:
+ printf("%s: invalid PHY B revision %d\n",
+ sc->bcw_dev.dv_xname, sc->bcw_phy_rev);
+ return;
+ }
+ }
+ if (sc->bcw_phy_type == BCW_PHY_TYPEG) {
+ switch(sc->bcw_phy_rev) {
+ case 1:
+ case 2:
+ case 4:
+ case 6:
+ case 7:
+ case 8: break;
+ default:
+ printf("%s: invalid PHY G revision %d\n",
+ sc->bcw_dev.dv_xname, sc->bcw_phy_rev);
+ return;
+ }
+ }
+
+ /* test for valid radio revisions */
+ if ((sc->bcw_phy_type == BCW_PHY_TYPEA) &
+ (sc->bcw_radiotype != 0x2060)) {
+ printf("%s: invalid PHY A radio 0x%x\n",
+ sc->bcw_dev.dv_xname, sc->bcw_radiotype);
+ return;
+ }
+ if ((sc->bcw_phy_type == BCW_PHY_TYPEB) &
+ ((sc->bcw_radiotype & 0xfff0) != 0x2050)) {
+ printf("%s: invalid PHY B radio 0x%x\n",
+ sc->bcw_dev.dv_xname, sc->bcw_radiotype);
+ return;
+ }
+ if ((sc->bcw_phy_type == BCW_PHY_TYPEG) &
+ (sc->bcw_radiotype != 0x2050)) {
+ printf("%s: invalid PHY G radio 0x%x\n",
+ sc->bcw_dev.dv_xname, sc->bcw_radiotype);
+ return;
+ }
+
+ /*
+ * Switch the radio off - candidate for seperate function
+ */
+
+ switch(sc->bcw_phy_type) {
+ case BCW_PHY_TYPEA:
+ /* Magic unexplained values */
+ BCW_WRITE16(regs, BCW_RADIO_CONTROL, 0x04);
+ BCW_WRITE16(regs, BCW_RADIO_DATALOW, 0xff);
+ BCW_WRITE16(regs, BCW_RADIO_CONTROL, 0x05);
+ BCW_WRITE16(regs, BCW_RADIO_DATALOW, 0xfb);
+ /*
+ * "When the term MaskSet is used, it is shorthand
+ * for reading a value from a register, applying a
+ * bitwise AND mask to the value and then applying
+ * a bitwise OR to set a value. This value is then
+ * written back to the register."
+ * - This makes little sense when the docs say that
+ * here we read a value, AND it with 0xffff, then
+ * OR with 0x8. Why not just set the 0x8 bit?
+ */
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x10);
+ sbval16 = BCW_READ16(regs, BCW_PHY_DATA);
+ sbval16 |= 0x8;
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x10);
+ BCW_WRITE16(regs, BCW_PHY_DATA, sbval16);
+
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x11);
+ sbval16 = BCW_READ16(regs, BCW_PHY_DATA);
+ sbval16 |= 0x8;
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x11);
+ BCW_WRITE16(regs, BCW_PHY_DATA, sbval16);
+ break;
+ case BCW_PHY_TYPEG:
+ if (sc->bcw_corerev >= 5) {
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x811);
+ sbval16 = BCW_READ16(regs, BCW_PHY_DATA);
+ sbval16 |= 0x8c;
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x811);
+ BCW_WRITE16(regs, BCW_PHY_DATA, sbval16);
+
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x812);
+ sbval16 = BCW_READ16(regs, BCW_PHY_DATA);
+ sbval16 &= 0xff73;
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x812);
+ BCW_WRITE16(regs, BCW_PHY_DATA, sbval16);
+ }
+ /* FALL-THROUGH */
+ default:
+ BCW_WRITE16(regs, BCW_PHY_CONTROL, 0x15);
+ BCW_WRITE16(regs, BCW_PHY_DATA, 0xaa00);
+ } /* end of switch statement to turn off radio */
+
+ // XXX - Get a copy of the BoardFlags to keep in RAM
+
+ /* Read antenna gain from SPROM and multiply by 4 */
+ sbval = BCW_READ16(regs, BCW_SPROM_ANTGAIN);
+ /* If unset, assume 2 */
+ if((sbval == 0) || (sbval == 0xffff)) sbval = 0x0202;
+ if(sc->bcw_phy_type == BCW_PHY_TYPEA)
+ sc->bcw_radio_gain = (sbval & 0xff);
+ else
+ sc->bcw_radio_gain = ((sbval & 0xff00) >> 8);
+ sc->bcw_radio_gain *= 4;
+
+ /*
+ * Set the paXbY vars, X=0 for PHY A, X=1 for B/G, but we'll
+ * just grab them all while we're here
+ */
+ sc->bcw_radio_pa0b0 = BCW_READ16(regs, BCW_SPROM_PA0B0);
+ sc->bcw_radio_pa0b1 = BCW_READ16(regs, BCW_SPROM_PA0B1);
+ sc->bcw_radio_pa0b2 = BCW_READ16(regs, BCW_SPROM_PA0B2);
+ sc->bcw_radio_pa1b0 = BCW_READ16(regs, BCW_SPROM_PA1B0);
+ sc->bcw_radio_pa1b1 = BCW_READ16(regs, BCW_SPROM_PA1B1);
+ sc->bcw_radio_pa1b2 = BCW_READ16(regs, BCW_SPROM_PA1B2);
+
+ /* Get the idle TSSI */
+ sbval = BCW_READ16(regs, BCW_SPROM_IDLETSSI);
+ if(sc->bcw_phy_type == BCW_PHY_TYPEA)
+ sc->bcw_idletssi = (sbval & 0xff);
+ else
+ sc->bcw_idletssi = ((sbval & 0xff00) >> 8);
+
+
+ /* Init the Microcode Flags Bitfield */
+ // http://bcm-specs.sipsolutions.net/MicrocodeFlagsBitfield
+
+ sbval = 0;
+ if((sc->bcw_phy_type == BCW_PHY_TYPEA) ||
+ (sc->bcw_phy_type == BCW_PHY_TYPEB) ||
+ (sc->bcw_phy_type == BCW_PHY_TYPEG))
+ sbval |= 2; /* Turned on during init for non N phys */
+ if((sc->bcw_phy_type == BCW_PHY_TYPEG) &&
+ (sc->bcw_phy_rev == 1))
+ sbval |= 0x20;
+ // XXX If this is a G PHY with BoardFlags BFL_PACTRL set, set bit 0x40
+ if((sc->bcw_phy_type == BCW_PHY_TYPEG) &&
+ (sc->bcw_phy_rev < 3))
+ sbval |= 0x8; /* MAGIC */
+ // XXX If BoardFlags BFL_XTAL is set, set bit 0x400
+ if(sc->bcw_phy_type == BCW_PHY_TYPEB)
+ sbval |= 0x4;
+ if((sc->bcw_radiotype == 0x2050) &&
+ (sc->bcw_radiorev <= 5))
+ sbval |= 0x40000;
+ /* XXX If the device isn't up and this is a PCI bus with revision
+ 10 or less set bit 0x80000 */
+
+
+ /* Now, write the value into the regster */
+ /*
+ * The MicrocodeBitFlags is an unaligned 32bit value in SHM, so the
+ * strategy is to select the aligned word for the lower 16 bits,
+ * but write to the unaligned address. Then, because the SHM
+ * pointer is automatically incremented to the next aligned word,
+ * we can just write the remaining bits as a 16 bit write.
+ * This explanation could make more sense, but an SHM read/write
+ * wrapper of some sort would be better.
+ */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL,
+ (BCW_SHM_CONTROL_SHARED << 16) + BCW_SHM_MICROCODEFLAGSLOW - 2);
+ BCW_WRITE16(regs, BCW_SHM_DATAHIGH, sbval & 0x00ff);
+ BCW_WRITE16(regs, BCW_SHM_DATALOW, (sbval & 0xff00)>>16);
+
+ /*
+ * Initialize the TSSI to DBM table
+ * The method is described at
+ * http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table
+ * but I suspect there's a standard way to do it in the 80211 stuff
+ */
+
+
+ /*
+ * TODO still for the card attach:
+ * - Disable the 80211 Core
+ * - Powercontrol Crystal Off (and write a wrapper for on/off)
+ * - Setup LEDs to blink in whatever fashionable manner
+ */
+
+
+
+ /*
+ * Allocate DMA-safe memory for ring descriptors.
+ * The receive, and transmit rings are 4k aligned
+ * XXX - still not too sure on how this works, it is
+ * some of the remaining untouched code from if_bce
+ */
+ if ((error = bus_dmamem_alloc(sc->bcw_dmatag,
+ 2 * PAGE_SIZE, PAGE_SIZE, 2 * PAGE_SIZE,
+ &seg, 1, &rseg, BUS_DMA_NOWAIT))) {
+ printf("%s: unable to alloc space for ring descriptors, "
+ "error = %d\n", sc->bcw_dev.dv_xname, error);
+ return;
+ }
+ /* map ring space to kernel */
+ if ((error = bus_dmamem_map(sc->bcw_dmatag, &seg, rseg,
+ 2 * PAGE_SIZE, &kva, BUS_DMA_NOWAIT))) {
+ printf("%s: unable to map DMA buffers, error = %d\n",
+ sc->bcw_dev.dv_xname, error);
+ bus_dmamem_free(sc->bcw_dmatag, &seg, rseg);
+ return;
+ }
+ /* create a dma map for the ring */
+ if ((error = bus_dmamap_create(sc->bcw_dmatag,
+ 2 * PAGE_SIZE, 1, 2 * PAGE_SIZE, 0, BUS_DMA_NOWAIT,
+ &sc->bcw_ring_map))) {
+ printf("%s: unable to create ring DMA map, error = %d\n",
+ sc->bcw_dev.dv_xname, error);
+ bus_dmamem_unmap(sc->bcw_dmatag, kva, 2 * PAGE_SIZE);
+ bus_dmamem_free(sc->bcw_dmatag, &seg, rseg);
+ return;
+ }
+ /* connect the ring space to the dma map */
+ if (bus_dmamap_load(sc->bcw_dmatag, sc->bcw_ring_map, kva,
+ 2 * PAGE_SIZE, NULL, BUS_DMA_NOWAIT)) {
+ bus_dmamap_destroy(sc->bcw_dmatag, sc->bcw_ring_map);
+ bus_dmamem_unmap(sc->bcw_dmatag, kva, 2 * PAGE_SIZE);
+ bus_dmamem_free(sc->bcw_dmatag, &seg, rseg);
+ return;
+ }
+ /* save the ring space in softc */
+ sc->bcw_rx_ring = (struct bcw_dma_slot *) kva;
+ sc->bcw_tx_ring = (struct bcw_dma_slot *) (kva + PAGE_SIZE);
+
+ /* Create the transmit buffer DMA maps. */
+ for (i = 0; i < BCW_NTXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->bcw_dmatag, MCLBYTES,
+ BCW_NTXFRAGS, MCLBYTES, 0, 0, &sc->bcw_cdata.bcw_tx_map[i])) != 0) {
+ printf("%s: unable to create tx DMA map, error = %d\n",
+ sc->bcw_dev.dv_xname, error);
+ }
+ sc->bcw_cdata.bcw_tx_chain[i] = NULL;
+ }
+
+ /* Create the receive buffer DMA maps. */
+ for (i = 0; i < BCW_NRXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->bcw_dmatag, MCLBYTES, 1,
+ MCLBYTES, 0, 0, &sc->bcw_cdata.bcw_rx_map[i])) != 0) {
+ printf("%s: unable to create rx DMA map, error = %d\n",
+ sc->bcw_dev.dv_xname, error);
+ }
+ sc->bcw_cdata.bcw_rx_chain[i] = NULL;
+ }
+
+ /* End of the DMA stuff */
+
+
+ ic->ic_phytype = IEEE80211_T_OFDM;
+ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+ ic->ic_state = IEEE80211_S_INIT;
+
+ /* set device capabilities - keep it simple */
+ ic->ic_caps =
+ IEEE80211_C_IBSS; /* IBSS mode supported */
+
+ /* MAC address */
+ if(sc->bcw_phy_type == BCW_PHY_TYPEA) {
+ i=BCW_READ16(regs, BCW_SPROM_ET1MACADDR);
+ ic->ic_myaddr[0] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[1] = i & 0xff;
+ i=BCW_READ16(regs, BCW_SPROM_ET1MACADDR + 2);
+ ic->ic_myaddr[2] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[3] = i & 0xff;
+ i=BCW_READ16(regs, BCW_SPROM_ET1MACADDR + 4);
+ ic->ic_myaddr[4] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[5] = i & 0xff;
+ } else { /* assume B or G PHY */
+ i=BCW_READ16(regs, BCW_SPROM_IL0MACADDR);
+ ic->ic_myaddr[0] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[1] = i & 0xff;
+ i=BCW_READ16(regs, BCW_SPROM_IL0MACADDR + 2);
+ ic->ic_myaddr[2] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[3] = i & 0xff;
+ i=BCW_READ16(regs, BCW_SPROM_IL0MACADDR + 4);
+ ic->ic_myaddr[4] = (i & 0xff00) >> 8;
+ ic->ic_myaddr[5] = i & 0xff;
+ }
+
+ printf(": %s, address %s\n", sc->bcw_intrstr,
+ ether_sprintf(ic->ic_myaddr));
+
+ /* Set supported rates */
+ ic->ic_sup_rates[IEEE80211_MODE_11B] = bcw_rateset_11b;
+ ic->ic_sup_rates[IEEE80211_MODE_11G] = bcw_rateset_11g;
+
+ /* Set supported channels */
+ for (i = 1; i <= 14; i++) {
+ ic->ic_channels[i].ic_freq =
+ ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+ ic->ic_channels[i].ic_flags =
+ IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+ }
+
+ /* IBSS channel undefined for now */
+ ic->ic_ibss_chan = &ic->ic_channels[0];
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = bcw_init;
+ ifp->if_ioctl = bcw_ioctl;
+ ifp->if_start = bcw_start;
+ ifp->if_watchdog = bcw_watchdog;
+ IFQ_SET_READY(&ifp->if_snd);
+ bcopy(sc->bcw_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+
+ /* Attach the interface */
+ if_attach(ifp);
+ ieee80211_ifattach(ifp);
+ /* override state transition machine */
+ sc->sc_newstate = ic->ic_newstate;
+ ic->ic_newstate = bcw_newstate;
+ ieee80211_media_init(ifp, bcw_media_change, bcw_media_status);
+
+ timeout_set(&sc->bcw_timeout, bcw_tick, sc);
+}
+
+/* handle media, and ethernet requests */
+int
+bcw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->bcw_ic;
+// struct bcw_regs *regs = &sc->bcw_regs;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ s = splnet();
+
+// if ((error = ether_ioctl(ifp, &sc->bcw_ac, cmd, data)) > 0) {
+// splx(s);
+// return (error);
+// }
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ bcw_init(ifp);
+ arp_ifinit(&sc->bcw_ac, ifa);
+ break;
+#endif /* INET */
+ default:
+ bcw_init(ifp);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if((ifp->if_flags & IFF_UP)&&(!(ifp->if_flags & IFF_RUNNING)))
+ bcw_init(ifp);
+ else if(ifp->if_flags & IFF_RUNNING)
+ bcw_stop(ifp, 1);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &ic->ic_ac) :
+ ether_delmulti(ifr, &ic->ic_ac);
+
+ if (error == ENETRESET)
+ error = 0;
+ break;
+
+ case SIOCG80211TXPOWER:
+ /*
+ * If the hardware radio transmitter switch is off, report a
+ * tx power of IEEE80211_TXPOWER_MIN to indicate that radio
+ * transmitter is killed.
+ */
+ break;
+
+ default:
+ error = ieee80211_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ if (error == ENETRESET) {
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
+ (IFF_UP | IFF_RUNNING))
+ bcw_init(ifp);
+ error = 0;
+ }
+
+ splx(s);
+ return error;
+}
+
+/* Start packet transmission on the interface. */
+void
+bcw_start(struct ifnet *ifp)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+ struct bcw_regs *regs = &sc->bcw_regs;
+ struct mbuf *m0;
+ bus_dmamap_t dmamap;
+ int txstart;
+ int txsfree;
+ int newpkts = 0;
+ int error;
+
+ /*
+ * do not start another if currently transmitting, and more
+ * descriptors(tx slots) are needed for next packet.
+ */
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ /* determine number of descriptors available */
+ if (sc->bcw_txsnext >= sc->bcw_txin)
+ txsfree = BCW_NTXDESC - 1 + sc->bcw_txin - sc->bcw_txsnext;
+ else
+ txsfree = sc->bcw_txin - sc->bcw_txsnext - 1;
+
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (txsfree > 0) {
+ int seg;
+
+ /* Grab a packet off the queue. */
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+
+ /* get the transmit slot dma map */
+ dmamap = sc->bcw_cdata.bcw_tx_map[sc->bcw_txsnext];
+
+ /*
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the alloted number of segments, or we
+ * were short on resources. If the packet will not fit,
+ * it will be dropped. If short on resources, it will
+ * be tried again later.
+ */
+ error = bus_dmamap_load_mbuf(sc->bcw_dmatag, dmamap, m0,
+ BUS_DMA_WRITE | BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ printf("%s: Tx packet consumes too many DMA segments, "
+ "dropping...\n", sc->bcw_dev.dv_xname);
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+ m_freem(m0);
+ ifp->if_oerrors++;
+ continue;
+ } else if (error) {
+ /* short on resources, come back later */
+ printf("%s: unable to load Tx buffer, error = %d\n",
+ sc->bcw_dev.dv_xname, error);
+ break;
+ }
+ /* If not enough descriptors available, try again later */
+ if (dmamap->dm_nsegs > txsfree) {
+ ifp->if_flags |= IFF_OACTIVE;
+ bus_dmamap_unload(sc->bcw_dmatag, dmamap);
+ break;
+ }
+ /* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. */
+
+ /* So take it off the queue */
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+
+ /* save the pointer so it can be freed later */
+ sc->bcw_cdata.bcw_tx_chain[sc->bcw_txsnext] = m0;
+
+ /* Sync the data DMA map. */
+ bus_dmamap_sync(sc->bcw_dmatag, dmamap, 0, dmamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Initialize the transmit descriptor(s). */
+ txstart = sc->bcw_txsnext;
+ for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
+ u_int32_t ctrl;
+
+ ctrl = dmamap->dm_segs[seg].ds_len & CTRL_BC_MASK;
+ if (seg == 0)
+ ctrl |= CTRL_SOF;
+ if (seg == dmamap->dm_nsegs - 1)
+ ctrl |= CTRL_EOF;
+ if (sc->bcw_txsnext == BCW_NTXDESC - 1)
+ ctrl |= CTRL_EOT;
+ ctrl |= CTRL_IOC;
+ sc->bcw_tx_ring[sc->bcw_txsnext].ctrl = htole32(ctrl);
+ sc->bcw_tx_ring[sc->bcw_txsnext].addr =
+ htole32(dmamap->dm_segs[seg].ds_addr + 0x40000000); /* MAGIC */
+ if (sc->bcw_txsnext + 1 > BCW_NTXDESC - 1)
+ sc->bcw_txsnext = 0;
+ else
+ sc->bcw_txsnext++;
+ txsfree--;
+ }
+ /* sync descriptors being used */
+ bus_dmamap_sync(sc->bcw_dmatag, sc->bcw_ring_map,
+ sizeof(struct bcw_dma_slot) * txstart + PAGE_SIZE,
+ sizeof(struct bcw_dma_slot) * dmamap->dm_nsegs,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Give the packet to the chip. */
+ BCW_WRITE32(regs, BCW_DMA_DPTR,
+ sc->bcw_txsnext * sizeof(struct bcw_dma_slot));
+
+ newpkts++;
+
+#if NBPFILTER > 0
+ /* Pass the packet to any BPF listeners. */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER > 0 */
+ }
+ if (txsfree == 0) {
+ /* No more slots left; notify upper layer. */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+ if (newpkts) {
+ /* Set a watchdog timer in case the chip flakes out. */
+ ifp->if_timer = 5;
+ }
+}
+
+/* Watchdog timer handler. */
+void
+bcw_watchdog(struct ifnet *ifp)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+
+ printf("%s: device timeout\n", sc->bcw_dev.dv_xname);
+ ifp->if_oerrors++;
+
+ (void) bcw_init(ifp);
+
+ /* Try to get more packets going. */
+ bcw_start(ifp);
+}
+
+int
+bcw_intr(void *xsc)
+{
+ struct bcw_softc *sc;
+ struct bcw_regs *regs;
+ struct ifnet *ifp;
+ u_int32_t intstatus;
+ int wantinit;
+ int handled = 0;
+
+ sc = xsc;
+ regs = &sc->bcw_regs;
+ ifp = &sc->bcw_ac.ac_if;
+
+
+ for (wantinit = 0; wantinit == 0;) {
+ intstatus = BCW_READ32(regs, BCW_INT_STS);
+
+ /* ignore if not ours, or unsolicited interrupts */
+ intstatus &= sc->bcw_intmask;
+ if (intstatus == 0)
+ break;
+
+ handled = 1;
+
+ /* Ack interrupt */
+ BCW_WRITE32(regs, BCW_INT_STS, intstatus);
+
+ /* Receive interrupts. */
+ if (intstatus & I_RI)
+ bcw_rxintr(sc);
+ /* Transmit interrupts. */
+ if (intstatus & I_XI)
+ bcw_txintr(sc);
+ /* Error interrupts */
+ if (intstatus & ~(I_RI | I_XI)) {
+ if (intstatus & I_XU)
+ printf("%s: transmit fifo underflow\n",
+ sc->bcw_dev.dv_xname);
+ if (intstatus & I_RO) {
+ printf("%s: receive fifo overflow\n",
+ sc->bcw_dev.dv_xname);
+ ifp->if_ierrors++;
+ }
+ if (intstatus & I_RU)
+ printf("%s: receive descriptor underflow\n",
+ sc->bcw_dev.dv_xname);
+ if (intstatus & I_DE)
+ printf("%s: descriptor protocol error\n",
+ sc->bcw_dev.dv_xname);
+ if (intstatus & I_PD)
+ printf("%s: data error\n",
+ sc->bcw_dev.dv_xname);
+ if (intstatus & I_PC)
+ printf("%s: descriptor error\n",
+ sc->bcw_dev.dv_xname);
+ if (intstatus & I_TO)
+ printf("%s: general purpose timeout\n",
+ sc->bcw_dev.dv_xname);
+ wantinit = 1;
+ }
+ }
+
+ if (handled) {
+ if (wantinit)
+ bcw_init(ifp);
+ /* Try to get more packets going. */
+ bcw_start(ifp);
+ }
+ return (handled);
+}
+
+/* Receive interrupt handler */
+void
+bcw_rxintr(struct bcw_softc *sc)
+{
+ struct ifnet *ifp = &sc->bcw_ac.ac_if;
+ struct bcw_regs *regs = &sc->bcw_regs;
+ struct rx_pph *pph;
+ struct mbuf *m;
+ int curr;
+ int len;
+ int i;
+
+ /* get pointer to active receive slot */
+ curr = BCW_READ32(regs, BCW_DMA_RXSTATUS) & RS_CD_MASK;
+ curr = curr / sizeof(struct bcw_dma_slot);
+ if (curr >= BCW_NRXDESC)
+ curr = BCW_NRXDESC - 1;
+
+ /* process packets up to but not current packet being worked on */
+ for (i = sc->bcw_rxin; i != curr;
+ i + 1 > BCW_NRXDESC - 1 ? i = 0 : i++) {
+ /* complete any post dma memory ops on packet */
+ bus_dmamap_sync(sc->bcw_dmatag, sc->bcw_cdata.bcw_rx_map[i], 0,
+ sc->bcw_cdata.bcw_rx_map[i]->dm_mapsize,
+ BUS_DMASYNC_POSTREAD);
+
+ /*
+ * If the packet had an error, simply recycle the buffer,
+ * resetting the len, and flags.
+ */
+ pph = mtod(sc->bcw_cdata.bcw_rx_chain[i], struct rx_pph *);
+ if (pph->flags & (RXF_NO | RXF_RXER | RXF_CRC | RXF_OV)) {
+ ifp->if_ierrors++;
+ pph->len = 0;
+ pph->flags = 0;
+ continue;
+ }
+ /* receive the packet */
+ len = pph->len;
+ if (len == 0)
+ continue; /* no packet if empty */
+ pph->len = 0;
+ pph->flags = 0;
+ /* bump past pre header to packet */
+ sc->bcw_cdata.bcw_rx_chain[i]->m_data +=
+ BCW_PREPKT_HEADER_SIZE;
+
+ /*
+ * The chip includes the CRC with every packet. Trim
+ * it off here.
+ */
+ len -= ETHER_CRC_LEN;
+
+ /*
+ * If the packet is small enough to fit in a
+ * single header mbuf, allocate one and copy
+ * the data into it. This greatly reduces
+ * memory consumption when receiving lots
+ * of small packets.
+ *
+ * Otherwise, add a new buffer to the receive
+ * chain. If this fails, drop the packet and
+ * recycle the old buffer.
+ */
+ if (len <= (MHLEN - 2)) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto dropit;
+ m->m_data += 2;
+ memcpy(mtod(m, caddr_t),
+ mtod(sc->bcw_cdata.bcw_rx_chain[i], caddr_t), len);
+ sc->bcw_cdata.bcw_rx_chain[i]->m_data -=
+ BCW_PREPKT_HEADER_SIZE;
+ } else {
+ m = sc->bcw_cdata.bcw_rx_chain[i];
+ if (bcw_add_rxbuf(sc, i) != 0) {
+ dropit:
+ ifp->if_ierrors++;
+ /* continue to use old buffer */
+ sc->bcw_cdata.bcw_rx_chain[i]->m_data -=
+ BCW_PREPKT_HEADER_SIZE;
+ bus_dmamap_sync(sc->bcw_dmatag,
+ sc->bcw_cdata.bcw_rx_map[i], 0,
+ sc->bcw_cdata.bcw_rx_map[i]->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+ continue;
+ }
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+ ifp->if_ipackets++;
+
+#if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass it up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif /* NBPFILTER > 0 */
+
+ /* Pass it on. */
+ ether_input_mbuf(ifp, m);
+
+ /* re-check current in case it changed */
+ curr = (BCW_READ32(regs,
+ BCW_DMA_RXSTATUS) & RS_CD_MASK) /
+ sizeof(struct bcw_dma_slot);
+ if (curr >= BCW_NRXDESC)
+ curr = BCW_NRXDESC - 1;
+ }
+ sc->bcw_rxin = curr;
+}
+
+/* Transmit interrupt handler */
+void
+bcw_txintr(struct bcw_softc *sc)
+{
+ struct ifnet *ifp = &sc->bcw_ac.ac_if;
+ struct bcw_regs *regs = &sc->bcw_regs;
+ int curr;
+ int i;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Go through the Tx list and free mbufs for those
+ * frames which have been transmitted.
+ */
+ curr = BCW_READ32(regs, BCW_DMA_TXSTATUS) & RS_CD_MASK;
+ curr = curr / sizeof(struct bcw_dma_slot);
+ if (curr >= BCW_NTXDESC)
+ curr = BCW_NTXDESC - 1;
+ for (i = sc->bcw_txin; i != curr;
+ i + 1 > BCW_NTXDESC - 1 ? i = 0 : i++) {
+ /* do any post dma memory ops on transmit data */
+ if (sc->bcw_cdata.bcw_tx_chain[i] == NULL)
+ continue;
+ bus_dmamap_sync(sc->bcw_dmatag, sc->bcw_cdata.bcw_tx_map[i], 0,
+ sc->bcw_cdata.bcw_tx_map[i]->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->bcw_dmatag, sc->bcw_cdata.bcw_tx_map[i]);
+ m_freem(sc->bcw_cdata.bcw_tx_chain[i]);
+ sc->bcw_cdata.bcw_tx_chain[i] = NULL;
+ ifp->if_opackets++;
+ }
+ sc->bcw_txin = curr;
+
+ /*
+ * If there are no more pending transmissions, cancel the watchdog
+ * timer
+ */
+ if (sc->bcw_txsnext == sc->bcw_txin)
+ ifp->if_timer = 0;
+}
+
+/* initialize the interface */
+int
+bcw_init(struct ifnet *ifp)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+ struct bcw_regs *regs = &sc->bcw_regs;
+ u_int32_t reg_win;
+ int error;
+ int i;
+
+ /* Cancel any pending I/O. */
+ bcw_stop(ifp, 0);
+
+ /*
+ * Most of this needs to be rewritten to take into account the
+ * possible single/multiple core nature of the BCM43xx, and the
+ * differences from the BCM44xx ethernet chip that if_bce.c is
+ * written for.
+ */
+
+ /* enable pci inerrupts, bursts, and prefetch */
+
+ /* remap the pci registers to the Sonics config registers */
+
+ /* save the current map, so it can be restored */
+ reg_win = BCW_READ32(regs, BCW_REG0_WIN);
+
+ /* set register window to Sonics registers */
+ BCW_WRITE32(regs, BCW_REG0_WIN, BCW_SONICS_WIN);
+
+ /* enable SB to PCI interrupt */
+ BCW_WRITE32(regs, BCW_SBINTVEC,
+ BCW_READ32(regs, BCW_SBINTVEC) |
+ SBIV_ENET0);
+
+ /* enable prefetch and bursts for sonics-to-pci translation 2 */
+ BCW_WRITE32(regs, BCW_SPCI_TR2,
+ BCW_READ32(regs, BCW_SPCI_TR2) |
+ SBTOPCI_PREF | SBTOPCI_BURST);
+
+ /* restore to ethernet register space */
+ BCW_WRITE32(regs, BCW_REG0_WIN, reg_win);
+
+ /* Reset the chip to a known state. */
+ bcw_reset(sc);
+
+ /* Initialize transmit descriptors */
+ memset(sc->bcw_tx_ring, 0, BCW_NTXDESC * sizeof(struct bcw_dma_slot));
+ sc->bcw_txsnext = 0;
+ sc->bcw_txin = 0;
+
+ /* enable crc32 generation and set proper LED modes */
+ BCW_WRITE32(regs, BCW_MACCTL,
+ BCW_READ32(regs, BCW_MACCTL) |
+ BCW_EMC_CRC32_ENAB | BCW_EMC_LED);
+
+ /* reset or clear powerdown control bit */
+ BCW_WRITE32(regs, BCW_MACCTL,
+ BCW_READ32(regs, BCW_MACCTL) &
+ ~BCW_EMC_PDOWN);
+
+ /* setup DMA interrupt control */
+ BCW_WRITE32(regs, BCW_DMAI_CTL, 1 << 24); /* MAGIC */
+
+ /* setup packet filter */
+ bcw_set_filter(ifp);
+
+ /* set max frame length, account for possible VLAN tag */
+ BCW_WRITE32(regs, BCW_RX_MAX,
+ ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
+ BCW_WRITE32(regs, BCW_TX_MAX,
+ ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
+
+ /* set tx watermark */
+ BCW_WRITE32(regs, BCW_TX_WATER, 56);
+
+ /* enable transmit */
+ BCW_WRITE32(regs, BCW_DMA_TXCTL, XC_XE);
+ BCW_WRITE32(regs, BCW_DMA_TXADDR,
+ sc->bcw_ring_map->dm_segs[0].ds_addr + PAGE_SIZE + 0x40000000); /* MAGIC */
+
+ /*
+ * Give the receive ring to the chip, and
+ * start the receive DMA engine.
+ */
+ sc->bcw_rxin = 0;
+
+ /* clear the rx descriptor ring */
+ memset(sc->bcw_rx_ring, 0, BCW_NRXDESC * sizeof(struct bcw_dma_slot));
+ /* enable receive */
+ BCW_WRITE32(regs, BCW_DMA_RXCTL,
+ BCW_PREPKT_HEADER_SIZE << 1 | 1);
+ BCW_WRITE32(regs, BCW_DMA_RXADDR,
+ sc->bcw_ring_map->dm_segs[0].ds_addr + 0x40000000); /* MAGIC */
+
+ /* Initalize receive descriptors */
+ for (i = 0; i < BCW_NRXDESC; i++) {
+ if (sc->bcw_cdata.bcw_rx_chain[i] == NULL) {
+ if ((error = bcw_add_rxbuf(sc, i)) != 0) {
+ printf("%s: unable to allocate or map rx(%d) "
+ "mbuf, error = %d\n", sc->bcw_dev.dv_xname,
+ i, error);
+ bcw_rxdrain(sc);
+ return (error);
+ }
+ } else
+ BCW_INIT_RXDESC(sc, i);
+ }
+
+ /* Enable interrupts */
+ sc->bcw_intmask =
+ I_XI | I_RI | I_XU | I_RO | I_RU | I_DE | I_PD | I_PC | I_TO;
+ BCW_WRITE32(regs, BCW_INT_MASK,
+ sc->bcw_intmask);
+
+ /* start the receive dma */
+ BCW_WRITE32(regs, BCW_DMA_RXDPTR,
+ BCW_NRXDESC * sizeof(struct bcw_dma_slot));
+
+ /* set media */
+// mii_mediachg(&sc->bcw_mii);
+
+ /* turn on the ethernet mac */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_ENET_CTL,
+// bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle,
+// BCW_ENET_CTL) | EC_EE);
+
+ /* start timer */
+ timeout_add(&sc->bcw_timeout, hz);
+
+ /* mark as running, and no outputs active */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return 0;
+}
+
+/* Add a receive buffer to the indiciated descriptor. */
+int
+bcw_add_rxbuf(struct bcw_softc *sc, int idx)
+{
+ struct mbuf *m;
+ int error;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ if (sc->bcw_cdata.bcw_rx_chain[idx] != NULL)
+ bus_dmamap_unload(sc->bcw_dmatag,
+ sc->bcw_cdata.bcw_rx_map[idx]);
+
+ sc->bcw_cdata.bcw_rx_chain[idx] = m;
+
+ error = bus_dmamap_load(sc->bcw_dmatag, sc->bcw_cdata.bcw_rx_map[idx],
+ m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
+ BUS_DMA_READ | BUS_DMA_NOWAIT);
+ if (error)
+ return (error);
+
+ bus_dmamap_sync(sc->bcw_dmatag, sc->bcw_cdata.bcw_rx_map[idx], 0,
+ sc->bcw_cdata.bcw_rx_map[idx]->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+ BCW_INIT_RXDESC(sc, idx);
+
+ return (0);
+
+}
+
+/* Drain the receive queue. */
+void
+bcw_rxdrain(struct bcw_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < BCW_NRXDESC; i++) {
+ if (sc->bcw_cdata.bcw_rx_chain[i] != NULL) {
+ bus_dmamap_unload(sc->bcw_dmatag,
+ sc->bcw_cdata.bcw_rx_map[i]);
+ m_freem(sc->bcw_cdata.bcw_rx_chain[i]);
+ sc->bcw_cdata.bcw_rx_chain[i] = NULL;
+ }
+ }
+}
+
+/* Stop transmission on the interface */
+void
+bcw_stop(struct ifnet *ifp, int disable)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+ struct bcw_regs *regs = &sc->bcw_regs;
+ int i;
+ //u_int32_t val;
+
+ /* Stop the 1 second timer */
+ timeout_del(&sc->bcw_timeout);
+
+ /* Mark the interface down and cancel the watchdog timer. */
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+
+ /* Disable interrupts. */
+ BCW_WRITE32(regs, BCW_INT_MASK, 0);
+ sc->bcw_intmask = 0;
+ delay(10);
+
+ /* Disable emac
+ bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_ENET_CTL, EC_ED);
+ for (i = 0; i < 200; i++) {
+ val = bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle,
+ BCW_ENET_CTL);
+ if (!(val & EC_ED))
+ break;
+ delay(10);
+ }
+ */
+ /* Stop the DMA */
+ BCW_WRITE32(regs, BCW_DMA_RXCTL, 0);
+ BCW_WRITE32(regs, BCW_DMA_TXCTL, 0);
+ delay(10);
+
+ /* Release any queued transmit buffers. */
+ for (i = 0; i < BCW_NTXDESC; i++) {
+ if (sc->bcw_cdata.bcw_tx_chain[i] != NULL) {
+ bus_dmamap_unload(sc->bcw_dmatag,
+ sc->bcw_cdata.bcw_tx_map[i]);
+ m_freem(sc->bcw_cdata.bcw_tx_chain[i]);
+ sc->bcw_cdata.bcw_tx_chain[i] = NULL;
+ }
+ }
+
+ /* drain receive queue */
+ if (disable)
+ bcw_rxdrain(sc);
+}
+
+/* reset the chip */
+void
+bcw_reset(sc)
+ struct bcw_softc *sc;
+{
+ struct bcw_regs *regs = &sc->bcw_regs;
+ u_int32_t val;
+ u_int32_t sbval;
+ int i;
+
+
+ /* if SB core is up, only clock of clock,reset,reject will be set */
+ sbval = BCW_READ32(regs, BCW_SBTMSTATELOW);
+
+ /* The core isn't running if the if the clock isn't enabled */
+ if ((sbval & (SBTML_RESET | SBTML_REJ | SBTML_CLK)) == SBTML_CLK) {
+
+ // Stop all DMA
+ BCW_WRITE32(regs, BCW_DMAI_CTL, 0);
+
+ /* reset the dma engines */
+ BCW_WRITE32(regs, BCW_DMA_TXCTL, 0);
+ val = BCW_READ32(regs, BCW_DMA_RXSTATUS);
+ /* if error on receive, wait to go idle */
+ if (val & RS_ERROR) {
+ for (i = 0; i < 100; i++) {
+ val = BCW_READ32(regs, BCW_DMA_RXSTATUS);
+ if (val & RS_DMA_IDLE)
+ break;
+ delay(10);
+ }
+ if (i == 100)
+ printf("%s: receive dma did not go idle after"
+ " error\n", sc->bcw_dev.dv_xname);
+ }
+ BCW_WRITE32(regs, BCW_DMA_RXSTATUS, 0);
+
+ /* reset ethernet mac
+ bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_ENET_CTL,
+ EC_ES);
+ for (i = 0; i < 200; i++) {
+ val = bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle,
+ BCW_ENET_CTL);
+ if (!(val & EC_ES))
+ break;
+ delay(10);
+ }
+ if (i == 200)
+ printf("%s: timed out resetting ethernet mac\n",
+ sc->bcw_dev.dv_xname);
+ */
+ } else {
+ u_int32_t reg_win;
+
+ /* remap the pci registers to the Sonics config registers */
+
+ /* save the current map, so it can be restored */
+ reg_win = BCW_READ32(regs, BCW_REG0_WIN);
+ /* set register window to Sonics registers */
+ BCW_WRITE32(regs, BCW_REG0_WIN, BCW_SONICS_WIN);
+
+ /* enable SB to PCI interrupt */
+ BCW_WRITE32(regs, BCW_SBINTVEC,
+ BCW_READ32(regs,
+ BCW_SBINTVEC) |
+ SBIV_ENET0);
+
+ /* enable prefetch and bursts for sonics-to-pci translation 2 */
+ BCW_WRITE32(regs, BCW_SPCI_TR2,
+ BCW_READ32(regs,
+ BCW_SPCI_TR2) |
+ SBTOPCI_PREF | SBTOPCI_BURST);
+
+ /* restore to ethernet register space */
+ BCW_WRITE32(regs, BCW_REG0_WIN, reg_win);
+ }
+
+ /* disable SB core if not in reset */
+ if (!(sbval & SBTML_RESET)) {
+
+ /* set the reject bit */
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW, SBTML_REJ | SBTML_CLK);
+ for (i = 0; i < 200; i++) {
+ val = BCW_READ32(regs, BCW_SBTMSTATELOW);
+ if (val & SBTML_REJ)
+ break;
+ delay(1);
+ }
+ if (i == 200)
+ printf("%s: while resetting core, reject did not set\n",
+ sc->bcw_dev.dv_xname);
+ /* wait until busy is clear */
+ for (i = 0; i < 200; i++) {
+ val = BCW_READ32(regs, BCW_SBTMSTATEHI);
+ if (!(val & 0x4))
+ break;
+ delay(1);
+ }
+ if (i == 200)
+ printf("%s: while resetting core, busy did not clear\n",
+ sc->bcw_dev.dv_xname);
+ /* set reset and reject while enabling the clocks */
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW,
+ SBTML_FGC | SBTML_CLK | SBTML_REJ | SBTML_RESET | SBTML_80211FLAG );
+ val = BCW_READ32(regs, BCW_SBTMSTATELOW);
+ delay(10);
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW, SBTML_REJ | SBTML_RESET);
+ delay(1);
+ }
+ // This is enabling/resetting the core
+ /* enable clock */
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW,
+ SBTML_FGC | SBTML_CLK | SBTML_RESET |
+ SBTML_80211FLAG | SBTML_80211PHY );
+ val = BCW_READ32(regs, BCW_SBTMSTATELOW);
+ delay(1);
+
+ /* clear any error bits that may be on */
+ val = BCW_READ32(regs, BCW_SBTMSTATEHI);
+ if (val & 1)
+ BCW_WRITE32(regs, BCW_SBTMSTATEHI, 0);
+ val = BCW_READ32(regs, BCW_SBIMSTATE);
+ if (val & SBIM_MAGIC_ERRORBITS)
+ BCW_WRITE32(regs, BCW_SBIMSTATE,
+ val & ~SBIM_MAGIC_ERRORBITS);
+
+ /* clear reset and allow it to propagate throughout the core */
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW,
+ SBTML_FGC | SBTML_CLK | SBTML_80211FLAG | SBTML_80211PHY );
+ val = BCW_READ32(regs, BCW_SBTMSTATELOW);
+ delay(1);
+
+ /* leave clock enabled */
+ BCW_WRITE32(regs, BCW_SBTMSTATELOW,
+ SBTML_CLK | SBTML_80211FLAG | SBTML_80211PHY);
+ val = BCW_READ32(regs, BCW_SBTMSTATELOW);
+ delay(1);
+
+ /* Write a 0 to MMIO reg 0x3e6, Baseband attenuation */
+ BCW_WRITE16(regs, 0x3e6,0);
+
+ /* Set 0x400 in the MMIO StatusBitField reg */
+ sbval=BCW_READ32(regs, 0x120);
+ sbval |= 0x400;
+ BCW_WRITE32(regs, 0x120, sbval);
+
+// /* initialize MDC preamble, frequency */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_MI_CTL, 0x8d); /* MAGIC */
+
+ /* enable phy, differs for internal, and external */
+// val = bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle, BCW_DEVCTL);
+// if (!(val & BCW_DC_IP)) {
+ /* select external phy */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_ENET_CTL, EC_EP);
+// } else if (val & BCW_DC_ER) { /* internal, clear reset bit if on */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_DEVCTL,
+// val & ~BCW_DC_ER);
+// delay(100);
+// }
+}
+
+/* Set up the receive filter. */
+void
+bcw_set_filter(struct ifnet *ifp)
+{
+// struct bcw_softc *sc = ifp->if_softc;
+
+// if (ifp->if_flags & IFF_PROMISC) {
+// ifp->if_flags |= IFF_ALLMULTI;
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_RX_CTL,
+// bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle, BCW_RX_CTL)
+// | ERC_PE);
+// } else {
+// ifp->if_flags &= ~IFF_ALLMULTI;
+
+ /* turn off promiscuous */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_RX_CTL,
+// bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle,
+// BCW_RX_CTL) & ~ERC_PE);
+
+ /* enable/disable broadcast */
+// if (ifp->if_flags & IFF_BROADCAST)
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle,
+// BCW_RX_CTL, bus_space_read_4(sc->bcw_btag,
+// sc->bcw_bhandle, BCW_RX_CTL) & ~ERC_DB);
+// else
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle,
+// BCW_RX_CTL, bus_space_read_4(sc->bcw_btag,
+// sc->bcw_bhandle, BCW_RX_CTL) | ERC_DB);
+
+ /* disable the filter */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_FILT_CTL,
+// 0);
+
+ /* add our own address */
+// bcw_add_mac(sc, sc->bcw_ac.ac_enaddr, 0);
+
+ /* for now accept all multicast */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_RX_CTL,
+// bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle, BCW_RX_CTL) |
+// ERC_AM);
+// ifp->if_flags |= IFF_ALLMULTI;
+
+ /* enable the filter */
+// bus_space_write_4(sc->bcw_btag, sc->bcw_bhandle, BCW_FILT_CTL,
+// bus_space_read_4(sc->bcw_btag, sc->bcw_bhandle,
+// BCW_FILT_CTL) | 1);
+// }
+}
+
+int
+bcw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+// struct bcw_softc *sc = ic->ic_softc;
+// enum ieee80211_state ostate;
+// uint32_t tmp;
+
+// ostate = ic->ic_state;
+ return 0;
+}
+
+int
+bcw_media_change(struct ifnet *ifp)
+{
+ int error;
+
+ error = ieee80211_media_change(ifp);
+ if (error != ENETRESET)
+ return error;
+
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
+ bcw_init(ifp);
+
+ return 0;
+}
+
+void
+bcw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
+{
+ struct bcw_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->bcw_ic;
+// uint32_t val;
+ int rate;
+
+ imr->ifm_status = IFM_AVALID;
+ imr->ifm_active = IFM_IEEE80211;
+ if (ic->ic_state == IEEE80211_S_RUN)
+ imr->ifm_status |= IFM_ACTIVE;
+
+ /*
+ * XXX Read current transmission rate from the adapter.
+ */
+// val = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE);
+ /* convert PLCP signal to 802.11 rate */
+// rate = bcw_rate(val);
+ rate = 0;
+
+ imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode);
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ break;
+ case IEEE80211_M_IBSS:
+ imr->ifm_active |= IFM_IEEE80211_ADHOC;
+ break;
+ case IEEE80211_M_MONITOR:
+ imr->ifm_active |= IFM_IEEE80211_MONITOR;
+ break;
+ case IEEE80211_M_AHDEMO:
+ case IEEE80211_M_HOSTAP:
+ /* should not get there */
+ break;
+ }
+}
+
+/* One second timer, checks link status */
+void
+bcw_tick(void *v)
+{
+// struct bcw_softc *sc = v;
+// http://bcm-specs.sipsolutions.net/PeriodicTasks
+// timeout_add(&sc->bcw_timeout, hz);
+
+
+}
+
+/*
+ * Validate Chip Access
+ */
+
+int
+bcw_validatechipaccess(struct bcw_softc *sc)
+{
+ struct bcw_regs *regs = &sc->bcw_regs;
+ u_int32_t save,val;
+
+ /*
+ * We use the offset of zero a lot here to reset the SHM pointer to the
+ * beginning of it's memory area, as it automatically moves on every
+ * access to the SHM DATA registers
+ */
+
+ /* Backup SHM uCode Revision before we clobber it */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL,
+ (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ save = BCW_READ32(regs, BCW_SHM_DATA);
+
+ /* write test value */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL, (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ BCW_WRITE32(regs, BCW_SHM_DATA, 0xaa5555aa);
+ DPRINTF(("Write test 1, "));
+ /* Read it back */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL, (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ val = BCW_READ32(regs, BCW_SHM_DATA);
+ DPRINTF(("Read test 1, "));
+ if (val != 0xaa5555aa) {
+ DPRINTF(("Failed test 1\n"));
+ return 1;
+ } else {
+ DPRINTF(("Passed test 1\n"));
+ }
+
+ /* write 2nd test value */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL, (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ BCW_WRITE32(regs, BCW_SHM_DATA, 0x55aaaa55);
+ DPRINTF(("Write test 2, "));
+ /* Read it back */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL, (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ val = BCW_READ32(regs, BCW_SHM_DATA);
+ DPRINTF(("Read test 2, "));
+ if (val != 0x55aaaa55) {
+ DPRINTF(("Failed test 2\n"));
+ return 2;
+ } else {
+ DPRINTF(("Passed test 2\n"));
+ }
+
+ /* Restore the saved value now that we're done */
+ BCW_WRITE32(regs, BCW_SHM_CONTROL, (BCW_SHM_CONTROL_SHARED << 16) + 0);
+ BCW_WRITE32(regs, BCW_SHM_DATA, save);
+
+ if (sc->bcw_corerev >= 3) {
+ DPRINTF(("Doing corerev >= 3 tests\n"));
+ /* do some test writes and reads against the TSF */
+ /*
+ * This works during the attach, but the spec at
+ * http://bcm-specs.sipsolutions.net/Timing
+ * say that we're reading/writing silly places, so these regs
+ * are not quite documented yet
+ */
+ BCW_WRITE16(regs, 0x18c, 0xaaaa);
+ BCW_WRITE32(regs, 0x18c, 0xccccbbbb);
+ val = BCW_READ16(regs, 0x604);
+ if (val != 0xbbbb) return 3;
+ val = BCW_READ16(regs, 0x606);
+ if (val != 0xcccc) return 4;
+ /* re-clear the TSF since we just filled it with garbage */
+ BCW_WRITE32(regs, 0x18c, 0x0);
+ }
+
+ /* Check the Status Bit Field for some unknown bits */
+ val = BCW_READ32(regs, BCW_SBF);
+ if ((val | 0x80000000) != 0x80000400 ) {
+ printf("%s: Warning, SBF is 0x%x, expected 0x80000400\n",
+ sc->bcw_dev.dv_xname,val);
+ /* May not be a critical failure, just warn for now */
+ //return 5;
+ }
+ /* Verify there are no interrupts active on the core */
+ val = BCW_READ32(regs, BCW_GIR);
+ if (val!=0) {
+ DPRINTF(("Failed Pending Interrupt test with val=0x%x\n",val));
+ return 6;
+ }
+
+ /* Above G means it's unsupported currently, like N */
+ if (sc->bcw_phy_type > BCW_PHY_TYPEG) {
+ DPRINTF(("PHY type %d greater than supported type %d\n",
+ sc->bcw_phy_type, BCW_PHY_TYPEG));
+ return 7;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Abstracted reads and writes - from rtw
+ */
+u_int8_t
+bcw_read8(void *arg, u_int32_t off)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ return (bus_space_read_1(regs->r_bt, regs->r_bh, off));
+}
+
+u_int16_t
+bcw_read16(void *arg, u_int32_t off)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ return (bus_space_read_2(regs->r_bt, regs->r_bh, off));
+}
+
+u_int32_t
+bcw_read32(void *arg, u_int32_t off)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ return (bus_space_read_4(regs->r_bt, regs->r_bh, off));
+}
+
+void
+bcw_write8(void *arg, u_int32_t off, u_int8_t val)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ bus_space_write_1(regs->r_bt, regs->r_bh, off, val);
+}
+
+void
+bcw_write16(void *arg, u_int32_t off, u_int16_t val)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ bus_space_write_2(regs->r_bt, regs->r_bh, off, val);
+}
+
+void
+bcw_write32(void *arg, u_int32_t off, u_int32_t val)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ bus_space_write_4(regs->r_bt, regs->r_bh, off, val);
+}
+
+void
+bcw_barrier(void *arg, u_int32_t reg0, u_int32_t reg1, int flags)
+{
+ struct bcw_regs *regs = (struct bcw_regs *)arg;
+ bus_space_barrier(regs->r_bh, regs->r_bt, MIN(reg0, reg1),
+ MAX(reg0, reg1) - MIN(reg0, reg1) + 4, flags);
+}
diff --git a/sys/dev/ic/bcwreg.h b/sys/dev/ic/bcwreg.h
new file mode 100644
index 00000000000..279ecc25ff2
--- /dev/null
+++ b/sys/dev/ic/bcwreg.h
@@ -0,0 +1,277 @@
+/* $OpenBSD: bcwreg.h,v 1.1 2006/11/17 18:58:31 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/* Broadcom BCM43xx */
+
+/* PCI registers defined in the PCI 2.2 spec. */
+#define BCW_PCI_BAR0 0x10
+
+/* Saved Interrupt mask */
+#define BCW_SAVEDINTRMASK 0xb007a864
+
+/* Sonics SB register access */
+#define BCW_ADDR_SPACE0 0x80
+#define BCW_ADDR_SPACE1 0x84
+#define BCW_REG0_WIN 0x80
+#define BCW_REG1_WIN 0x84
+#define BCW_SPROM_CONTROL 0x88
+#define BCW_ADDR1_BURST_CONTROL 0x8C
+#define BCW_PCII 0x90
+#define BCW_PCICR 0x94
+#define BCW_BI 0x98
+#define BCW_PCICI 0xB0
+#define BCW_PCICO 0xB4
+#define BCW_PCICOE 0xB8
+#define BCW_GPIOI 0xB0 /* GPIO IN */
+#define BCW_GPIOO 0xB4 /* GPIO OUT */
+#define BCW_GPIOE 0xB8 /* GPIO ENABLE */
+
+/* Some bitmasks */
+#define BCW_XTALPOWERUP 0x40
+#define BCW_PLLPOWERDOWN 0x80
+
+/* Core select address macro */
+#define BCW_CORE_SELECT(x) (0x18000000 + (x * 0x1000))
+
+/* Some Core Types */
+#define BCW_CORE_COMMON 0x800
+#define BCW_CORE_PCI 0x804
+#define BCW_CORE_ENET 0x806
+#define BCW_CORE_80211 0x812
+#define BCW_CORE_PCIE 0x820
+#define BCW_CORE_MIMOPHY 0x821
+
+#define BCW_CORE_COMMON_CHIPID 0x0
+
+/* Core Info Registers */
+#define BCW_CIR_SBID_HI 0xffc
+#define BCW_CIR_SBID_LO 0xff8
+
+#define BCW_SBTMSTATELOW 0x0f98
+#define BCW_SBTMSTATEHI 0x0f9C
+
+#define BCW_SONICS_WIN 0x18002000
+
+/* Sonics PCI control */
+#define BCW_SPCI_TR2 0x0108 /* Sonics to PCI translation
+ * 2 */
+/* bit defines */
+#define SBTOPCI_PREF 0x4 /* prefetch enable */
+#define SBTOPCI_BURST 0x8 /* burst enable */
+#define BCW_SBINTVEC 0x0f94
+/* interrupt bits */
+#define SBIV_ENET0 0x02 /* enable for enet 0 */
+#define SBIV_ENET1 0x40 /* enable for enet 1 */
+
+
+/* Host Interface Registers */
+
+#define BCW_DEVCTL 0x0000 /* device control */
+/* device control bits */
+#define BCW_DC_IP 0x00000400 /* internal phy present */
+#define BCW_DC_ER 0x00008000 /* ephy reset */
+/* Interrupt Control */
+#define BCW_INT_STS 0x0020
+#define BCW_INT_MASK 0x0024
+/* bits for both status, and mask */
+#define I_TO 0x00000080 /* general timeout */
+#define I_PC 0x00000400 /* descriptor error */
+#define I_PD 0x00000800 /* data error */
+#define I_DE 0x00001000 /* desc. protocol error */
+#define I_RU 0x00002000 /* rx desc. underflow */
+#define I_RO 0x00004000 /* rx fifo overflow */
+#define I_XU 0x00008000 /* tx fifo underflow */
+#define I_RI 0x00010000 /* receive interrupt */
+#define I_XI 0x01000000 /* transmit interrupt */
+
+/* Ethernet MAC Control */
+#define BCW_MACCTL 0x00A8 /* ethernet mac control */
+/* mac control bits */
+#define BCW_EMC_CRC32_ENAB 0x00000001 /* crc32 generation */
+#define BCW_EMC_PDOWN 0x00000004 /* PHY powerdown */
+#define BCW_EMC_EDET 0x00000008 /* PHY energy detect */
+#define BCW_EMC_LED 0x000000e0 /* PHY LED control */
+
+/* DMA Interrupt control */
+#define BCW_DMAI_CTL 0x0100
+
+/* DMA registers */
+#define BCW_DMA_TXCTL 0x0200 /* transmit control */
+/* transmit control bits */
+#define XC_XE 0x1 /* transmit enable */
+#define XC_LE 0x4 /* loopback enable */
+#define BCW_DMA_TXADDR 0x0204 /* tx ring base address */
+#define BCW_DMA_DPTR 0x0208 /* last tx descriptor */
+#define BCW_DMA_TXSTATUS 0x020C /* active desc, etc */
+#define BCW_DMA_RXCTL 0x0210 /* enable, etc */
+#define BCW_DMA_RXADDR 0x0214 /* rx ring base address */
+#define BCW_DMA_RXDPTR 0x0218 /* last descriptor */
+#define BCW_DMA_RXSTATUS 0x021C /* active desc, etc */
+/* receive status bits */
+#define RS_CD_MASK 0x0fff /* current descriptor pointer */
+#define RS_DMA_IDLE 0x2000 /* DMA is idle */
+#define RS_ERROR 0xf0000 /* had an error */
+
+/* Ethernet MAC control registers */
+#define BCW_RX_CTL 0x0400 /* receive config */
+/* config bits */
+#define ERC_DB 0x00000001 /* disable broadcast */
+#define ERC_AM 0x00000002 /* rx all multicast */
+#define ERC_PE 0x00000008 /* promiscuous enable */
+
+#define BCW_RX_MAX 0x0404 /* max packet length */
+#define BCW_TX_MAX 0x0408
+#define BCW_MI_CTL 0x0410
+#define BCW_MI_COMM 0x0414
+#define BCW_MI_STS 0x041C
+/* mii status bits */
+#define BCW_MIINTR 0x00000001 /* mii mdio interrupt */
+
+#define BCW_FILT_LOW 0x0420 /* mac low 4 bytes */
+#define BCW_FILT_HI 0x0424 /* mac hi 2 bytes */
+#define BCW_FILT_CTL 0x0428 /* packet filter ctrl */
+#define BCW_ENET_CTL 0x042C
+/* bits for mac control */
+#define EC_EE 0x00000001 /* emac enable */
+#define EC_ED 0x00000002 /* disable emac */
+#define EC_ES 0x00000004 /* soft reset emac */
+#define EC_EP 0x00000008 /* external phy */
+#define BCW_TX_CTL 0x0430
+/* bits for transmit control */
+#define EXC_FD 0x00000001 /* full duplex */
+#define BCW_TX_WATER 0x0434 /* tx watermark */
+
+/* statistics counters */
+#define BCW_RX_PKTS 0x058C
+
+/* SiliconBackplane registers */
+#define BCW_SBIMSTATE 0x0f90
+#define BCW_SBTMSTATELOW 0x0f98
+#define BCW_SBTMSTATEHI 0x0f9C
+#define SBTML_RESET 0x1 /* reset */
+#define SBTML_REJ 0x6 /* reject */
+#define SBTML_CLK 0x10000 /* clock enable */
+#define SBTML_FGC 0x20000 /* force gated clocks on */
+#define SBTML_80211FLAG 0x40000 /* core specific flag */
+#define SBTML_80211PHY 0x20000000 /* Attach PHY */
+#define SBTMH_BUSY 0x4
+
+#define SBIM_MAGIC_ERRORBITS 0x60000
+
+/*
+ * MMIO Registers by offset, followed by indented bitmasks
+ */
+#define BCW_SPROM_CONTROL 0x88 /* SPROM Control register */
+
+#define BCW_SBF 0x120 /* MIMO - Status Bit Field */
+#define BCW_SBF_MAC_ENABLED 0x00000001 /* Set when mac enabled */
+#define BCW_SBF_CORE_READY 0x00000004 /* set after core reset/enabled */
+#define BCW_SBF_REGISTER_BYTESWAP 0x00010000 /* xfer regs are byteswapped in hw */
+#define BCW_SBF_ADHOC 0x00020000 /* Operating mode is not adhoc */
+#define BCW_SBF_AP 0x00040000 /* Device is in AP mode */
+#define BCW_SBF_RADIOREG_LOCK 0x00080000 /* Radio Registers locked for use */
+#define BCW_SBF_MONITOR 0x00400000 /* Pass HW handled control frames
+ * to driver, needs PROMISC also */
+#define BCW_SBF_PROMISC 0x01000000 /* Device is in promiscuous mode */
+#define BCW_SBF_PS1 0x02000000 /* Power saving bit 1 - unknown */
+#define BCW_SBF_PS2 0x04000000 /* bit 2 - Device is awake */
+#define BCW_SBF_SSID_BCAST 0x08000000 /* set = SSID bcast is disabled
+ * unset = SSID bcast enabled */
+#define BCW_SBF_TIME_UPDATE 0x10000000 /* Related to TSF updates */
+
+#define BCW_GIR 0x128 /* MIMO - Generic Interrupt Reason */
+
+#define BCW_SHM_CONTROL 0x160 /* Control */
+#define BCW_SHM_DATA 0x164 /* Data - 32bit */
+#define BCW_SHM_DATALOW 0x164 /* Data Low - 16bit */
+#define BCW_SHM_DATAHIGH 0x166 /* Data High - 16 bit */
+#define BCW_SHM_CONTROL_SHARED 0x0001 /* Select SHM Routing shared memory */
+#define BCW_SHM_CONTROL_80211 0x0002 /* Select 80211 settings */
+#define BCW_SHM_CONTROL_PCM 0x0003 /* Select PCM data */
+#define BCW_SHM_CONTROL_HWMAC 0x0004 /* Security Hardware MAC Address list */
+#define BCW_SHM_CONTROL_MCODE 0x0300 /* Microcode */
+#define BCW_SHM_CONTROL_INIMCODE 0x0301 /* Initial Value Microcode? */
+/* SHM Addresses */
+#define BCW_SHM_MICROCODEFLAGSLOW 0x005e /* Flags for Microcode ops */
+#define BCW_SHM_MICROCODEFLAGSHIGH 0x0060 /* Flags for Microcode ops */
+/* http://bcm-specs.sipsolutions.net/MicrocodeFlagsBitfield */
+#define BCW_SHM_MICROCODEFLAGS
+
+/* 0x200 DMA Register space */
+/* 0x300 PIO Register space */
+
+#define BCW_RADIO_CONTROL 0x3f6 /* Control - 16bit */
+#define BCW_RADIO_DATA 0x3fa /* Data - 16bit */
+#define BCW_RADIO_DATALOW 0x3fa /* Data Low - 16bit */
+#define BCW_RADIO_DATAHIGH 0x3f8 /* Data High - 16 bit */
+#define BCW_RADIO_ID 0x01 /* Radio ID offset */
+
+#define BCW_PHY_CONTROL 0x3fc /* Control - 16bit */
+#define BCW_PHY_DATA 0x3fe /* Data - 16bit */
+
+/* SPROM registers are 16 bit and based at MMIO offset 0x1000 */
+#define BCW_MMIO_BASE 0x1000
+
+#define BCW_SPROM_IL0MACADDR 0x1048 /* 802.11b/g MAC */
+#define BCW_SPROM_ET0MACADDR 0x104e /* ethernet MAC */
+#define BCW_SPROM_ET1MACADDR 0x1054 /* 802.11a MAC */
+
+
+#define BCW_SPROM_PA0B0 0x105e
+#define BCW_SPROM_PA0B1 0x1060
+#define BCW_SPROM_PA0B2 0x1062
+#define BCW_SPROM_PAMAXPOWER 0x1066 /* 7-0 for A, 15-8 for B/G */
+#define BCW_SPROM_PA1B0 0x106a
+#define BCW_SPROM_PA1B1 0x106c
+#define BCW_SPROM_PA1B2 0x106e
+#define BCW_SPROM_IDLETSSI 0x1070 /* As below */
+#define BCW_SPROM_ANTGAIN 0x1074 /* bits 7-0 for an A PHY
+ bits 15-8 for B/G PHYs */
+
+
+
+
+#define BCW_PHY_TYPEA 0x0 /* 802.11a PHY */
+#define BCW_PHY_TYPEB 0x1 /* 802.11b PHY */
+#define BCW_PHY_TYPEG 0x2 /* 802.11g PHY */
+#define BCW_PHY_TYPEN 0x4 /* 802.11n PHY */
+
+#define BCW_READ8(regs, ofs) \
+ ((*(regs)->r_read8)(regs, ofs))
+
+#define BCW_READ16(regs, ofs) \
+ ((*(regs)->r_read16)(regs, ofs))
+
+#define BCW_READ32(regs, ofs) \
+ ((*(regs)->r_read32)(regs, ofs))
+
+#define BCW_WRITE8(regs, ofs, val) \
+ ((*(regs)->r_write8)(regs, ofs, val))
+
+#define BCW_WRITE16(regs, ofs, val) \
+ ((*(regs)->r_write16)(regs, ofs, val))
+
+#define BCW_WRITE32(regs, ofs, val) \
+ ((*(regs)->r_write32)(regs, ofs, val))
+
+#define BCW_ISSET(regs, reg, mask) \
+ (BCW_READ32((regs), (reg)) & (mask))
+
+#define BCW_CLR(regs, reg, mask) \
+ BCW_WRITE32((regs), (reg), BCW_READ32((regs), (reg)) & ~(mask))
+
diff --git a/sys/dev/ic/bcwvar.h b/sys/dev/ic/bcwvar.h
new file mode 100644
index 00000000000..91960c11254
--- /dev/null
+++ b/sys/dev/ic/bcwvar.h
@@ -0,0 +1,216 @@
+/* $OpenBSD: bcwvar.h,v 1.1 2006/11/17 18:58:31 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
+ * Copyright (c) 2003 Clifford Wright. 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.
+ */
+
+/*
+ * Broadcom BCM43xx Wireless network chipsets (broadcom.com)
+ * SiliconBackplane is technology from Sonics, Inc.(sonicsinc.com)
+ *
+ * Cliff Wright cliff@snipe444.org
+ */
+
+
+#define BCW_MAX_RADIOS 2
+struct bcw_radio {
+ u_int16_t id;
+ u_int16_t info;
+ u_char enabled;
+};
+
+#define BCW_MAX_CORES 10
+struct bcw_core {
+ u_int16_t id;
+ u_int16_t revision;
+ u_char enabled;
+};
+
+/* number of descriptors used in a ring */
+#define BCW_NRXDESC 128
+#define BCW_NTXDESC 128
+/*
+* 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.
+*
+* The chip has 6 DMA engines, looks like we only need to use one each
+* for TX and RX, the others stay disabled.
+*/
+struct bcw_chain_data {
+ struct mbuf *bcw_tx_chain[BCW_NTXDESC];
+ struct mbuf *bcw_rx_chain[BCW_NRXDESC];
+ bus_dmamap_t bcw_tx_map[BCW_NTXDESC];
+ bus_dmamap_t bcw_rx_map[BCW_NRXDESC];
+};
+
+struct bcw_regs {
+ bus_space_tag_t r_bt;
+ bus_space_handle_t r_bh;
+// enum bcw_access r_access;
+ void *r_priv;
+
+ /* bus independent I/O callbacks */
+ u_int8_t (*r_read8)(void *, u_int32_t);
+ u_int16_t (*r_read16)(void *, u_int32_t);
+ u_int32_t (*r_read32)(void *, u_int32_t);
+ void (*r_write8)(void *, u_int32_t, u_int8_t);
+ void (*r_write16)(void *, u_int32_t, u_int16_t);
+ void (*r_write32)(void *, u_int32_t, u_int32_t);
+ void (*r_barrier)(void *, u_int32_t, u_int32_t, int);
+};
+/* Needs to have garbage removed */
+struct bcw_softc {
+ struct device bcw_dev;
+ struct ieee80211com bcw_ic;
+ struct bcw_regs bcw_regs;
+ int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
+ int (*sc_enable)(struct bcw_softc *);
+ void (*sc_disable)(struct bcw_softc *);
+ bus_space_tag_t bcw_btag;
+ bus_space_handle_t bcw_bhandle;
+ bus_dma_tag_t bcw_dmatag;
+ struct arpcom bcw_ac; /* interface info */
+ void *bcw_intrhand;
+ const char *bcw_intrstr; /* interrupt description */
+ struct pci_attach_args bcw_pa;
+ u_int32_t bcw_phy; /* eeprom indicated phy */
+ struct bcw_dma_slot *bcw_rx_ring; /* receive ring */
+ struct bcw_dma_slot *bcw_tx_ring; /* transmit ring */
+ struct bcw_chain_data bcw_cdata; /* mbufs */
+ bus_dmamap_t bcw_ring_map;
+ u_int32_t bcw_intmask; /* current intr mask */
+ u_int32_t bcw_rxin; /* last rx descriptor seen */
+ u_int32_t bcw_txin; /* last tx descriptor seen */
+ int bcw_txsfree; /* no. tx slots available */
+ int bcw_txsnext; /* next available tx slot */
+ struct timeout bcw_timeout;
+ /* Break these out into seperate structs */
+ u_int16_t bcw_chipid; /* Chip ID */
+ u_int16_t bcw_chiprev; /* Chip Revision */
+ u_int16_t bcw_prodid; /* Product ID */
+// struct bcw_core core[BCW_MAX_CORES];
+// struct bcw_radio radio[BCW_MAX_RADIOS];
+ u_int16_t bcw_phy_version;
+ u_int16_t bcw_phy_type;
+ u_int16_t bcw_phy_rev;
+ u_int16_t bcw_corerev;
+ u_int32_t bcw_radioid;
+ u_int16_t bcw_radiorev;
+ u_int16_t bcw_radiotype;
+ u_int32_t bcw_phyinfo;
+ u_int16_t bcw_numcores;
+ u_int16_t bcw_havecommon;
+ u_int8_t bcw_radio_gain;
+ u_int16_t bcw_radio_pa0b0;
+ u_int16_t bcw_radio_pa0b1;
+ u_int16_t bcw_radio_pa0b2;
+ u_int16_t bcw_radio_pa1b0;
+ u_int16_t bcw_radio_pa1b1;
+ u_int16_t bcw_radio_pa1b2;
+ u_int8_t bcw_idletssi;
+};
+
+void bcw_attach(struct bcw_softc *);
+int bcw_intr(void *);
+
+#define BCW_DEBUG
+#ifdef BCW_DEBUG
+//#define DPRINTF(x) do { if (bcw_debug) printf x; } while (0)
+//#define DPRINTFN(n,x) do { if (bcwdebug >= (n)) printf x; } while (0)
+#define DPRINTF(x) do { if (1) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (1 >= (n)) printf x; } while (0)
+//int bcw_debug = 99;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+/*
+ * Some legacy stuff from bce and iwi to make this compile
+ */
+/* transmit buffer max frags allowed */
+#define BCW_NTXFRAGS 16
+
+/* ring descriptor */
+struct bcw_dma_slot {
+ u_int32_t ctrl;
+ u_int32_t addr;
+};
+
+#define CTRL_BC_MASK 0x1fff /* buffer byte count */
+#define CTRL_EOT 0x10000000 /* end of descriptor table */
+#define CTRL_IOC 0x20000000 /* interrupt on completion */
+#define CTRL_EOF 0x40000000 /* end of frame */
+#define CTRL_SOF 0x80000000 /* start of frame */
+
+/* Packet status is returned in a pre-packet header */
+struct rx_pph {
+ u_int16_t len;
+ u_int16_t flags;
+ u_int16_t pad[12];
+};
+
+#define BCW_PREPKT_HEADER_SIZE 30
+
+/* packet status flags bits */
+#define RXF_NO 0x8 /* odd number of nibbles */
+#define RXF_RXER 0x4 /* receive symbol error */
+#define RXF_CRC 0x2 /* crc error */
+#define RXF_OV 0x1 /* fifo overflow */
+
+#define BCW_TIMEOUT 100 /* # 10us for mii read/write */
+
+/* for ring descriptors */
+#define BCW_RXBUF_LEN (MCLBYTES - 4)
+#define BCW_INIT_RXDESC(sc, x) \
+do { \
+ struct bcw_dma_slot *__bcwd = &sc->bcw_rx_ring[x]; \
+ \
+ *mtod(sc->bcw_cdata.bcw_rx_chain[x], u_int32_t *) = 0; \
+ __bcwd->addr = \
+ htole32(sc->bcw_cdata.bcw_rx_map[x]->dm_segs[0].ds_addr \
+ + 0x40000000); \
+ if (x != (BCW_NRXDESC - 1)) \
+ __bcwd->ctrl = htole32(BCW_RXBUF_LEN); \
+ else \
+ __bcwd->ctrl = htole32(BCW_RXBUF_LEN | CTRL_EOT); \
+ bus_dmamap_sync(sc->bcw_dmatag, sc->bcw_ring_map, \
+ sizeof(struct bcw_dma_slot) * x, \
+ sizeof(struct bcw_dma_slot), \
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+} while (/* CONSTCOND */ 0)
+
+#define BCW_NTXFRAGS 16
+
+static const struct ieee80211_rateset bcw_rateset_11a =
+ { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
+static const struct ieee80211_rateset bcw_rateset_11b =
+ { 4, { 2, 4, 11, 22 } };
+static const struct ieee80211_rateset bcw_rateset_11g =
+ { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+