svn commit: r191762 - in head/sys: conf dev/bwi modules/bwi
Warner Losh
imp at FreeBSD.org
Sun May 3 04:01:44 UTC 2009
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 <sepherosa at 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 ***
More information about the svn-src-head
mailing list