From owner-svn-src-all@FreeBSD.ORG Sun May 3 04:01:43 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D8821106566C; Sun, 3 May 2009 04:01:43 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id C43198FC14; Sun, 3 May 2009 04:01:43 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n4341hcw003808; Sun, 3 May 2009 04:01:43 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4341h9W003803; Sun, 3 May 2009 04:01:43 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <200905030401.n4341h9W003803@svn.freebsd.org> From: Warner Losh Date: Sun, 3 May 2009 04:01:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r191762 - in head/sys: conf dev/bwi modules/bwi X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 03 May 2009 04:01:44 -0000 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 + * + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_inet.h" +#include "opt_bwi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +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 ***