Author: imp
Date: Sun May  3 04:01:43 2009
New Revision: 191762
URL: http://svn.freebsd.org/changeset/base/191762

Log:
  Bring in Andrew Thompson's port of Sepherosa Ziehau's bwi driver for
  Broadcom BCM43xx chipsets.  This driver uses the v3 firmware that
  needs to be fetched separately.  A port will be committed to create
  the bwi firmware module.
  
  The driver matches the following chips: Broadcom BCM4301, BCM4307,
  BCM4306, BCM4309, BCM4311, BCM4312, BCM4318, BCM4319
  
  The driver works for 802.11b and 802.11g.
  
  Limitations:
        This doesn't support the 802.11a or 802.11n portion of radios.
        Some BCM4306 and BCM4309 cards don't work with Channel 1, 2 or 3.
        Documenation for this firmware is reverse engineered from
                 http://bcm.sipsolutions.net/
        V4 of the firmware is needed for 11a or 11n support
                 http://bcm-v4.sipsolutions.net/
        Firmware needs to be fetched from a third party, port to be committed
  
  # I've tested this with a BCM4319 mini-pci and a BCM4318 CardBus card, and
  # not connected it to the build until the firmware port is committed.
  
  Obtained from:        DragonFlyBSD, //depot/projects/vap
  Reviewed by:  sam@, thompsa@

Added:
  head/sys/dev/bwi/
  head/sys/dev/bwi/bitops.h   (contents, props changed)
  head/sys/dev/bwi/bwimac.c   (contents, props changed)
  head/sys/dev/bwi/bwimac.h   (contents, props changed)
  head/sys/dev/bwi/bwiphy.c   (contents, props changed)
  head/sys/dev/bwi/bwiphy.h   (contents, props changed)
  head/sys/dev/bwi/bwirf.c   (contents, props changed)
  head/sys/dev/bwi/bwirf.h   (contents, props changed)
  head/sys/dev/bwi/if_bwi.c   (contents, props changed)
  head/sys/dev/bwi/if_bwi_pci.c   (contents, props changed)
  head/sys/dev/bwi/if_bwireg.h   (contents, props changed)
  head/sys/dev/bwi/if_bwivar.h   (contents, props changed)
  head/sys/modules/bwi/
  head/sys/modules/bwi/Makefile   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/conf/options

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Sun May  3 02:37:13 2009        (r191761)
+++ head/sys/conf/files Sun May  3 04:01:43 2009        (r191762)
@@ -712,6 +712,11 @@ dev/buslogic/bt_eisa.c             optional bt eisa
 dev/buslogic/bt_isa.c          optional bt isa
 dev/buslogic/bt_mca.c          optional bt mca
 dev/buslogic/bt_pci.c          optional bt pci
+dev/bwi/bwiirf.c               optional bwi
+dev/bwi/bwimac.c               optional bwi
+dev/bwi/bwiphy.c               optional bwi
+dev/bwi/if_bwi.c               optional bwi
+dev/bwi/if_bwi_pci.c           optional bwi pci
 dev/cardbus/cardbus.c          optional cardbus
 dev/cardbus/cardbus_cis.c      optional cardbus
 dev/cardbus/cardbus_device.c   optional cardbus

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options       Sun May  3 02:37:13 2009        (r191761)
+++ head/sys/conf/options       Sun May  3 04:01:43 2009        (r191762)
@@ -763,6 +763,10 @@ AH_NEED_DESC_SWAP  opt_ah.h
 AH_USE_INIPDGAIN       opt_ah.h
 AH_MAXCHAN             opt_ah.h
 
+# options for the Broadcom BCM43xx driver (bwi)
+BWI_DEBUG              opt_bwi.h
+BWI_DEBUG_VERBOSE      opt_bwi.h
+
 # options for the Marvell 8335 wireless driver
 MALO_DEBUG             opt_malo.h
 MALO_TXBUF             opt_malo.h

