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