Added: head/sys/dev/bwi/bitops.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/bwi/bitops.h   Sun May  3 04:01:43 2009        (r191762)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2004, 2005 David Young.  All rights reserved.
+ *
+ * Programmed for NetBSD by David Young.
+ *
+ * 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 David Young may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY David Young ``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 David
+ * Young 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.
+ *
+ * $DragonFly: src/sys/dev/netif/bwi/bitops.h,v 1.1 2007/09/08 06:15:54 sephe 
Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _BITOPS_H
+#define _BITOPS_H
+
+/*
+ * __BIT(n): Return a bitmask with bit m set, where the least
+ *           significant bit is bit 0.
+ *
+ * __BITS(m, n): Return a bitmask with bits m through n, inclusive,
+ *               set.  It does not matter whether m>n or m<=n.  The
+ *               least significant bit is bit 0.
+ *
+ * A "bitfield" is a span of consecutive bits defined by a bitmask,
+ * where 1s select the bits in the bitfield.  __SHIFTIN, __SHIFTOUT,
+ * and SHIFTOUT_MASK help read and write bitfields from device registers.
+ *
+ * __SHIFTIN(v, mask): Left-shift bits `v' into the bitfield
+ *                     defined by `mask', and return them.  No
+ *                     side-effects.
+ *
+ * __SHIFTOUT(v, mask): Extract and return the bitfield selected
+ *                      by `mask' from `v', right-shifting the
+ *                      bits so that the rightmost selected bit
+ *                      is at bit 0.  No side-effects.
+ *
+ * __SHIFTOUT_MASK(mask): Right-shift the bits in `mask' so that
+ *                        the rightmost non-zero bit is at bit
+ *                        0.  This is useful for finding the
+ *                        greatest unsigned value that a bitfield
+ *                        can hold.  No side-effects.  Note that
+ *                        SHIFTOUT_MASK(m) = SHIFTOUT(m, m).
+ */
+
+/* __BIT(n): nth bit, where __BIT(0) == 0x1. */
+#define        __BIT(__n) (((__n) == 32) ? 0 : ((uint32_t)1 << (__n)))
+
+/* __BITS(m, n): bits m through n, m < n. */
+#define        __BITS(__m, __n)        \
+       ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
+
+/* Find least significant bit that is set */
+#define        __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ 
(__mask))
+
+#define        __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / 
__LOWEST_SET_BIT(__mask))
+#define        __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask))
+#define        __SHIFTOUT_MASK(__mask) __SHIFTOUT((__mask), (__mask))
+
+#endif /* !_BITOPS_H */

Added: head/sys/dev/bwi/bwimac.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/bwi/bwimac.c   Sun May  3 04:01:43 2009        (r191762)
@@ -0,0 +1,1982 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ * 
+ * This code is derived from software contributed to The DragonFly Project
+ * by Sepherosa Ziehau <sepher...@gmail.com>
+ * 
+ * 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. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ * 
+ * $DragonFly: src/sys/dev/netif/bwi/bwimac.c,v 1.13 2008/02/15 11:15:38 sephe 
Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_bwi.h"
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <sys/linker.h>
+#include <sys/firmware.h>
+ 
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_amrr.h>
+#include <net80211/ieee80211_phy.h>
+
+#include <machine/bus.h>
+
+#include <dev/bwi/bitops.h>
+#include <dev/bwi/if_bwireg.h>
+#include <dev/bwi/if_bwivar.h>
+#include <dev/bwi/bwimac.h>
+#include <dev/bwi/bwirf.h>
+#include <dev/bwi/bwiphy.h>
+
+struct bwi_retry_lim {
+       uint16_t        shretry;
+       uint16_t        shretry_fb;
+       uint16_t        lgretry;
+       uint16_t        lgretry_fb;
+};
+
+static int     bwi_mac_test(struct bwi_mac *);
+static int     bwi_mac_get_property(struct bwi_mac *);
+
+static void    bwi_mac_set_retry_lim(struct bwi_mac *,
+                       const struct bwi_retry_lim *);
+static void    bwi_mac_set_ackrates(struct bwi_mac *,
+                       const struct ieee80211_rate_table *rt,
+                       const struct ieee80211_rateset *);
+
+static int     bwi_mac_gpio_init(struct bwi_mac *);
+static int     bwi_mac_gpio_fini(struct bwi_mac *);
+static void    bwi_mac_opmode_init(struct bwi_mac *);
+static void    bwi_mac_hostflags_init(struct bwi_mac *);
+static void    bwi_mac_bss_param_init(struct bwi_mac *);
+
+static int     bwi_mac_fw_alloc(struct bwi_mac *);
+static void    bwi_mac_fw_free(struct bwi_mac *);
+static int     bwi_mac_fw_load(struct bwi_mac *);
+static int     bwi_mac_fw_init(struct bwi_mac *);
+static int     bwi_mac_fw_load_iv(struct bwi_mac *, const struct firmware *);
+
+static void    bwi_mac_setup_tpctl(struct bwi_mac *);
+static void    bwi_mac_adjust_tpctl(struct bwi_mac *, int, int);
+
+static void    bwi_mac_lock(struct bwi_mac *);
+static void    bwi_mac_unlock(struct bwi_mac *);
+
+static const uint8_t bwi_sup_macrev[] = { 2, 4, 5, 6, 7, 9, 10 };
+
+void
+bwi_tmplt_write_4(struct bwi_mac *mac, uint32_t ofs, uint32_t val)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+
+       if (mac->mac_flags & BWI_MAC_F_BSWAP)
+               val = bswap32(val);
+
+       CSR_WRITE_4(sc, BWI_MAC_TMPLT_CTRL, ofs);
+       CSR_WRITE_4(sc, BWI_MAC_TMPLT_DATA, val);
+}
+
+void
+bwi_hostflags_write(struct bwi_mac *mac, uint64_t flags)
+{
+       uint64_t val;
+
+       val = flags & 0xffff;
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO, val);
+
+       val = (flags >> 16) & 0xffff;
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI, val);
+
+       /* HI has unclear meaning, so leave it as it is */
+}
+
+uint64_t
+bwi_hostflags_read(struct bwi_mac *mac)
+{
+       uint64_t flags, val;
+
+       /* HI has unclear meaning, so don't touch it */
+       flags = 0;
+
+       val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI);
+       flags |= val << 16;
+
+       val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO);
+       flags |= val;
+
+       return flags;
+}
+
+uint16_t
+bwi_memobj_read_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       uint32_t data_reg;
+       int ofs;
+
+       data_reg = BWI_MOBJ_DATA;
+       ofs = ofs0 / 4;
+
+       if (ofs0 % 4 != 0)
+               data_reg = BWI_MOBJ_DATA_UNALIGN;
+
+       CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+       return CSR_READ_2(sc, data_reg);
+}
+
+uint32_t
+bwi_memobj_read_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       int ofs;
+
+       ofs = ofs0 / 4;
+       if (ofs0 % 4 != 0) {
+               uint32_t ret;
+
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+               ret = CSR_READ_2(sc, BWI_MOBJ_DATA_UNALIGN);
+               ret <<= 16;
+
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
+                           BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1));
+               ret |= CSR_READ_2(sc, BWI_MOBJ_DATA);
+
+               return ret;
+       } else {
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+               return CSR_READ_4(sc, BWI_MOBJ_DATA);
+       }
+}
+
+void
+bwi_memobj_write_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0,
+                  uint16_t v)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       uint32_t data_reg;
+       int ofs;
+
+       data_reg = BWI_MOBJ_DATA;
+       ofs = ofs0 / 4;
+
+       if (ofs0 % 4 != 0)
+               data_reg = BWI_MOBJ_DATA_UNALIGN;
+
+       CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+       CSR_WRITE_2(sc, data_reg, v);
+}
+
+void
+bwi_memobj_write_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0,
+                  uint32_t v)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       int ofs;
+
+       ofs = ofs0 / 4;
+       if (ofs0 % 4 != 0) {
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+               CSR_WRITE_2(sc, BWI_MOBJ_DATA_UNALIGN, v >> 16);
+
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
+                           BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1));
+               CSR_WRITE_2(sc, BWI_MOBJ_DATA, v & 0xffff);
+       } else {
+               CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
+               CSR_WRITE_4(sc, BWI_MOBJ_DATA, v);
+       }
+}
+
+int
+bwi_mac_lateattach(struct bwi_mac *mac)
+{
+       int error;
+
+       if (mac->mac_rev >= 5)
+               CSR_READ_4(mac->mac_sc, BWI_STATE_HI); /* dummy read */
+
+       bwi_mac_reset(mac, 1);
+
+       error = bwi_phy_attach(mac);
+       if (error)
+               return error;
+
+       error = bwi_rf_attach(mac);
+       if (error)
+               return error;
+
+       /* Link 11B/G PHY, unlink 11A PHY */
+       if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A)
+               bwi_mac_reset(mac, 0);
+       else
+               bwi_mac_reset(mac, 1);
+
+       error = bwi_mac_test(mac);
+       if (error)
+               return error;
+
+       error = bwi_mac_get_property(mac);
+       if (error)
+               return error;
+
+       error = bwi_rf_map_txpower(mac);
+       if (error)
+               return error;
+
+       bwi_rf_off(mac);
+       CSR_WRITE_2(mac->mac_sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC);
+       bwi_regwin_disable(mac->mac_sc, &mac->mac_regwin, 0);
+
+       return 0;
+}
+
+int
+bwi_mac_init(struct bwi_mac *mac)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       int error, i;
+
+       /* Clear MAC/PHY/RF states */
+       bwi_mac_setup_tpctl(mac);
+       bwi_rf_clear_state(&mac->mac_rf);
+       bwi_phy_clear_state(&mac->mac_phy);
+
+       /* Enable MAC and linked it to PHY */
+       if (!bwi_regwin_is_enabled(sc, &mac->mac_regwin))
+               bwi_mac_reset(mac, 1);
+
+       /* Initialize backplane */
+       error = bwi_bus_init(sc, mac);
+       if (error)
+               return error;
+
+       /* XXX work around for hardware bugs? */
+       if (sc->sc_bus_regwin.rw_rev <= 5 &&
+           sc->sc_bus_regwin.rw_type != BWI_REGWIN_T_BUSPCIE) {
+               CSR_SETBITS_4(sc, BWI_CONF_LO,
+               __SHIFTIN(BWI_CONF_LO_SERVTO, BWI_CONF_LO_SERVTO_MASK) |
+               __SHIFTIN(BWI_CONF_LO_REQTO, BWI_CONF_LO_REQTO_MASK));
+       }
+
+       /* Calibrate PHY */
+       error = bwi_phy_calibrate(mac);
+       if (error) {
+               device_printf(sc->sc_dev, "PHY calibrate failed\n");
+               return error;
+       }
+
+       /* Prepare to initialize firmware */
+       CSR_WRITE_4(sc, BWI_MAC_STATUS,
+                   BWI_MAC_STATUS_UCODE_JUMP0 |
+                   BWI_MAC_STATUS_IHREN);
+
+       /*
+        * Load and initialize firmwares
+        */
+       error = bwi_mac_fw_alloc(mac);
+       if (error)
+               return error;
+
+       error = bwi_mac_fw_load(mac);
+       if (error)
+               return error;
+
+       error = bwi_mac_gpio_init(mac);
+       if (error)
+               return error;
+
+       error = bwi_mac_fw_init(mac);
+       if (error)
+               return error;
+
+       /*
+        * Turn on RF
+        */
+       bwi_rf_on(mac);
+
+       /* TODO: LED, hardware rf enabled is only related to LED setting */
+
+       /*
+        * Initialize PHY
+        */
+       CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
+       bwi_phy_init(mac);
+
+       /* TODO: interference mitigation */
+
+       /*
+        * Setup antenna mode
+        */
+       bwi_rf_set_ant_mode(mac, mac->mac_rf.rf_ant_mode);
+
+       /*
+        * Initialize operation mode (RX configuration)
+        */
+       bwi_mac_opmode_init(mac);
+
+       /* XXX what's these */
+       if (mac->mac_rev < 3) {
+               CSR_WRITE_2(sc, 0x60e, 0);
+               CSR_WRITE_2(sc, 0x610, 0x8000);
+               CSR_WRITE_2(sc, 0x604, 0);
+               CSR_WRITE_2(sc, 0x606, 0x200);
+       } else {
+               CSR_WRITE_4(sc, 0x188, 0x80000000);
+               CSR_WRITE_4(sc, 0x18c, 0x2000000);
+       }
+
+       /*
+        * Initialize TX/RX interrupts' mask
+        */
+       CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_INTR_TIMER1);
+       for (i = 0; i < BWI_TXRX_NRING; ++i) {
+               uint32_t intrs;
+
+               if (BWI_TXRX_IS_RX(i))
+                       intrs = BWI_TXRX_RX_INTRS;
+               else
+                       intrs = BWI_TXRX_TX_INTRS;
+               CSR_WRITE_4(sc, BWI_TXRX_INTR_MASK(i), intrs);
+       }
+
+       /* XXX what's this */
+       CSR_SETBITS_4(sc, BWI_STATE_LO, 0x100000);
+
+       /* Setup MAC power up delay */
+       CSR_WRITE_2(sc, BWI_MAC_POWERUP_DELAY, sc->sc_pwron_delay);
+
+       /* Set MAC regwin revision */
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_MACREV, mac->mac_rev);
+
+       /*
+        * Initialize host flags
+        */
+       bwi_mac_hostflags_init(mac);
+
+       /*
+        * Initialize BSS parameters
+        */
+       bwi_mac_bss_param_init(mac);
+
+       /*
+        * Initialize TX rings
+        */
+       for (i = 0; i < BWI_TX_NRING; ++i) {
+               error = sc->sc_init_tx_ring(sc, i);
+               if (error) {
+                       device_printf(sc->sc_dev,
+                                 "can't initialize %dth TX ring\n", i);
+                       return error;
+               }
+       }
+
+       /*
+        * Initialize RX ring
+        */
+       error = sc->sc_init_rx_ring(sc);
+       if (error) {
+               device_printf(sc->sc_dev, "can't initialize RX ring\n");
+               return error;
+       }
+
+       /*
+        * Initialize TX stats if the current MAC uses that
+        */
+       if (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) {
+               error = sc->sc_init_txstats(sc);
+               if (error) {
+                       device_printf(sc->sc_dev,
+                                 "can't initialize TX stats ring\n");
+                       return error;
+               }
+       }
+
+       /* XXX what's these */
+       CSR_WRITE_2(sc, 0x612, 0x50);   /* Force Pre-TBTT to 80? */
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x416, 0x50);
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x414, 0x1f4);
+
+       mac->mac_flags |= BWI_MAC_F_INITED;
+       return 0;
+}
+
+void
+bwi_mac_reset(struct bwi_mac *mac, int link_phy)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       uint32_t flags, state_lo, status;
+
+       flags = BWI_STATE_LO_FLAG_PHYRST | BWI_STATE_LO_FLAG_PHYCLKEN;
+       if (link_phy)
+               flags |= BWI_STATE_LO_FLAG_PHYLNK;
+       bwi_regwin_enable(sc, &mac->mac_regwin, flags);
+       DELAY(2000);
+
+       state_lo = CSR_READ_4(sc, BWI_STATE_LO);
+       state_lo |= BWI_STATE_LO_GATED_CLOCK;
+       state_lo &= ~__SHIFTIN(BWI_STATE_LO_FLAG_PHYRST,
+                              BWI_STATE_LO_FLAGS_MASK);
+       CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
+       /* Flush pending bus write */
+       CSR_READ_4(sc, BWI_STATE_LO);
+       DELAY(1000);
+
+       state_lo &= ~BWI_STATE_LO_GATED_CLOCK;
+       CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
+       /* Flush pending bus write */
+       CSR_READ_4(sc, BWI_STATE_LO);
+       DELAY(1000);
+
+       CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
+
+       status = CSR_READ_4(sc, BWI_MAC_STATUS);
+       status |= BWI_MAC_STATUS_IHREN;
+       if (link_phy)
+               status |= BWI_MAC_STATUS_PHYLNK;
+       else
+               status &= ~BWI_MAC_STATUS_PHYLNK;
+       CSR_WRITE_4(sc, BWI_MAC_STATUS, status);
+
+       if (link_phy) {
+               DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT,
+                       "%s\n", "PHY is linked");
+               mac->mac_phy.phy_flags |= BWI_PHY_F_LINKED;
+       } else {
+               DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT,
+                       "%s\n", "PHY is unlinked");
+               mac->mac_phy.phy_flags &= ~BWI_PHY_F_LINKED;
+       }
+}
+
+void
+bwi_mac_set_tpctl_11bg(struct bwi_mac *mac, const struct bwi_tpctl *new_tpctl)
+{
+       struct bwi_rf *rf = &mac->mac_rf;
+       struct bwi_tpctl *tpctl = &mac->mac_tpctl;
+
+       if (new_tpctl != NULL) {
+               KASSERT(new_tpctl->bbp_atten <= BWI_BBP_ATTEN_MAX,
+                   ("bbp_atten %d", new_tpctl->bbp_atten));
+               KASSERT(new_tpctl->rf_atten <=
+                        (rf->rf_rev < 6 ? BWI_RF_ATTEN_MAX0
+                                        : BWI_RF_ATTEN_MAX1),
+                   ("rf_atten %d", new_tpctl->rf_atten));
+               KASSERT(new_tpctl->tp_ctrl1 <= BWI_TPCTL1_MAX,
+                   ("tp_ctrl1 %d", new_tpctl->tp_ctrl1));
+
+               tpctl->bbp_atten = new_tpctl->bbp_atten;
+               tpctl->rf_atten = new_tpctl->rf_atten;
+               tpctl->tp_ctrl1 = new_tpctl->tp_ctrl1;
+       }
+
+       /* Set BBP attenuation */
+       bwi_phy_set_bbp_atten(mac, tpctl->bbp_atten);
+
+       /* Set RF attenuation */
+       RF_WRITE(mac, BWI_RFR_ATTEN, tpctl->rf_atten);
+       MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_RF_ATTEN,
+                    tpctl->rf_atten);
+
+       /* Set TX power */
+       if (rf->rf_type == BWI_RF_T_BCM2050) {
+               RF_FILT_SETBITS(mac, BWI_RFR_TXPWR, ~BWI_RFR_TXPWR1_MASK,
+                       __SHIFTIN(tpctl->tp_ctrl1, BWI_RFR_TXPWR1_MASK));
+       }
+
+       /* Adjust RF Local Oscillator */
+       if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G)
+               bwi_rf_lo_adjust(mac, tpctl);
+}
+
+static int
+bwi_mac_test(struct bwi_mac *mac)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       uint32_t orig_val, val;
+
+#define TEST_VAL1      0xaa5555aa
+#define TEST_VAL2      0x55aaaa55
+
+       /* Save it for later restoring */
+       orig_val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
+
+       /* Test 1 */
+       MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL1);
+       val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
+       if (val != TEST_VAL1) {
+               device_printf(sc->sc_dev, "TEST1 failed\n");
+               return ENXIO;
+       }
+
+       /* Test 2 */
+       MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL2);
+       val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
+       if (val != TEST_VAL2) {
+               device_printf(sc->sc_dev, "TEST2 failed\n");
+               return ENXIO;
+       }
+
+       /* Restore to the original value */
+       MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, orig_val);
+
+       val = CSR_READ_4(sc, BWI_MAC_STATUS);
+       if ((val & ~BWI_MAC_STATUS_PHYLNK) != BWI_MAC_STATUS_IHREN) {
+               device_printf(sc->sc_dev, "%s failed, MAC status 0x%08x\n",
+                             __func__, val);
+               return ENXIO;
+       }
+
+       val = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
+       if (val != 0) {
+               device_printf(sc->sc_dev, "%s failed, intr status %08x\n",
+                             __func__, val);
+               return ENXIO;
+       }
+
+#undef TEST_VAL2
+#undef TEST_VAL1
+
+       return 0;
+}
+
+static void
+bwi_mac_setup_tpctl(struct bwi_mac *mac)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       struct bwi_rf *rf = &mac->mac_rf;
+       struct bwi_phy *phy = &mac->mac_phy;
+       struct bwi_tpctl *tpctl = &mac->mac_tpctl;
+
+       /* Calc BBP attenuation */
+       if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev < 6)
+               tpctl->bbp_atten = 0;
+       else
+               tpctl->bbp_atten = 2;
+
+       /* Calc TX power CTRL1?? */
+       tpctl->tp_ctrl1 = 0;
+       if (rf->rf_type == BWI_RF_T_BCM2050) {
+               if (rf->rf_rev == 1)
+                       tpctl->tp_ctrl1 = 3;
+               else if (rf->rf_rev < 6)
+                       tpctl->tp_ctrl1 = 2;
+               else if (rf->rf_rev == 8)
+                       tpctl->tp_ctrl1 = 1;
+       }
+
+       /* Empty TX power CTRL2?? */
+       tpctl->tp_ctrl2 = 0xffff;
+
+       /*
+        * Calc RF attenuation
+        */
+       if (phy->phy_mode == IEEE80211_MODE_11A) {
+               tpctl->rf_atten = 0x60;
+               goto back;
+       }
+
+       if (BWI_IS_BRCM_BCM4309G(sc) && sc->sc_pci_revid < 0x51) {
+               tpctl->rf_atten = sc->sc_pci_revid < 0x43 ? 2 : 3;
+               goto back;
+       }
+
+       tpctl->rf_atten = 5;
+
+       if (rf->rf_type != BWI_RF_T_BCM2050) {
+               if (rf->rf_type == BWI_RF_T_BCM2053 && rf->rf_rev == 1)
+                       tpctl->rf_atten = 6;
+               goto back;
+       }
+
+       /*
+        * NB: If we reaches here and the card is BRCM_BCM4309G,
+        *     then the card's PCI revision must >= 0x51
+        */
+
+       /* BCM2050 RF */
+       switch (rf->rf_rev) {
+       case 1:
+               if (phy->phy_mode == IEEE80211_MODE_11G) {
+                       if (BWI_IS_BRCM_BCM4309G(sc) || BWI_IS_BRCM_BU4306(sc))
+                               tpctl->rf_atten = 3;
+                       else
+                               tpctl->rf_atten = 1;
+               } else {
+                       if (BWI_IS_BRCM_BCM4309G(sc))
+                               tpctl->rf_atten = 7;
+                       else
+                               tpctl->rf_atten = 6;
+               }
+               break;
+       case 2:
+               if (phy->phy_mode == IEEE80211_MODE_11G) {
+                       /*
+                        * NOTE: Order of following conditions is critical
+                        */
+                       if (BWI_IS_BRCM_BCM4309G(sc))
+                               tpctl->rf_atten = 3;
+                       else if (BWI_IS_BRCM_BU4306(sc))
+                               tpctl->rf_atten = 5;
+                       else if (sc->sc_bbp_id == BWI_BBPID_BCM4320)
+                               tpctl->rf_atten = 4;
+                       else
+                               tpctl->rf_atten = 3;
+               } else {
+                       tpctl->rf_atten = 6;
+               }
+               break;
+       case 4:
+       case 5:
+               tpctl->rf_atten = 1;
+               break;
+       case 8:
+               tpctl->rf_atten = 0x1a;
+               break;
+       }
+back:
+       DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER,
+               "bbp atten: %u, rf atten: %u, ctrl1: %u, ctrl2: %u\n",
+               tpctl->bbp_atten, tpctl->rf_atten,
+               tpctl->tp_ctrl1, tpctl->tp_ctrl2);
+}
+
+void
+bwi_mac_dummy_xmit(struct bwi_mac *mac)
+{
+#define PACKET_LEN     5
+       static const uint32_t   packet_11a[PACKET_LEN] =
+       { 0x000201cc, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 };
+       static const uint32_t   packet_11bg[PACKET_LEN] =
+       { 0x000b846e, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 };
+
+       struct bwi_softc *sc = mac->mac_sc;
+       struct bwi_rf *rf = &mac->mac_rf;
+       const uint32_t *packet;
+       uint16_t val_50c;
+       int wait_max, i;
+
+       if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A) {
+               wait_max = 30;
+               packet = packet_11a;
+               val_50c = 1;
+       } else {
+               wait_max = 250;
+               packet = packet_11bg;
+               val_50c = 0;
+       }
+
+       for (i = 0; i < PACKET_LEN; ++i)
+               TMPLT_WRITE_4(mac, i * 4, packet[i]);
+
+       CSR_READ_4(sc, BWI_MAC_STATUS); /* dummy read */
+
+       CSR_WRITE_2(sc, 0x568, 0);
+       CSR_WRITE_2(sc, 0x7c0, 0);
+       CSR_WRITE_2(sc, 0x50c, val_50c);
+       CSR_WRITE_2(sc, 0x508, 0);
+       CSR_WRITE_2(sc, 0x50a, 0);
+       CSR_WRITE_2(sc, 0x54c, 0);
+       CSR_WRITE_2(sc, 0x56a, 0x14);
+       CSR_WRITE_2(sc, 0x568, 0x826);
+       CSR_WRITE_2(sc, 0x500, 0);
+       CSR_WRITE_2(sc, 0x502, 0x30);
+
+       if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5)
+               RF_WRITE(mac, 0x51, 0x17);
+
+       for (i = 0; i < wait_max; ++i) {
+               if (CSR_READ_2(sc, 0x50e) & 0x80)
+                       break;
+               DELAY(10);
+       }
+       for (i = 0; i < 10; ++i) {
+               if (CSR_READ_2(sc, 0x50e) & 0x400)
+                       break;
+               DELAY(10);
+       }
+       for (i = 0; i < 10; ++i) {
+               if ((CSR_READ_2(sc, 0x690) & 0x100) == 0)
+                       break;
+               DELAY(10);
+       }
+
+       if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5)
+               RF_WRITE(mac, 0x51, 0x37);
+#undef PACKET_LEN
+}
+
+void
+bwi_mac_init_tpctl_11bg(struct bwi_mac *mac)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       struct bwi_phy *phy = &mac->mac_phy;
+       struct bwi_rf *rf = &mac->mac_rf;
+       struct bwi_tpctl tpctl_orig;
+       int restore_tpctl = 0;
+
+       KASSERT(phy->phy_mode != IEEE80211_MODE_11A,
+           ("phy_mode %d", phy->phy_mode));
+
+       if (BWI_IS_BRCM_BU4306(sc))
+               return;
+
+       PHY_WRITE(mac, 0x28, 0x8018);
+       CSR_CLRBITS_2(sc, BWI_BBP_ATTEN, 0x20);
+
+       if (phy->phy_mode == IEEE80211_MODE_11G) {
+               if ((phy->phy_flags & BWI_PHY_F_LINKED) == 0)
+                       return;
+               PHY_WRITE(mac, 0x47a, 0xc111);
+       }
+       if (mac->mac_flags & BWI_MAC_F_TPCTL_INITED)
+               return;
+
+       if (phy->phy_mode == IEEE80211_MODE_11B && phy->phy_rev >= 2 &&
+           rf->rf_type == BWI_RF_T_BCM2050) {
+               RF_SETBITS(mac, 0x76, 0x84);
+       } else {
+               struct bwi_tpctl tpctl;
+
+               /* Backup original TX power control variables */
+               bcopy(&mac->mac_tpctl, &tpctl_orig, sizeof(tpctl_orig));
+               restore_tpctl = 1;
+
+               bcopy(&mac->mac_tpctl, &tpctl, sizeof(tpctl));
+               tpctl.bbp_atten = 11;
+               tpctl.tp_ctrl1 = 0;
+#ifdef notyet
+               if (rf->rf_rev >= 6 && rf->rf_rev <= 8)
+                       tpctl.rf_atten = 31;
+               else
+#endif
+                       tpctl.rf_atten = 9;
+
+               bwi_mac_set_tpctl_11bg(mac, &tpctl);
+       }
+
+       bwi_mac_dummy_xmit(mac);
+
+       mac->mac_flags |= BWI_MAC_F_TPCTL_INITED;
+       rf->rf_base_tssi = PHY_READ(mac, 0x29);
+       DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER,
+               "base tssi %d\n", rf->rf_base_tssi);
+
+       if (abs(rf->rf_base_tssi - rf->rf_idle_tssi) >= 20) {
+               device_printf(sc->sc_dev, "base tssi measure failed\n");
+               mac->mac_flags |= BWI_MAC_F_TPCTL_ERROR;
+       }
+
+       if (restore_tpctl)
+               bwi_mac_set_tpctl_11bg(mac, &tpctl_orig);
+       else
+               RF_CLRBITS(mac, 0x76, 0x84);
+
+       bwi_rf_clear_tssi(mac);
+}
+
+void
+bwi_mac_detach(struct bwi_mac *mac)
+{
+       bwi_mac_fw_free(mac);
+}
+
+static __inline int
+bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw,
+                    uint8_t fw_type)
+{
+       const struct bwi_fwhdr *hdr;
+       struct ifnet *ifp = sc->sc_ifp;
+
+       if (fw->datasize < sizeof(*hdr)) {
+               if_printf(ifp, "invalid firmware (%s): invalid size %zu\n",
+                         fw->name, fw->datasize);
+               return 0;
+       }
+
+       hdr = (const struct bwi_fwhdr *)fw->data;
+
+       if (fw_type != BWI_FW_T_IV) {
+               /*
+                * Don't verify IV's size, it has different meaning
+                */
+               if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) {
+                       if_printf(ifp, "invalid firmware (%s): size mismatch, "
+                                 "fw %u, real %zu\n", fw->name,
+                                 be32toh(hdr->fw_size),
+                                 fw->datasize - sizeof(*hdr));
+                       return 0;
+               }
+       }
+
+       if (hdr->fw_type != fw_type) {
+               if_printf(ifp, "invalid firmware (%s): type mismatch, "
+                         "fw \'%c\', target \'%c\'\n", fw->name,
+                         hdr->fw_type, fw_type);
+               return 0;
+       }
+
+       if (hdr->fw_gen != BWI_FW_GEN_1) {
+               if_printf(ifp, "invalid firmware (%s): wrong generation, "
+                         "fw %d, target %d\n", fw->name,
+                         hdr->fw_gen, BWI_FW_GEN_1);
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * XXX Error cleanup
+ */
+static int
+bwi_mac_fw_alloc(struct bwi_mac *mac)
+{
+       struct bwi_softc *sc = mac->mac_sc;
+       struct ifnet *ifp = sc->sc_ifp;
+       char fwname[64];
+       int idx;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to