1191762Simp/*
2191762Simp * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3191762Simp *
4191762Simp * This code is derived from software contributed to The DragonFly Project
5191762Simp * by Sepherosa Ziehau <sepherosa@gmail.com>
6191762Simp *
7191762Simp * Redistribution and use in source and binary forms, with or without
8191762Simp * modification, are permitted provided that the following conditions
9191762Simp * are met:
10191762Simp *
11191762Simp * 1. Redistributions of source code must retain the above copyright
12191762Simp *    notice, this list of conditions and the following disclaimer.
13191762Simp * 2. Redistributions in binary form must reproduce the above copyright
14191762Simp *    notice, this list of conditions and the following disclaimer in
15191762Simp *    the documentation and/or other materials provided with the
16191762Simp *    distribution.
17191762Simp * 3. Neither the name of The DragonFly Project nor the names of its
18191762Simp *    contributors may be used to endorse or promote products derived
19191762Simp *    from this software without specific, prior written permission.
20191762Simp *
21191762Simp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22191762Simp * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23191762Simp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24191762Simp * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25191762Simp * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26191762Simp * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27191762Simp * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28191762Simp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29191762Simp * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30191762Simp * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31191762Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32191762Simp * SUCH DAMAGE.
33191762Simp *
34191762Simp * $DragonFly: src/sys/dev/netif/bwi/bwimac.c,v 1.13 2008/02/15 11:15:38 sephe Exp $
35191762Simp */
36191762Simp
37191762Simp#include <sys/cdefs.h>
38191762Simp__FBSDID("$FreeBSD$");
39191762Simp
40191762Simp#include "opt_inet.h"
41191762Simp#include "opt_bwi.h"
42191762Simp
43191762Simp#include <sys/param.h>
44191762Simp#include <sys/endian.h>
45191762Simp#include <sys/kernel.h>
46191762Simp#include <sys/bus.h>
47191762Simp#include <sys/malloc.h>
48191762Simp#include <sys/proc.h>
49191762Simp#include <sys/rman.h>
50191762Simp#include <sys/socket.h>
51191762Simp#include <sys/sockio.h>
52191762Simp#include <sys/sysctl.h>
53191762Simp#include <sys/systm.h>
54191762Simp
55191762Simp#include <sys/linker.h>
56191762Simp#include <sys/firmware.h>
57191762Simp
58191762Simp#include <net/if.h>
59191762Simp#include <net/if_dl.h>
60191762Simp#include <net/if_media.h>
61191762Simp#include <net/if_types.h>
62191762Simp#include <net/if_arp.h>
63191762Simp#include <net/ethernet.h>
64191762Simp#include <net/if_llc.h>
65191762Simp
66191762Simp#include <net80211/ieee80211_var.h>
67191762Simp#include <net80211/ieee80211_radiotap.h>
68191762Simp#include <net80211/ieee80211_amrr.h>
69191762Simp#include <net80211/ieee80211_phy.h>
70191762Simp
71191762Simp#include <machine/bus.h>
72191762Simp
73191762Simp#include <dev/bwi/bitops.h>
74191762Simp#include <dev/bwi/if_bwireg.h>
75191762Simp#include <dev/bwi/if_bwivar.h>
76191762Simp#include <dev/bwi/bwimac.h>
77191762Simp#include <dev/bwi/bwirf.h>
78191762Simp#include <dev/bwi/bwiphy.h>
79191762Simp
80191762Simpstruct bwi_retry_lim {
81191762Simp	uint16_t	shretry;
82191762Simp	uint16_t	shretry_fb;
83191762Simp	uint16_t	lgretry;
84191762Simp	uint16_t	lgretry_fb;
85191762Simp};
86191762Simp
87191762Simpstatic int	bwi_mac_test(struct bwi_mac *);
88191762Simpstatic int	bwi_mac_get_property(struct bwi_mac *);
89191762Simp
90191762Simpstatic void	bwi_mac_set_retry_lim(struct bwi_mac *,
91191762Simp			const struct bwi_retry_lim *);
92191762Simpstatic void	bwi_mac_set_ackrates(struct bwi_mac *,
93191762Simp			const struct ieee80211_rate_table *rt,
94191762Simp			const struct ieee80211_rateset *);
95191762Simp
96191762Simpstatic int	bwi_mac_gpio_init(struct bwi_mac *);
97191762Simpstatic int	bwi_mac_gpio_fini(struct bwi_mac *);
98191762Simpstatic void	bwi_mac_opmode_init(struct bwi_mac *);
99191762Simpstatic void	bwi_mac_hostflags_init(struct bwi_mac *);
100191762Simpstatic void	bwi_mac_bss_param_init(struct bwi_mac *);
101191762Simp
102191762Simpstatic int	bwi_mac_fw_alloc(struct bwi_mac *);
103191762Simpstatic void	bwi_mac_fw_free(struct bwi_mac *);
104191762Simpstatic int	bwi_mac_fw_load(struct bwi_mac *);
105191762Simpstatic int	bwi_mac_fw_init(struct bwi_mac *);
106191762Simpstatic int	bwi_mac_fw_load_iv(struct bwi_mac *, const struct firmware *);
107191762Simp
108191762Simpstatic void	bwi_mac_setup_tpctl(struct bwi_mac *);
109191762Simpstatic void	bwi_mac_adjust_tpctl(struct bwi_mac *, int, int);
110191762Simp
111191762Simpstatic void	bwi_mac_lock(struct bwi_mac *);
112191762Simpstatic void	bwi_mac_unlock(struct bwi_mac *);
113191762Simp
114191762Simpstatic const uint8_t bwi_sup_macrev[] = { 2, 4, 5, 6, 7, 9, 10 };
115191762Simp
116191762Simpvoid
117191762Simpbwi_tmplt_write_4(struct bwi_mac *mac, uint32_t ofs, uint32_t val)
118191762Simp{
119191762Simp	struct bwi_softc *sc = mac->mac_sc;
120191762Simp
121191762Simp	if (mac->mac_flags & BWI_MAC_F_BSWAP)
122191762Simp		val = bswap32(val);
123191762Simp
124191762Simp	CSR_WRITE_4(sc, BWI_MAC_TMPLT_CTRL, ofs);
125191762Simp	CSR_WRITE_4(sc, BWI_MAC_TMPLT_DATA, val);
126191762Simp}
127191762Simp
128191762Simpvoid
129191762Simpbwi_hostflags_write(struct bwi_mac *mac, uint64_t flags)
130191762Simp{
131191762Simp	uint64_t val;
132191762Simp
133191762Simp	val = flags & 0xffff;
134191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO, val);
135191762Simp
136191762Simp	val = (flags >> 16) & 0xffff;
137191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI, val);
138191762Simp
139191762Simp	/* HI has unclear meaning, so leave it as it is */
140191762Simp}
141191762Simp
142191762Simpuint64_t
143191762Simpbwi_hostflags_read(struct bwi_mac *mac)
144191762Simp{
145191762Simp	uint64_t flags, val;
146191762Simp
147191762Simp	/* HI has unclear meaning, so don't touch it */
148191762Simp	flags = 0;
149191762Simp
150191762Simp	val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI);
151191762Simp	flags |= val << 16;
152191762Simp
153191762Simp	val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO);
154191762Simp	flags |= val;
155191762Simp
156191762Simp	return flags;
157191762Simp}
158191762Simp
159191762Simpuint16_t
160191762Simpbwi_memobj_read_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0)
161191762Simp{
162191762Simp	struct bwi_softc *sc = mac->mac_sc;
163191762Simp	uint32_t data_reg;
164191762Simp	int ofs;
165191762Simp
166191762Simp	data_reg = BWI_MOBJ_DATA;
167191762Simp	ofs = ofs0 / 4;
168191762Simp
169191762Simp	if (ofs0 % 4 != 0)
170191762Simp		data_reg = BWI_MOBJ_DATA_UNALIGN;
171191762Simp
172191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
173191762Simp	return CSR_READ_2(sc, data_reg);
174191762Simp}
175191762Simp
176191762Simpuint32_t
177191762Simpbwi_memobj_read_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0)
178191762Simp{
179191762Simp	struct bwi_softc *sc = mac->mac_sc;
180191762Simp	int ofs;
181191762Simp
182191762Simp	ofs = ofs0 / 4;
183191762Simp	if (ofs0 % 4 != 0) {
184191762Simp		uint32_t ret;
185191762Simp
186191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
187191762Simp		ret = CSR_READ_2(sc, BWI_MOBJ_DATA_UNALIGN);
188191762Simp		ret <<= 16;
189191762Simp
190191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
191191762Simp			    BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1));
192191762Simp		ret |= CSR_READ_2(sc, BWI_MOBJ_DATA);
193191762Simp
194191762Simp		return ret;
195191762Simp	} else {
196191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
197191762Simp		return CSR_READ_4(sc, BWI_MOBJ_DATA);
198191762Simp	}
199191762Simp}
200191762Simp
201191762Simpvoid
202191762Simpbwi_memobj_write_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0,
203191762Simp		   uint16_t v)
204191762Simp{
205191762Simp	struct bwi_softc *sc = mac->mac_sc;
206191762Simp	uint32_t data_reg;
207191762Simp	int ofs;
208191762Simp
209191762Simp	data_reg = BWI_MOBJ_DATA;
210191762Simp	ofs = ofs0 / 4;
211191762Simp
212191762Simp	if (ofs0 % 4 != 0)
213191762Simp		data_reg = BWI_MOBJ_DATA_UNALIGN;
214191762Simp
215191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
216191762Simp	CSR_WRITE_2(sc, data_reg, v);
217191762Simp}
218191762Simp
219191762Simpvoid
220191762Simpbwi_memobj_write_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0,
221191762Simp		   uint32_t v)
222191762Simp{
223191762Simp	struct bwi_softc *sc = mac->mac_sc;
224191762Simp	int ofs;
225191762Simp
226191762Simp	ofs = ofs0 / 4;
227191762Simp	if (ofs0 % 4 != 0) {
228191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
229191762Simp		CSR_WRITE_2(sc, BWI_MOBJ_DATA_UNALIGN, v >> 16);
230191762Simp
231191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
232191762Simp			    BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1));
233191762Simp		CSR_WRITE_2(sc, BWI_MOBJ_DATA, v & 0xffff);
234191762Simp	} else {
235191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs));
236191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_DATA, v);
237191762Simp	}
238191762Simp}
239191762Simp
240191762Simpint
241191762Simpbwi_mac_lateattach(struct bwi_mac *mac)
242191762Simp{
243191762Simp	int error;
244191762Simp
245191762Simp	if (mac->mac_rev >= 5)
246191762Simp		CSR_READ_4(mac->mac_sc, BWI_STATE_HI); /* dummy read */
247191762Simp
248191762Simp	bwi_mac_reset(mac, 1);
249191762Simp
250191762Simp	error = bwi_phy_attach(mac);
251191762Simp	if (error)
252191762Simp		return error;
253191762Simp
254191762Simp	error = bwi_rf_attach(mac);
255191762Simp	if (error)
256191762Simp		return error;
257191762Simp
258191762Simp	/* Link 11B/G PHY, unlink 11A PHY */
259191762Simp	if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A)
260191762Simp		bwi_mac_reset(mac, 0);
261191762Simp	else
262191762Simp		bwi_mac_reset(mac, 1);
263191762Simp
264191762Simp	error = bwi_mac_test(mac);
265191762Simp	if (error)
266191762Simp		return error;
267191762Simp
268191762Simp	error = bwi_mac_get_property(mac);
269191762Simp	if (error)
270191762Simp		return error;
271191762Simp
272191762Simp	error = bwi_rf_map_txpower(mac);
273191762Simp	if (error)
274191762Simp		return error;
275191762Simp
276191762Simp	bwi_rf_off(mac);
277191762Simp	CSR_WRITE_2(mac->mac_sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC);
278191762Simp	bwi_regwin_disable(mac->mac_sc, &mac->mac_regwin, 0);
279191762Simp
280191762Simp	return 0;
281191762Simp}
282191762Simp
283191762Simpint
284191762Simpbwi_mac_init(struct bwi_mac *mac)
285191762Simp{
286191762Simp	struct bwi_softc *sc = mac->mac_sc;
287191762Simp	int error, i;
288191762Simp
289191762Simp	/* Clear MAC/PHY/RF states */
290191762Simp	bwi_mac_setup_tpctl(mac);
291191762Simp	bwi_rf_clear_state(&mac->mac_rf);
292191762Simp	bwi_phy_clear_state(&mac->mac_phy);
293191762Simp
294191762Simp	/* Enable MAC and linked it to PHY */
295191762Simp	if (!bwi_regwin_is_enabled(sc, &mac->mac_regwin))
296191762Simp		bwi_mac_reset(mac, 1);
297191762Simp
298191762Simp	/* Initialize backplane */
299191762Simp	error = bwi_bus_init(sc, mac);
300191762Simp	if (error)
301191762Simp		return error;
302191762Simp
303191995Simp	/* do timeout fixup */
304191762Simp	if (sc->sc_bus_regwin.rw_rev <= 5 &&
305191762Simp	    sc->sc_bus_regwin.rw_type != BWI_REGWIN_T_BUSPCIE) {
306191762Simp		CSR_SETBITS_4(sc, BWI_CONF_LO,
307191762Simp		__SHIFTIN(BWI_CONF_LO_SERVTO, BWI_CONF_LO_SERVTO_MASK) |
308191762Simp		__SHIFTIN(BWI_CONF_LO_REQTO, BWI_CONF_LO_REQTO_MASK));
309191762Simp	}
310191762Simp
311191762Simp	/* Calibrate PHY */
312191762Simp	error = bwi_phy_calibrate(mac);
313191762Simp	if (error) {
314191762Simp		device_printf(sc->sc_dev, "PHY calibrate failed\n");
315191762Simp		return error;
316191762Simp	}
317191762Simp
318191762Simp	/* Prepare to initialize firmware */
319191762Simp	CSR_WRITE_4(sc, BWI_MAC_STATUS,
320191762Simp		    BWI_MAC_STATUS_UCODE_JUMP0 |
321191762Simp		    BWI_MAC_STATUS_IHREN);
322191762Simp
323191762Simp	/*
324191762Simp	 * Load and initialize firmwares
325191762Simp	 */
326191762Simp	error = bwi_mac_fw_alloc(mac);
327191762Simp	if (error)
328191762Simp		return error;
329191762Simp
330191762Simp	error = bwi_mac_fw_load(mac);
331191762Simp	if (error)
332191762Simp		return error;
333191762Simp
334191762Simp	error = bwi_mac_gpio_init(mac);
335191762Simp	if (error)
336191762Simp		return error;
337191762Simp
338191762Simp	error = bwi_mac_fw_init(mac);
339191762Simp	if (error)
340191762Simp		return error;
341191762Simp
342191762Simp	/*
343191762Simp	 * Turn on RF
344191762Simp	 */
345191762Simp	bwi_rf_on(mac);
346191762Simp
347191762Simp	/* TODO: LED, hardware rf enabled is only related to LED setting */
348191762Simp
349191762Simp	/*
350191762Simp	 * Initialize PHY
351191762Simp	 */
352191762Simp	CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
353191762Simp	bwi_phy_init(mac);
354191762Simp
355191762Simp	/* TODO: interference mitigation */
356191762Simp
357191762Simp	/*
358191762Simp	 * Setup antenna mode
359191762Simp	 */
360191762Simp	bwi_rf_set_ant_mode(mac, mac->mac_rf.rf_ant_mode);
361191762Simp
362191762Simp	/*
363191762Simp	 * Initialize operation mode (RX configuration)
364191762Simp	 */
365191762Simp	bwi_mac_opmode_init(mac);
366191762Simp
367191995Simp	/* set up Beacon interval */
368191762Simp	if (mac->mac_rev < 3) {
369191762Simp		CSR_WRITE_2(sc, 0x60e, 0);
370191762Simp		CSR_WRITE_2(sc, 0x610, 0x8000);
371191762Simp		CSR_WRITE_2(sc, 0x604, 0);
372191762Simp		CSR_WRITE_2(sc, 0x606, 0x200);
373191762Simp	} else {
374191762Simp		CSR_WRITE_4(sc, 0x188, 0x80000000);
375191762Simp		CSR_WRITE_4(sc, 0x18c, 0x2000000);
376191762Simp	}
377191762Simp
378191762Simp	/*
379191762Simp	 * Initialize TX/RX interrupts' mask
380191762Simp	 */
381191762Simp	CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_INTR_TIMER1);
382191762Simp	for (i = 0; i < BWI_TXRX_NRING; ++i) {
383191762Simp		uint32_t intrs;
384191762Simp
385191762Simp		if (BWI_TXRX_IS_RX(i))
386191762Simp			intrs = BWI_TXRX_RX_INTRS;
387191762Simp		else
388191762Simp			intrs = BWI_TXRX_TX_INTRS;
389191762Simp		CSR_WRITE_4(sc, BWI_TXRX_INTR_MASK(i), intrs);
390191762Simp	}
391191762Simp
392191995Simp	/* allow the MAC to control the PHY clock (dynamic on/off) */
393191762Simp	CSR_SETBITS_4(sc, BWI_STATE_LO, 0x100000);
394191762Simp
395191762Simp	/* Setup MAC power up delay */
396191762Simp	CSR_WRITE_2(sc, BWI_MAC_POWERUP_DELAY, sc->sc_pwron_delay);
397191762Simp
398191762Simp	/* Set MAC regwin revision */
399191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_MACREV, mac->mac_rev);
400191762Simp
401191762Simp	/*
402191762Simp	 * Initialize host flags
403191762Simp	 */
404191762Simp	bwi_mac_hostflags_init(mac);
405191762Simp
406191762Simp	/*
407191762Simp	 * Initialize BSS parameters
408191762Simp	 */
409191762Simp	bwi_mac_bss_param_init(mac);
410191762Simp
411191762Simp	/*
412191762Simp	 * Initialize TX rings
413191762Simp	 */
414191762Simp	for (i = 0; i < BWI_TX_NRING; ++i) {
415191762Simp		error = sc->sc_init_tx_ring(sc, i);
416191762Simp		if (error) {
417191762Simp			device_printf(sc->sc_dev,
418191762Simp				  "can't initialize %dth TX ring\n", i);
419191762Simp			return error;
420191762Simp		}
421191762Simp	}
422191762Simp
423191762Simp	/*
424191762Simp	 * Initialize RX ring
425191762Simp	 */
426191762Simp	error = sc->sc_init_rx_ring(sc);
427191762Simp	if (error) {
428191762Simp		device_printf(sc->sc_dev, "can't initialize RX ring\n");
429191762Simp		return error;
430191762Simp	}
431191762Simp
432191762Simp	/*
433191762Simp	 * Initialize TX stats if the current MAC uses that
434191762Simp	 */
435191762Simp	if (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) {
436191762Simp		error = sc->sc_init_txstats(sc);
437191762Simp		if (error) {
438191762Simp			device_printf(sc->sc_dev,
439191762Simp				  "can't initialize TX stats ring\n");
440191762Simp			return error;
441191762Simp		}
442191762Simp	}
443191762Simp
444191995Simp	/* update PRETBTT */
445191762Simp	CSR_WRITE_2(sc, 0x612, 0x50);	/* Force Pre-TBTT to 80? */
446191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x416, 0x50);
447191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x414, 0x1f4);
448191762Simp
449191762Simp	mac->mac_flags |= BWI_MAC_F_INITED;
450191762Simp	return 0;
451191762Simp}
452191762Simp
453191762Simpvoid
454191762Simpbwi_mac_reset(struct bwi_mac *mac, int link_phy)
455191762Simp{
456191762Simp	struct bwi_softc *sc = mac->mac_sc;
457191762Simp	uint32_t flags, state_lo, status;
458191762Simp
459191762Simp	flags = BWI_STATE_LO_FLAG_PHYRST | BWI_STATE_LO_FLAG_PHYCLKEN;
460191762Simp	if (link_phy)
461191762Simp		flags |= BWI_STATE_LO_FLAG_PHYLNK;
462191762Simp	bwi_regwin_enable(sc, &mac->mac_regwin, flags);
463191762Simp	DELAY(2000);
464191762Simp
465191762Simp	state_lo = CSR_READ_4(sc, BWI_STATE_LO);
466191762Simp	state_lo |= BWI_STATE_LO_GATED_CLOCK;
467191762Simp	state_lo &= ~__SHIFTIN(BWI_STATE_LO_FLAG_PHYRST,
468191762Simp			       BWI_STATE_LO_FLAGS_MASK);
469191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
470191762Simp	/* Flush pending bus write */
471191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
472191762Simp	DELAY(1000);
473191762Simp
474191762Simp	state_lo &= ~BWI_STATE_LO_GATED_CLOCK;
475191762Simp	CSR_WRITE_4(sc, BWI_STATE_LO, state_lo);
476191762Simp	/* Flush pending bus write */
477191762Simp	CSR_READ_4(sc, BWI_STATE_LO);
478191762Simp	DELAY(1000);
479191762Simp
480191762Simp	CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
481191762Simp
482191762Simp	status = CSR_READ_4(sc, BWI_MAC_STATUS);
483191762Simp	status |= BWI_MAC_STATUS_IHREN;
484191762Simp	if (link_phy)
485191762Simp		status |= BWI_MAC_STATUS_PHYLNK;
486191762Simp	else
487191762Simp		status &= ~BWI_MAC_STATUS_PHYLNK;
488191762Simp	CSR_WRITE_4(sc, BWI_MAC_STATUS, status);
489191762Simp
490191762Simp	if (link_phy) {
491191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT,
492191762Simp			"%s\n", "PHY is linked");
493191762Simp		mac->mac_phy.phy_flags |= BWI_PHY_F_LINKED;
494191762Simp	} else {
495191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT,
496191762Simp			"%s\n", "PHY is unlinked");
497191762Simp		mac->mac_phy.phy_flags &= ~BWI_PHY_F_LINKED;
498191762Simp	}
499191762Simp}
500191762Simp
501191762Simpvoid
502191762Simpbwi_mac_set_tpctl_11bg(struct bwi_mac *mac, const struct bwi_tpctl *new_tpctl)
503191762Simp{
504191762Simp	struct bwi_rf *rf = &mac->mac_rf;
505191762Simp	struct bwi_tpctl *tpctl = &mac->mac_tpctl;
506191762Simp
507191762Simp	if (new_tpctl != NULL) {
508191762Simp		KASSERT(new_tpctl->bbp_atten <= BWI_BBP_ATTEN_MAX,
509191762Simp		    ("bbp_atten %d", new_tpctl->bbp_atten));
510191762Simp		KASSERT(new_tpctl->rf_atten <=
511191762Simp			 (rf->rf_rev < 6 ? BWI_RF_ATTEN_MAX0
512191762Simp			 		 : BWI_RF_ATTEN_MAX1),
513191762Simp		    ("rf_atten %d", new_tpctl->rf_atten));
514191762Simp		KASSERT(new_tpctl->tp_ctrl1 <= BWI_TPCTL1_MAX,
515191762Simp		    ("tp_ctrl1 %d", new_tpctl->tp_ctrl1));
516191762Simp
517191762Simp		tpctl->bbp_atten = new_tpctl->bbp_atten;
518191762Simp		tpctl->rf_atten = new_tpctl->rf_atten;
519191762Simp		tpctl->tp_ctrl1 = new_tpctl->tp_ctrl1;
520191762Simp	}
521191762Simp
522191762Simp	/* Set BBP attenuation */
523191762Simp	bwi_phy_set_bbp_atten(mac, tpctl->bbp_atten);
524191762Simp
525191762Simp	/* Set RF attenuation */
526191762Simp	RF_WRITE(mac, BWI_RFR_ATTEN, tpctl->rf_atten);
527191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_RF_ATTEN,
528191762Simp		     tpctl->rf_atten);
529191762Simp
530191762Simp	/* Set TX power */
531191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050) {
532191762Simp		RF_FILT_SETBITS(mac, BWI_RFR_TXPWR, ~BWI_RFR_TXPWR1_MASK,
533191762Simp			__SHIFTIN(tpctl->tp_ctrl1, BWI_RFR_TXPWR1_MASK));
534191762Simp	}
535191762Simp
536191762Simp	/* Adjust RF Local Oscillator */
537191762Simp	if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G)
538191762Simp		bwi_rf_lo_adjust(mac, tpctl);
539191762Simp}
540191762Simp
541191762Simpstatic int
542191762Simpbwi_mac_test(struct bwi_mac *mac)
543191762Simp{
544191762Simp	struct bwi_softc *sc = mac->mac_sc;
545191762Simp	uint32_t orig_val, val;
546191762Simp
547191762Simp#define TEST_VAL1	0xaa5555aa
548191762Simp#define TEST_VAL2	0x55aaaa55
549191762Simp
550191762Simp	/* Save it for later restoring */
551191762Simp	orig_val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
552191762Simp
553191762Simp	/* Test 1 */
554191762Simp	MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL1);
555191762Simp	val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
556191762Simp	if (val != TEST_VAL1) {
557191762Simp		device_printf(sc->sc_dev, "TEST1 failed\n");
558191762Simp		return ENXIO;
559191762Simp	}
560191762Simp
561191762Simp	/* Test 2 */
562191762Simp	MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL2);
563191762Simp	val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
564191762Simp	if (val != TEST_VAL2) {
565191762Simp		device_printf(sc->sc_dev, "TEST2 failed\n");
566191762Simp		return ENXIO;
567191762Simp	}
568191762Simp
569191762Simp	/* Restore to the original value */
570191762Simp	MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, orig_val);
571191762Simp
572191762Simp	val = CSR_READ_4(sc, BWI_MAC_STATUS);
573191762Simp	if ((val & ~BWI_MAC_STATUS_PHYLNK) != BWI_MAC_STATUS_IHREN) {
574191762Simp		device_printf(sc->sc_dev, "%s failed, MAC status 0x%08x\n",
575191762Simp			      __func__, val);
576191762Simp		return ENXIO;
577191762Simp	}
578191762Simp
579191762Simp	val = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
580191762Simp	if (val != 0) {
581191762Simp		device_printf(sc->sc_dev, "%s failed, intr status %08x\n",
582191762Simp			      __func__, val);
583191762Simp		return ENXIO;
584191762Simp	}
585191762Simp
586191762Simp#undef TEST_VAL2
587191762Simp#undef TEST_VAL1
588191762Simp
589191762Simp	return 0;
590191762Simp}
591191762Simp
592191762Simpstatic void
593191762Simpbwi_mac_setup_tpctl(struct bwi_mac *mac)
594191762Simp{
595191762Simp	struct bwi_softc *sc = mac->mac_sc;
596191762Simp	struct bwi_rf *rf = &mac->mac_rf;
597191762Simp	struct bwi_phy *phy = &mac->mac_phy;
598191762Simp	struct bwi_tpctl *tpctl = &mac->mac_tpctl;
599191762Simp
600191762Simp	/* Calc BBP attenuation */
601191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev < 6)
602191762Simp		tpctl->bbp_atten = 0;
603191762Simp	else
604191762Simp		tpctl->bbp_atten = 2;
605191762Simp
606191762Simp	/* Calc TX power CTRL1?? */
607191762Simp	tpctl->tp_ctrl1 = 0;
608191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050) {
609191762Simp		if (rf->rf_rev == 1)
610191762Simp			tpctl->tp_ctrl1 = 3;
611191762Simp		else if (rf->rf_rev < 6)
612191762Simp			tpctl->tp_ctrl1 = 2;
613191762Simp		else if (rf->rf_rev == 8)
614191762Simp			tpctl->tp_ctrl1 = 1;
615191762Simp	}
616191762Simp
617191762Simp	/* Empty TX power CTRL2?? */
618191762Simp	tpctl->tp_ctrl2 = 0xffff;
619191762Simp
620191762Simp	/*
621191762Simp	 * Calc RF attenuation
622191762Simp	 */
623191762Simp	if (phy->phy_mode == IEEE80211_MODE_11A) {
624191762Simp		tpctl->rf_atten = 0x60;
625191762Simp		goto back;
626191762Simp	}
627191762Simp
628191762Simp	if (BWI_IS_BRCM_BCM4309G(sc) && sc->sc_pci_revid < 0x51) {
629191762Simp		tpctl->rf_atten = sc->sc_pci_revid < 0x43 ? 2 : 3;
630191762Simp		goto back;
631191762Simp	}
632191762Simp
633191762Simp	tpctl->rf_atten = 5;
634191762Simp
635191762Simp	if (rf->rf_type != BWI_RF_T_BCM2050) {
636191762Simp		if (rf->rf_type == BWI_RF_T_BCM2053 && rf->rf_rev == 1)
637191762Simp			tpctl->rf_atten = 6;
638191762Simp		goto back;
639191762Simp	}
640191762Simp
641191762Simp	/*
642191762Simp	 * NB: If we reaches here and the card is BRCM_BCM4309G,
643191762Simp	 *     then the card's PCI revision must >= 0x51
644191762Simp	 */
645191762Simp
646191762Simp	/* BCM2050 RF */
647191762Simp	switch (rf->rf_rev) {
648191762Simp	case 1:
649191762Simp		if (phy->phy_mode == IEEE80211_MODE_11G) {
650191762Simp			if (BWI_IS_BRCM_BCM4309G(sc) || BWI_IS_BRCM_BU4306(sc))
651191762Simp				tpctl->rf_atten = 3;
652191762Simp			else
653191762Simp				tpctl->rf_atten = 1;
654191762Simp		} else {
655191762Simp			if (BWI_IS_BRCM_BCM4309G(sc))
656191762Simp				tpctl->rf_atten = 7;
657191762Simp			else
658191762Simp				tpctl->rf_atten = 6;
659191762Simp		}
660191762Simp		break;
661191762Simp	case 2:
662191762Simp		if (phy->phy_mode == IEEE80211_MODE_11G) {
663191762Simp			/*
664191762Simp			 * NOTE: Order of following conditions is critical
665191762Simp			 */
666191762Simp			if (BWI_IS_BRCM_BCM4309G(sc))
667191762Simp				tpctl->rf_atten = 3;
668191762Simp			else if (BWI_IS_BRCM_BU4306(sc))
669191762Simp				tpctl->rf_atten = 5;
670191762Simp			else if (sc->sc_bbp_id == BWI_BBPID_BCM4320)
671191762Simp				tpctl->rf_atten = 4;
672191762Simp			else
673191762Simp				tpctl->rf_atten = 3;
674191762Simp		} else {
675191762Simp			tpctl->rf_atten = 6;
676191762Simp		}
677191762Simp		break;
678191762Simp	case 4:
679191762Simp	case 5:
680191762Simp		tpctl->rf_atten = 1;
681191762Simp		break;
682191762Simp	case 8:
683191762Simp		tpctl->rf_atten = 0x1a;
684191762Simp		break;
685191762Simp	}
686191762Simpback:
687191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER,
688191762Simp		"bbp atten: %u, rf atten: %u, ctrl1: %u, ctrl2: %u\n",
689191762Simp		tpctl->bbp_atten, tpctl->rf_atten,
690191762Simp		tpctl->tp_ctrl1, tpctl->tp_ctrl2);
691191762Simp}
692191762Simp
693191762Simpvoid
694191762Simpbwi_mac_dummy_xmit(struct bwi_mac *mac)
695191762Simp{
696191762Simp#define PACKET_LEN	5
697191762Simp	static const uint32_t	packet_11a[PACKET_LEN] =
698191762Simp	{ 0x000201cc, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 };
699191762Simp	static const uint32_t	packet_11bg[PACKET_LEN] =
700191762Simp	{ 0x000b846e, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 };
701191762Simp
702191762Simp	struct bwi_softc *sc = mac->mac_sc;
703191762Simp	struct bwi_rf *rf = &mac->mac_rf;
704191762Simp	const uint32_t *packet;
705191762Simp	uint16_t val_50c;
706191762Simp	int wait_max, i;
707191762Simp
708191762Simp	if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A) {
709191762Simp		wait_max = 30;
710191762Simp		packet = packet_11a;
711191762Simp		val_50c = 1;
712191762Simp	} else {
713191762Simp		wait_max = 250;
714191762Simp		packet = packet_11bg;
715191762Simp		val_50c = 0;
716191762Simp	}
717191762Simp
718191762Simp	for (i = 0; i < PACKET_LEN; ++i)
719191762Simp		TMPLT_WRITE_4(mac, i * 4, packet[i]);
720191762Simp
721191762Simp	CSR_READ_4(sc, BWI_MAC_STATUS);	/* dummy read */
722191762Simp
723191762Simp	CSR_WRITE_2(sc, 0x568, 0);
724191762Simp	CSR_WRITE_2(sc, 0x7c0, 0);
725191762Simp	CSR_WRITE_2(sc, 0x50c, val_50c);
726191762Simp	CSR_WRITE_2(sc, 0x508, 0);
727191762Simp	CSR_WRITE_2(sc, 0x50a, 0);
728191762Simp	CSR_WRITE_2(sc, 0x54c, 0);
729191762Simp	CSR_WRITE_2(sc, 0x56a, 0x14);
730191762Simp	CSR_WRITE_2(sc, 0x568, 0x826);
731191762Simp	CSR_WRITE_2(sc, 0x500, 0);
732191762Simp	CSR_WRITE_2(sc, 0x502, 0x30);
733191762Simp
734191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5)
735191762Simp		RF_WRITE(mac, 0x51, 0x17);
736191762Simp
737191762Simp	for (i = 0; i < wait_max; ++i) {
738191762Simp		if (CSR_READ_2(sc, 0x50e) & 0x80)
739191762Simp			break;
740191762Simp		DELAY(10);
741191762Simp	}
742191762Simp	for (i = 0; i < 10; ++i) {
743191762Simp		if (CSR_READ_2(sc, 0x50e) & 0x400)
744191762Simp			break;
745191762Simp		DELAY(10);
746191762Simp	}
747191762Simp	for (i = 0; i < 10; ++i) {
748191762Simp		if ((CSR_READ_2(sc, 0x690) & 0x100) == 0)
749191762Simp			break;
750191762Simp		DELAY(10);
751191762Simp	}
752191762Simp
753191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5)
754191762Simp		RF_WRITE(mac, 0x51, 0x37);
755191762Simp#undef PACKET_LEN
756191762Simp}
757191762Simp
758191762Simpvoid
759191762Simpbwi_mac_init_tpctl_11bg(struct bwi_mac *mac)
760191762Simp{
761191762Simp	struct bwi_softc *sc = mac->mac_sc;
762191762Simp	struct bwi_phy *phy = &mac->mac_phy;
763191762Simp	struct bwi_rf *rf = &mac->mac_rf;
764191762Simp	struct bwi_tpctl tpctl_orig;
765191762Simp	int restore_tpctl = 0;
766191762Simp
767191762Simp	KASSERT(phy->phy_mode != IEEE80211_MODE_11A,
768191762Simp	    ("phy_mode %d", phy->phy_mode));
769191762Simp
770191762Simp	if (BWI_IS_BRCM_BU4306(sc))
771191762Simp		return;
772191762Simp
773191762Simp	PHY_WRITE(mac, 0x28, 0x8018);
774191762Simp	CSR_CLRBITS_2(sc, BWI_BBP_ATTEN, 0x20);
775191762Simp
776191762Simp	if (phy->phy_mode == IEEE80211_MODE_11G) {
777191762Simp		if ((phy->phy_flags & BWI_PHY_F_LINKED) == 0)
778191762Simp			return;
779191762Simp		PHY_WRITE(mac, 0x47a, 0xc111);
780191762Simp	}
781191762Simp	if (mac->mac_flags & BWI_MAC_F_TPCTL_INITED)
782191762Simp		return;
783191762Simp
784191762Simp	if (phy->phy_mode == IEEE80211_MODE_11B && phy->phy_rev >= 2 &&
785191762Simp	    rf->rf_type == BWI_RF_T_BCM2050) {
786191762Simp		RF_SETBITS(mac, 0x76, 0x84);
787191762Simp	} else {
788191762Simp		struct bwi_tpctl tpctl;
789191762Simp
790191762Simp		/* Backup original TX power control variables */
791191762Simp		bcopy(&mac->mac_tpctl, &tpctl_orig, sizeof(tpctl_orig));
792191762Simp		restore_tpctl = 1;
793191762Simp
794191762Simp		bcopy(&mac->mac_tpctl, &tpctl, sizeof(tpctl));
795191762Simp		tpctl.bbp_atten = 11;
796191762Simp		tpctl.tp_ctrl1 = 0;
797191762Simp#ifdef notyet
798191762Simp		if (rf->rf_rev >= 6 && rf->rf_rev <= 8)
799191762Simp			tpctl.rf_atten = 31;
800191762Simp		else
801191762Simp#endif
802191762Simp			tpctl.rf_atten = 9;
803191762Simp
804191762Simp		bwi_mac_set_tpctl_11bg(mac, &tpctl);
805191762Simp	}
806191762Simp
807191762Simp	bwi_mac_dummy_xmit(mac);
808191762Simp
809191762Simp	mac->mac_flags |= BWI_MAC_F_TPCTL_INITED;
810191762Simp	rf->rf_base_tssi = PHY_READ(mac, 0x29);
811191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER,
812191762Simp		"base tssi %d\n", rf->rf_base_tssi);
813191762Simp
814191762Simp	if (abs(rf->rf_base_tssi - rf->rf_idle_tssi) >= 20) {
815191762Simp		device_printf(sc->sc_dev, "base tssi measure failed\n");
816191762Simp		mac->mac_flags |= BWI_MAC_F_TPCTL_ERROR;
817191762Simp	}
818191762Simp
819191762Simp	if (restore_tpctl)
820191762Simp		bwi_mac_set_tpctl_11bg(mac, &tpctl_orig);
821191762Simp	else
822191762Simp		RF_CLRBITS(mac, 0x76, 0x84);
823191762Simp
824191762Simp	bwi_rf_clear_tssi(mac);
825191762Simp}
826191762Simp
827191762Simpvoid
828191762Simpbwi_mac_detach(struct bwi_mac *mac)
829191762Simp{
830191762Simp	bwi_mac_fw_free(mac);
831191762Simp}
832191762Simp
833191762Simpstatic __inline int
834191762Simpbwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw,
835191762Simp		     uint8_t fw_type)
836191762Simp{
837191762Simp	const struct bwi_fwhdr *hdr;
838191762Simp	struct ifnet *ifp = sc->sc_ifp;
839191762Simp
840191762Simp	if (fw->datasize < sizeof(*hdr)) {
841191762Simp		if_printf(ifp, "invalid firmware (%s): invalid size %zu\n",
842191762Simp			  fw->name, fw->datasize);
843191762Simp		return 0;
844191762Simp	}
845191762Simp
846191762Simp	hdr = (const struct bwi_fwhdr *)fw->data;
847191762Simp
848191762Simp	if (fw_type != BWI_FW_T_IV) {
849191762Simp		/*
850191762Simp		 * Don't verify IV's size, it has different meaning
851191762Simp		 */
852191762Simp		if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) {
853191762Simp			if_printf(ifp, "invalid firmware (%s): size mismatch, "
854191762Simp				  "fw %u, real %zu\n", fw->name,
855191762Simp				  be32toh(hdr->fw_size),
856191762Simp				  fw->datasize - sizeof(*hdr));
857191762Simp			return 0;
858191762Simp		}
859191762Simp	}
860191762Simp
861191762Simp	if (hdr->fw_type != fw_type) {
862191762Simp		if_printf(ifp, "invalid firmware (%s): type mismatch, "
863191762Simp			  "fw \'%c\', target \'%c\'\n", fw->name,
864191762Simp			  hdr->fw_type, fw_type);
865191762Simp		return 0;
866191762Simp	}
867191762Simp
868191762Simp	if (hdr->fw_gen != BWI_FW_GEN_1) {
869191762Simp		if_printf(ifp, "invalid firmware (%s): wrong generation, "
870191762Simp			  "fw %d, target %d\n", fw->name,
871191762Simp			  hdr->fw_gen, BWI_FW_GEN_1);
872191762Simp		return 0;
873191762Simp	}
874191762Simp	return 1;
875191762Simp}
876191762Simp
877191762Simp/*
878191762Simp * XXX Error cleanup
879191762Simp */
880191762Simpstatic int
881191762Simpbwi_mac_fw_alloc(struct bwi_mac *mac)
882191762Simp{
883191762Simp	struct bwi_softc *sc = mac->mac_sc;
884191762Simp	struct ifnet *ifp = sc->sc_ifp;
885191762Simp	char fwname[64];
886191762Simp	int idx;
887191762Simp
888191762Simp	/*
889191762Simp	 * Try getting the firmware stub so firmware
890191762Simp	 * module would be loaded automatically
891191762Simp	 */
892191762Simp	if (mac->mac_stub == NULL) {
893191762Simp		snprintf(fwname, sizeof(fwname), BWI_FW_STUB_PATH,
894191762Simp			 sc->sc_fw_version);
895191762Simp		mac->mac_stub = firmware_get(fwname);
896191762Simp		if (mac->mac_stub == NULL) {
897191762Simp			if_printf(ifp, "request firmware %s failed\n", fwname);
898191762Simp			return ENOMEM;
899191762Simp		}
900191762Simp	}
901191762Simp
902191762Simp	if (mac->mac_ucode == NULL) {
903191762Simp		snprintf(fwname, sizeof(fwname), BWI_FW_UCODE_PATH,
904191762Simp			  sc->sc_fw_version,
905191762Simp			  mac->mac_rev >= 5 ? 5 : mac->mac_rev);
906191762Simp
907191762Simp		mac->mac_ucode = firmware_get(fwname);
908191762Simp		if (mac->mac_ucode == NULL) {
909191762Simp			if_printf(ifp, "request firmware %s failed\n", fwname);
910191762Simp			return ENOMEM;
911191762Simp		}
912191762Simp
913191762Simp		if (!bwi_fwimage_is_valid(sc, mac->mac_ucode, BWI_FW_T_UCODE))
914191762Simp			return EINVAL;
915191762Simp	}
916191762Simp
917191762Simp	if (mac->mac_pcm == NULL) {
918191762Simp		snprintf(fwname, sizeof(fwname), BWI_FW_PCM_PATH,
919191762Simp			  sc->sc_fw_version,
920191762Simp			  mac->mac_rev < 5 ? 4 : 5);
921191762Simp
922191762Simp		mac->mac_pcm = firmware_get(fwname);
923191762Simp		if (mac->mac_pcm == NULL) {
924191762Simp			if_printf(ifp, "request firmware %s failed\n", fwname);
925191762Simp			return ENOMEM;
926191762Simp		}
927191762Simp
928191762Simp		if (!bwi_fwimage_is_valid(sc, mac->mac_pcm, BWI_FW_T_PCM))
929191762Simp			return EINVAL;
930191762Simp	}
931191762Simp
932191762Simp	if (mac->mac_iv == NULL) {
933191762Simp		/* TODO: 11A */
934191762Simp		if (mac->mac_rev == 2 || mac->mac_rev == 4) {
935191762Simp			idx = 2;
936191762Simp		} else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) {
937191762Simp			idx = 5;
938191762Simp		} else {
939191762Simp			if_printf(ifp, "no suitible IV for MAC rev %d\n",
940191762Simp				  mac->mac_rev);
941191762Simp			return ENODEV;
942191762Simp		}
943191762Simp
944191762Simp		snprintf(fwname, sizeof(fwname), BWI_FW_IV_PATH,
945191762Simp			  sc->sc_fw_version, idx);
946191762Simp
947191762Simp		mac->mac_iv = firmware_get(fwname);
948191762Simp		if (mac->mac_iv == NULL) {
949191762Simp			if_printf(ifp, "request firmware %s failed\n", fwname);
950191762Simp			return ENOMEM;
951191762Simp		}
952191762Simp		if (!bwi_fwimage_is_valid(sc, mac->mac_iv, BWI_FW_T_IV))
953191762Simp			return EINVAL;
954191762Simp	}
955191762Simp
956191762Simp	if (mac->mac_iv_ext == NULL) {
957191762Simp		/* TODO: 11A */
958191762Simp		if (mac->mac_rev == 2 || mac->mac_rev == 4 ||
959191762Simp		    mac->mac_rev >= 11) {
960191762Simp			/* No extended IV */
961191762Simp			goto back;
962191762Simp		} else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) {
963191762Simp			idx = 5;
964191762Simp		} else {
965191762Simp			if_printf(ifp, "no suitible ExtIV for MAC rev %d\n",
966191762Simp				  mac->mac_rev);
967191762Simp			return ENODEV;
968191762Simp		}
969191762Simp
970191762Simp		snprintf(fwname, sizeof(fwname), BWI_FW_IV_EXT_PATH,
971191762Simp			  sc->sc_fw_version, idx);
972191762Simp
973191762Simp		mac->mac_iv_ext = firmware_get(fwname);
974191762Simp		if (mac->mac_iv_ext == NULL) {
975191762Simp			if_printf(ifp, "request firmware %s failed\n", fwname);
976191762Simp			return ENOMEM;
977191762Simp		}
978191762Simp		if (!bwi_fwimage_is_valid(sc, mac->mac_iv_ext, BWI_FW_T_IV))
979191762Simp			return EINVAL;
980191762Simp	}
981191762Simpback:
982191762Simp	return 0;
983191762Simp}
984191762Simp
985191762Simpstatic void
986191762Simpbwi_mac_fw_free(struct bwi_mac *mac)
987191762Simp{
988191762Simp	if (mac->mac_ucode != NULL) {
989191762Simp		firmware_put(mac->mac_ucode, FIRMWARE_UNLOAD);
990191762Simp		mac->mac_ucode = NULL;
991191762Simp	}
992191762Simp
993191762Simp	if (mac->mac_pcm != NULL) {
994191762Simp		firmware_put(mac->mac_pcm, FIRMWARE_UNLOAD);
995191762Simp		mac->mac_pcm = NULL;
996191762Simp	}
997191762Simp
998191762Simp	if (mac->mac_iv != NULL) {
999191762Simp		firmware_put(mac->mac_iv, FIRMWARE_UNLOAD);
1000191762Simp		mac->mac_iv = NULL;
1001191762Simp	}
1002191762Simp
1003191762Simp	if (mac->mac_iv_ext != NULL) {
1004191762Simp		firmware_put(mac->mac_iv_ext, FIRMWARE_UNLOAD);
1005191762Simp		mac->mac_iv_ext = NULL;
1006191762Simp	}
1007191762Simp
1008191762Simp	if (mac->mac_stub != NULL) {
1009191762Simp		firmware_put(mac->mac_stub, FIRMWARE_UNLOAD);
1010191762Simp		mac->mac_stub = NULL;
1011191762Simp	}
1012191762Simp}
1013191762Simp
1014191762Simpstatic int
1015191762Simpbwi_mac_fw_load(struct bwi_mac *mac)
1016191762Simp{
1017191762Simp	struct bwi_softc *sc = mac->mac_sc;
1018191762Simp	struct ifnet *ifp = sc->sc_ifp;
1019191762Simp	const uint32_t *fw;
1020191762Simp	uint16_t fw_rev;
1021191762Simp	int fw_len, i;
1022191762Simp
1023191762Simp	/*
1024191762Simp	 * Load ucode image
1025191762Simp	 */
1026191762Simp	fw = (const uint32_t *)
1027191762Simp	     ((const uint8_t *)mac->mac_ucode->data + BWI_FWHDR_SZ);
1028191762Simp	fw_len = (mac->mac_ucode->datasize - BWI_FWHDR_SZ) / sizeof(uint32_t);
1029191762Simp
1030191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
1031191762Simp		    BWI_MOBJ_CTRL_VAL(
1032191762Simp		    BWI_FW_UCODE_MOBJ | BWI_WR_MOBJ_AUTOINC, 0));
1033191762Simp	for (i = 0; i < fw_len; ++i) {
1034191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_DATA, be32toh(fw[i]));
1035191762Simp		DELAY(10);
1036191762Simp	}
1037191762Simp
1038191762Simp	/*
1039191762Simp	 * Load PCM image
1040191762Simp	 */
1041191762Simp	fw = (const uint32_t *)
1042191762Simp	     ((const uint8_t *)mac->mac_pcm->data + BWI_FWHDR_SZ);
1043191762Simp	fw_len = (mac->mac_pcm->datasize - BWI_FWHDR_SZ) / sizeof(uint32_t);
1044191762Simp
1045191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
1046191762Simp		    BWI_MOBJ_CTRL_VAL(BWI_FW_PCM_MOBJ, 0x01ea));
1047191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_DATA, 0x4000);
1048191762Simp
1049191762Simp	CSR_WRITE_4(sc, BWI_MOBJ_CTRL,
1050191762Simp		    BWI_MOBJ_CTRL_VAL(BWI_FW_PCM_MOBJ, 0x01eb));
1051191762Simp	for (i = 0; i < fw_len; ++i) {
1052191762Simp		CSR_WRITE_4(sc, BWI_MOBJ_DATA, be32toh(fw[i]));
1053191762Simp		DELAY(10);
1054191762Simp	}
1055191762Simp
1056191762Simp	CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_ALL_INTRS);
1057191762Simp	CSR_WRITE_4(sc, BWI_MAC_STATUS,
1058191762Simp		    BWI_MAC_STATUS_UCODE_START |
1059191762Simp		    BWI_MAC_STATUS_IHREN |
1060191762Simp		    BWI_MAC_STATUS_INFRA);
1061191762Simp
1062191762Simp#define NRETRY	200
1063191762Simp
1064191762Simp	for (i = 0; i < NRETRY; ++i) {
1065191762Simp		uint32_t intr_status;
1066191762Simp
1067191762Simp		intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
1068191762Simp		if (intr_status == BWI_INTR_READY)
1069191762Simp			break;
1070191762Simp		DELAY(10);
1071191762Simp	}
1072191762Simp	if (i == NRETRY) {
1073191762Simp		if_printf(ifp, "firmware (ucode&pcm) loading timed out\n");
1074191762Simp		return ETIMEDOUT;
1075191762Simp	}
1076191762Simp
1077191762Simp#undef NRETRY
1078191762Simp
1079191762Simp	CSR_READ_4(sc, BWI_MAC_INTR_STATUS);	/* dummy read */
1080191762Simp
1081191762Simp	fw_rev = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWREV);
1082191762Simp	if (fw_rev > BWI_FW_VERSION3_REVMAX) {
1083191762Simp		if_printf(ifp, "firmware version 4 is not supported yet\n");
1084191762Simp		return ENODEV;
1085191762Simp	}
1086191762Simp
1087191762Simp	if_printf(ifp, "firmware rev 0x%04x, patch level 0x%04x\n", fw_rev,
1088191762Simp		  MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV));
1089191762Simp	return 0;
1090191762Simp}
1091191762Simp
1092191762Simpstatic int
1093191762Simpbwi_mac_gpio_init(struct bwi_mac *mac)
1094191762Simp{
1095191762Simp	struct bwi_softc *sc = mac->mac_sc;
1096191762Simp	struct bwi_regwin *old, *gpio_rw;
1097191762Simp	uint32_t filt, bits;
1098191762Simp	int error;
1099191762Simp
1100191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_GPOSEL_MASK);
1101191762Simp	/* TODO:LED */
1102191762Simp
1103191762Simp	CSR_SETBITS_2(sc, BWI_MAC_GPIO_MASK, 0xf);
1104191762Simp
1105191762Simp	filt = 0x1f;
1106191762Simp	bits = 0xf;
1107191762Simp	if (sc->sc_bbp_id == BWI_BBPID_BCM4301) {
1108191762Simp		filt |= 0x60;
1109191762Simp		bits |= 0x60;
1110191762Simp	}
1111191762Simp	if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) {
1112191762Simp		CSR_SETBITS_2(sc, BWI_MAC_GPIO_MASK, 0x200);
1113191762Simp		filt |= 0x200;
1114191762Simp		bits |= 0x200;
1115191762Simp	}
1116191762Simp
1117191762Simp	gpio_rw = BWI_GPIO_REGWIN(sc);
1118191762Simp	error = bwi_regwin_switch(sc, gpio_rw, &old);
1119191762Simp	if (error)
1120191762Simp		return error;
1121191762Simp
1122191762Simp	CSR_FILT_SETBITS_4(sc, BWI_GPIO_CTRL, filt, bits);
1123191762Simp
1124191762Simp	return bwi_regwin_switch(sc, old, NULL);
1125191762Simp}
1126191762Simp
1127191762Simpstatic int
1128191762Simpbwi_mac_gpio_fini(struct bwi_mac *mac)
1129191762Simp{
1130191762Simp	struct bwi_softc *sc = mac->mac_sc;
1131191762Simp	struct bwi_regwin *old, *gpio_rw;
1132191762Simp	int error;
1133191762Simp
1134191762Simp	gpio_rw = BWI_GPIO_REGWIN(sc);
1135191762Simp	error = bwi_regwin_switch(sc, gpio_rw, &old);
1136191762Simp	if (error)
1137191762Simp		return error;
1138191762Simp
1139191762Simp	CSR_WRITE_4(sc, BWI_GPIO_CTRL, 0);
1140191762Simp
1141191762Simp	return bwi_regwin_switch(sc, old, NULL);
1142191762Simp}
1143191762Simp
1144191762Simpstatic int
1145191762Simpbwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw)
1146191762Simp{
1147191762Simp	struct bwi_softc *sc = mac->mac_sc;
1148191762Simp	struct ifnet *ifp = sc->sc_ifp;
1149191762Simp	const struct bwi_fwhdr *hdr;
1150191762Simp	const struct bwi_fw_iv *iv;
1151191762Simp	int n, i, iv_img_size;
1152191762Simp
1153191762Simp	/* Get the number of IVs in the IV image */
1154191762Simp	hdr = (const struct bwi_fwhdr *)fw->data;
1155191762Simp	n = be32toh(hdr->fw_iv_cnt);
1156191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_FIRMWARE,
1157191762Simp		"IV count %d\n", n);
1158191762Simp
1159191762Simp	/* Calculate the IV image size, for later sanity check */
1160191762Simp	iv_img_size = fw->datasize - sizeof(*hdr);
1161191762Simp
1162191762Simp	/* Locate the first IV */
1163191762Simp	iv = (const struct bwi_fw_iv *)
1164191762Simp	     ((const uint8_t *)fw->data + sizeof(*hdr));
1165191762Simp
1166191762Simp	for (i = 0; i < n; ++i) {
1167191762Simp		uint16_t iv_ofs, ofs;
1168191762Simp		int sz = 0;
1169191762Simp
1170191762Simp		if (iv_img_size < sizeof(iv->iv_ofs)) {
1171191762Simp			if_printf(ifp, "invalid IV image, ofs\n");
1172191762Simp			return EINVAL;
1173191762Simp		}
1174191762Simp		iv_img_size -= sizeof(iv->iv_ofs);
1175191762Simp		sz += sizeof(iv->iv_ofs);
1176191762Simp
1177191762Simp		iv_ofs = be16toh(iv->iv_ofs);
1178191762Simp
1179191762Simp		ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK);
1180191762Simp		if (ofs >= 0x1000) {
1181191762Simp			if_printf(ifp, "invalid ofs (0x%04x) "
1182191762Simp				  "for %dth iv\n", ofs, i);
1183191762Simp			return EINVAL;
1184191762Simp		}
1185191762Simp
1186191762Simp		if (iv_ofs & BWI_FW_IV_IS_32BIT) {
1187191762Simp			uint32_t val32;
1188191762Simp
1189191762Simp			if (iv_img_size < sizeof(iv->iv_val.val32)) {
1190191762Simp				if_printf(ifp, "invalid IV image, val32\n");
1191191762Simp				return EINVAL;
1192191762Simp			}
1193191762Simp			iv_img_size -= sizeof(iv->iv_val.val32);
1194191762Simp			sz += sizeof(iv->iv_val.val32);
1195191762Simp
1196191762Simp			val32 = be32toh(iv->iv_val.val32);
1197191762Simp			CSR_WRITE_4(sc, ofs, val32);
1198191762Simp		} else {
1199191762Simp			uint16_t val16;
1200191762Simp
1201191762Simp			if (iv_img_size < sizeof(iv->iv_val.val16)) {
1202191762Simp				if_printf(ifp, "invalid IV image, val16\n");
1203191762Simp				return EINVAL;
1204191762Simp			}
1205191762Simp			iv_img_size -= sizeof(iv->iv_val.val16);
1206191762Simp			sz += sizeof(iv->iv_val.val16);
1207191762Simp
1208191762Simp			val16 = be16toh(iv->iv_val.val16);
1209191762Simp			CSR_WRITE_2(sc, ofs, val16);
1210191762Simp		}
1211191762Simp
1212191762Simp		iv = (const struct bwi_fw_iv *)((const uint8_t *)iv + sz);
1213191762Simp	}
1214191762Simp
1215191762Simp	if (iv_img_size != 0) {
1216191762Simp		if_printf(ifp, "invalid IV image, size left %d\n", iv_img_size);
1217191762Simp		return EINVAL;
1218191762Simp	}
1219191762Simp	return 0;
1220191762Simp}
1221191762Simp
1222191762Simpstatic int
1223191762Simpbwi_mac_fw_init(struct bwi_mac *mac)
1224191762Simp{
1225191762Simp	struct ifnet *ifp = mac->mac_sc->sc_ifp;
1226191762Simp	int error;
1227191762Simp
1228191762Simp	error = bwi_mac_fw_load_iv(mac, mac->mac_iv);
1229191762Simp	if (error) {
1230191762Simp		if_printf(ifp, "load IV failed\n");
1231191762Simp		return error;
1232191762Simp	}
1233191762Simp
1234191762Simp	if (mac->mac_iv_ext != NULL) {
1235191762Simp		error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext);
1236191762Simp		if (error)
1237191762Simp			if_printf(ifp, "load ExtIV failed\n");
1238191762Simp	}
1239191762Simp	return error;
1240191762Simp}
1241191762Simp
1242191762Simpstatic void
1243191762Simpbwi_mac_opmode_init(struct bwi_mac *mac)
1244191762Simp{
1245191762Simp	struct bwi_softc *sc = mac->mac_sc;
1246191762Simp	struct ifnet *ifp = sc->sc_ifp;
1247191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1248191762Simp	uint32_t mac_status;
1249191762Simp	uint16_t pre_tbtt;
1250191762Simp
1251191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA);
1252191762Simp	CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA);
1253191762Simp
1254191762Simp	/* Set probe resp timeout to infinite */
1255191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 0);
1256191762Simp
1257191762Simp	/*
1258191762Simp	 * TODO: factor out following part
1259191762Simp	 */
1260191762Simp
1261191762Simp	mac_status = CSR_READ_4(sc, BWI_MAC_STATUS);
1262191762Simp	mac_status &= ~(BWI_MAC_STATUS_OPMODE_HOSTAP |
1263191762Simp			BWI_MAC_STATUS_PASS_CTL |
1264191762Simp			BWI_MAC_STATUS_PASS_BCN |
1265191762Simp			BWI_MAC_STATUS_PASS_BADPLCP |
1266191762Simp			BWI_MAC_STATUS_PASS_BADFCS |
1267191762Simp			BWI_MAC_STATUS_PROMISC);
1268191762Simp	mac_status |= BWI_MAC_STATUS_INFRA;
1269191762Simp
1270191762Simp	/* Always turn on PROMISC on old hardware */
1271191762Simp	if (mac->mac_rev < 5)
1272191762Simp		mac_status |= BWI_MAC_STATUS_PROMISC;
1273191762Simp
1274191762Simp	switch (ic->ic_opmode) {
1275191762Simp	case IEEE80211_M_IBSS:
1276191762Simp		mac_status &= ~BWI_MAC_STATUS_INFRA;
1277191762Simp		break;
1278191762Simp	case IEEE80211_M_HOSTAP:
1279191762Simp		mac_status |= BWI_MAC_STATUS_OPMODE_HOSTAP;
1280191762Simp		break;
1281191762Simp	case IEEE80211_M_MONITOR:
1282191762Simp#if 0
1283191762Simp		/* Do you want data from your microwave oven? */
1284191762Simp		mac_status |= BWI_MAC_STATUS_PASS_CTL |
1285191762Simp			      BWI_MAC_STATUS_PASS_BADPLCP |
1286191762Simp			      BWI_MAC_STATUS_PASS_BADFCS;
1287191762Simp#else
1288191762Simp		mac_status |= BWI_MAC_STATUS_PASS_CTL;
1289191762Simp#endif
1290191762Simp		/* Promisc? */
1291191762Simp		break;
1292191762Simp	default:
1293191762Simp		break;
1294191762Simp	}
1295191762Simp
1296191762Simp	if (ic->ic_ifp->if_flags & IFF_PROMISC)
1297191762Simp		mac_status |= BWI_MAC_STATUS_PROMISC;
1298191762Simp
1299191762Simp	CSR_WRITE_4(sc, BWI_MAC_STATUS, mac_status);
1300191762Simp
1301191762Simp	if (ic->ic_opmode != IEEE80211_M_IBSS &&
1302191762Simp	    ic->ic_opmode != IEEE80211_M_HOSTAP) {
1303191762Simp		if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_rev == 3)
1304191762Simp			pre_tbtt = 100;
1305191762Simp		else
1306191762Simp			pre_tbtt = 50;
1307191762Simp	} else {
1308191762Simp		pre_tbtt = 2;
1309191762Simp	}
1310191762Simp	CSR_WRITE_2(sc, BWI_MAC_PRE_TBTT, pre_tbtt);
1311191762Simp}
1312191762Simp
1313191762Simpstatic void
1314191762Simpbwi_mac_hostflags_init(struct bwi_mac *mac)
1315191762Simp{
1316191762Simp	struct bwi_softc *sc = mac->mac_sc;
1317191762Simp	struct bwi_phy *phy = &mac->mac_phy;
1318191762Simp	struct bwi_rf *rf = &mac->mac_rf;
1319191762Simp	uint64_t host_flags;
1320191762Simp
1321191762Simp	if (phy->phy_mode == IEEE80211_MODE_11A)
1322191762Simp		return;
1323191762Simp
1324191762Simp	host_flags = HFLAGS_READ(mac);
1325191762Simp	host_flags |= BWI_HFLAG_SYM_WA;
1326191762Simp
1327191762Simp	if (phy->phy_mode == IEEE80211_MODE_11G) {
1328191762Simp		if (phy->phy_rev == 1)
1329191762Simp			host_flags |= BWI_HFLAG_GDC_WA;
1330191762Simp		if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9)
1331191762Simp			host_flags |= BWI_HFLAG_OFDM_PA;
1332191762Simp	} else if (phy->phy_mode == IEEE80211_MODE_11B) {
1333191762Simp		if (phy->phy_rev >= 2 && rf->rf_type == BWI_RF_T_BCM2050)
1334191762Simp			host_flags &= ~BWI_HFLAG_GDC_WA;
1335191762Simp	} else {
1336191762Simp		panic("unknown PHY mode %u\n", phy->phy_mode);
1337191762Simp	}
1338191762Simp
1339191762Simp	HFLAGS_WRITE(mac, host_flags);
1340191762Simp}
1341191762Simp
1342191762Simpstatic void
1343191762Simpbwi_mac_bss_param_init(struct bwi_mac *mac)
1344191762Simp{
1345191762Simp	struct bwi_softc *sc = mac->mac_sc;
1346191762Simp	struct bwi_phy *phy = &mac->mac_phy;
1347191762Simp	struct ifnet *ifp = sc->sc_ifp;
1348191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1349191762Simp	const struct ieee80211_rate_table *rt;
1350191762Simp	struct bwi_retry_lim lim;
1351191762Simp	uint16_t cw_min;
1352191762Simp
1353191762Simp	/*
1354191762Simp	 * Set short/long retry limits
1355191762Simp	 */
1356191762Simp	bzero(&lim, sizeof(lim));
1357191762Simp	lim.shretry = BWI_SHRETRY;
1358191762Simp	lim.shretry_fb = BWI_SHRETRY_FB;
1359191762Simp	lim.lgretry = BWI_LGRETRY;
1360191762Simp	lim.lgretry_fb = BWI_LGRETRY_FB;
1361191762Simp	bwi_mac_set_retry_lim(mac, &lim);
1362191762Simp
1363191762Simp	/*
1364191762Simp	 * Implicitly prevent firmware from sending probe response
1365191762Simp	 * by setting its "probe response timeout" to 1us.
1366191762Simp	 */
1367191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 1);
1368191762Simp
1369191762Simp	/*
1370191762Simp	 * XXX MAC level acknowledge and CW min/max should depend
1371191762Simp	 * on the char rateset of the IBSS/BSS to join.
1372191762Simp	 * XXX this is all wrong; should be done on channel change
1373191762Simp	 */
1374191762Simp	if (phy->phy_mode == IEEE80211_MODE_11B) {
1375191762Simp		rt = ieee80211_get_ratetable(
1376191762Simp		    ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_B));
1377191762Simp		bwi_mac_set_ackrates(mac, rt,
1378191762Simp		    &ic->ic_sup_rates[IEEE80211_MODE_11B]);
1379191762Simp	} else {
1380191762Simp		rt = ieee80211_get_ratetable(
1381191762Simp		    ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_G));
1382191762Simp		bwi_mac_set_ackrates(mac, rt,
1383191762Simp		    &ic->ic_sup_rates[IEEE80211_MODE_11G]);
1384191762Simp	}
1385191762Simp
1386191762Simp	/*
1387191762Simp	 * Set CW min
1388191762Simp	 */
1389191762Simp	if (phy->phy_mode == IEEE80211_MODE_11B)
1390191762Simp		cw_min = IEEE80211_CW_MIN_0;
1391191762Simp	else
1392191762Simp		cw_min = IEEE80211_CW_MIN_1;
1393191762Simp	MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_CWMIN, cw_min);
1394191762Simp
1395191762Simp	/*
1396191762Simp	 * Set CW max
1397191762Simp	 */
1398191762Simp	MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_CWMAX,
1399191762Simp		     IEEE80211_CW_MAX);
1400191762Simp}
1401191762Simp
1402191762Simpstatic void
1403191762Simpbwi_mac_set_retry_lim(struct bwi_mac *mac, const struct bwi_retry_lim *lim)
1404191762Simp{
1405191762Simp	/* Short/Long retry limit */
1406191762Simp	MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_SHRETRY,
1407191762Simp		     lim->shretry);
1408191762Simp	MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_LGRETRY,
1409191762Simp		     lim->lgretry);
1410191762Simp
1411191762Simp	/* Short/Long retry fallback limit */
1412191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_SHRETRY_FB,
1413191762Simp		     lim->shretry_fb);
1414191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_LGRETEY_FB,
1415191762Simp		     lim->lgretry_fb);
1416191762Simp}
1417191762Simp
1418191762Simpstatic void
1419191762Simpbwi_mac_set_ackrates(struct bwi_mac *mac, const struct ieee80211_rate_table *rt,
1420191762Simp	const struct ieee80211_rateset *rs)
1421191762Simp{
1422191762Simp	int i;
1423191762Simp
1424191762Simp	/* XXX not standard conforming */
1425191762Simp	for (i = 0; i < rs->rs_nrates; ++i) {
1426191762Simp		enum ieee80211_phytype modtype;
1427191762Simp		uint16_t ofs;
1428191762Simp
1429191762Simp		modtype = ieee80211_rate2phytype(rt, rs->rs_rates[i]);
1430191762Simp		switch (modtype) {
1431191762Simp		case IEEE80211_T_DS:
1432191762Simp			ofs = 0x4c0;
1433191762Simp			break;
1434191762Simp		case IEEE80211_T_OFDM:
1435191762Simp			ofs = 0x480;
1436191762Simp			break;
1437191762Simp		default:
1438191762Simp			panic("unsupported modtype %u\n", modtype);
1439191762Simp		}
1440191762Simp		ofs += 2*(ieee80211_rate2plcp(rs->rs_rates[i], modtype) & 0xf);
1441191762Simp
1442191762Simp		MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, ofs + 0x20,
1443191762Simp			     MOBJ_READ_2(mac, BWI_COMM_MOBJ, ofs));
1444191762Simp	}
1445191762Simp}
1446191762Simp
1447191762Simpint
1448191762Simpbwi_mac_start(struct bwi_mac *mac)
1449191762Simp{
1450191762Simp	struct bwi_softc *sc = mac->mac_sc;
1451191762Simp
1452191762Simp	CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_ENABLE);
1453191762Simp	CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_INTR_READY);
1454191762Simp
1455191762Simp	/* Flush pending bus writes */
1456191762Simp	CSR_READ_4(sc, BWI_MAC_STATUS);
1457191762Simp	CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
1458191762Simp
1459191762Simp	return bwi_mac_config_ps(mac);
1460191762Simp}
1461191762Simp
1462191762Simpint
1463191762Simpbwi_mac_stop(struct bwi_mac *mac)
1464191762Simp{
1465191762Simp	struct bwi_softc *sc = mac->mac_sc;
1466191762Simp	int error, i;
1467191762Simp
1468191762Simp	error = bwi_mac_config_ps(mac);
1469191762Simp	if (error)
1470191762Simp		return error;
1471191762Simp
1472191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_ENABLE);
1473191762Simp
1474191762Simp	/* Flush pending bus write */
1475191762Simp	CSR_READ_4(sc, BWI_MAC_STATUS);
1476191762Simp
1477191762Simp#define NRETRY	10000
1478191762Simp	for (i = 0; i < NRETRY; ++i) {
1479191762Simp		if (CSR_READ_4(sc, BWI_MAC_INTR_STATUS) & BWI_INTR_READY)
1480191762Simp			break;
1481191762Simp		DELAY(1);
1482191762Simp	}
1483191762Simp	if (i == NRETRY) {
1484191762Simp		device_printf(sc->sc_dev, "can't stop MAC\n");
1485191762Simp		return ETIMEDOUT;
1486191762Simp	}
1487191762Simp#undef NRETRY
1488191762Simp
1489191762Simp	return 0;
1490191762Simp}
1491191762Simp
1492191762Simpint
1493191762Simpbwi_mac_config_ps(struct bwi_mac *mac)
1494191762Simp{
1495191762Simp	struct bwi_softc *sc = mac->mac_sc;
1496191762Simp	uint32_t status;
1497191762Simp
1498191762Simp	status = CSR_READ_4(sc, BWI_MAC_STATUS);
1499191762Simp
1500191762Simp	status &= ~BWI_MAC_STATUS_HW_PS;
1501191762Simp	status |= BWI_MAC_STATUS_WAKEUP;
1502191762Simp	CSR_WRITE_4(sc, BWI_MAC_STATUS, status);
1503191762Simp
1504191762Simp	/* Flush pending bus write */
1505191762Simp	CSR_READ_4(sc, BWI_MAC_STATUS);
1506191762Simp
1507191762Simp	if (mac->mac_rev >= 5) {
1508191762Simp		int i;
1509191762Simp
1510191762Simp#define NRETRY	100
1511191762Simp		for (i = 0; i < NRETRY; ++i) {
1512191762Simp			if (MOBJ_READ_2(mac, BWI_COMM_MOBJ,
1513191762Simp			    BWI_COMM_MOBJ_UCODE_STATE) != BWI_UCODE_STATE_PS)
1514191762Simp				break;
1515191762Simp			DELAY(10);
1516191762Simp		}
1517191762Simp		if (i == NRETRY) {
1518191762Simp			device_printf(sc->sc_dev, "config PS failed\n");
1519191762Simp			return ETIMEDOUT;
1520191762Simp		}
1521191762Simp#undef NRETRY
1522191762Simp	}
1523191762Simp	return 0;
1524191762Simp}
1525191762Simp
1526191762Simpvoid
1527191762Simpbwi_mac_reset_hwkeys(struct bwi_mac *mac)
1528191762Simp{
1529191762Simp	/* TODO: firmware crypto */
1530191762Simp	MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_KEYTABLE_OFS);
1531191762Simp}
1532191762Simp
1533191762Simpvoid
1534191762Simpbwi_mac_shutdown(struct bwi_mac *mac)
1535191762Simp{
1536191762Simp	struct bwi_softc *sc = mac->mac_sc;
1537191762Simp	int i;
1538191762Simp
1539191762Simp	if (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS)
1540191762Simp		sc->sc_free_txstats(sc);
1541191762Simp
1542191762Simp	sc->sc_free_rx_ring(sc);
1543191762Simp
1544191762Simp	for (i = 0; i < BWI_TX_NRING; ++i)
1545191762Simp		sc->sc_free_tx_ring(sc, i);
1546191762Simp
1547191762Simp	bwi_rf_off(mac);
1548191762Simp
1549191762Simp	/* TODO:LED */
1550191762Simp
1551191762Simp	bwi_mac_gpio_fini(mac);
1552191762Simp
1553191762Simp	bwi_rf_off(mac); /* XXX again */
1554191762Simp	CSR_WRITE_2(sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC);
1555191762Simp	bwi_regwin_disable(sc, &mac->mac_regwin, 0);
1556191762Simp
1557191762Simp	mac->mac_flags &= ~BWI_MAC_F_INITED;
1558191762Simp}
1559191762Simp
1560191762Simpstatic int
1561191762Simpbwi_mac_get_property(struct bwi_mac *mac)
1562191762Simp{
1563191762Simp	struct bwi_softc *sc = mac->mac_sc;
1564191762Simp	enum bwi_bus_space old_bus_space;
1565191762Simp	uint32_t val;
1566191762Simp
1567191762Simp	/*
1568191762Simp	 * Byte swap
1569191762Simp	 */
1570191762Simp	val = CSR_READ_4(sc, BWI_MAC_STATUS);
1571191762Simp	if (val & BWI_MAC_STATUS_BSWAP) {
1572191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1573191762Simp			"need byte swap");
1574191762Simp		mac->mac_flags |= BWI_MAC_F_BSWAP;
1575191762Simp	}
1576191762Simp
1577191762Simp	/*
1578191762Simp	 * DMA address space
1579191762Simp	 */
1580191762Simp	old_bus_space = sc->sc_bus_space;
1581191762Simp
1582191762Simp	val = CSR_READ_4(sc, BWI_STATE_HI);
1583191762Simp	if (__SHIFTOUT(val, BWI_STATE_HI_FLAGS_MASK) &
1584191762Simp	    BWI_STATE_HI_FLAG_64BIT) {
1585191762Simp		/* 64bit address */
1586191762Simp		sc->sc_bus_space = BWI_BUS_SPACE_64BIT;
1587191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1588191762Simp			"64bit bus space");
1589191762Simp	} else {
1590191762Simp		uint32_t txrx_reg = BWI_TXRX_CTRL_BASE + BWI_TX32_CTRL;
1591191762Simp
1592191762Simp		CSR_WRITE_4(sc, txrx_reg, BWI_TXRX32_CTRL_ADDRHI_MASK);
1593191762Simp		if (CSR_READ_4(sc, txrx_reg) & BWI_TXRX32_CTRL_ADDRHI_MASK) {
1594191762Simp			/* 32bit address */
1595191762Simp			sc->sc_bus_space = BWI_BUS_SPACE_32BIT;
1596191762Simp			DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1597191762Simp				"32bit bus space");
1598191762Simp		} else {
1599191762Simp			/* 30bit address */
1600191762Simp			sc->sc_bus_space = BWI_BUS_SPACE_30BIT;
1601191762Simp			DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1602191762Simp				"30bit bus space");
1603191762Simp		}
1604191762Simp	}
1605191762Simp
1606191762Simp	if (old_bus_space != 0 && old_bus_space != sc->sc_bus_space) {
1607191762Simp		device_printf(sc->sc_dev, "MACs bus space mismatch!\n");
1608191762Simp		return ENXIO;
1609191762Simp	}
1610191762Simp	return 0;
1611191762Simp}
1612191762Simp
1613191762Simpvoid
1614191762Simpbwi_mac_updateslot(struct bwi_mac *mac, int shslot)
1615191762Simp{
1616191762Simp	uint16_t slot_time;
1617191762Simp
1618191762Simp	if (mac->mac_phy.phy_mode == IEEE80211_MODE_11B)
1619191762Simp		return;
1620191762Simp
1621191762Simp	if (shslot)
1622191762Simp		slot_time = IEEE80211_DUR_SHSLOT;
1623191762Simp	else
1624191762Simp		slot_time = IEEE80211_DUR_SLOT;
1625191762Simp
1626191762Simp	CSR_WRITE_2(mac->mac_sc, BWI_MAC_SLOTTIME,
1627191762Simp		    slot_time + BWI_MAC_SLOTTIME_ADJUST);
1628191762Simp	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_SLOTTIME, slot_time);
1629191762Simp}
1630191762Simp
1631191762Simpint
1632191762Simpbwi_mac_attach(struct bwi_softc *sc, int id, uint8_t rev)
1633191762Simp{
1634191762Simp	struct bwi_mac *mac;
1635191762Simp	int i;
1636191762Simp
1637191762Simp	KASSERT(sc->sc_nmac <= BWI_MAC_MAX && sc->sc_nmac >= 0,
1638191762Simp	    ("sc_nmac %d", sc->sc_nmac));
1639191762Simp
1640191762Simp	if (sc->sc_nmac == BWI_MAC_MAX) {
1641191762Simp		device_printf(sc->sc_dev, "too many MACs\n");
1642191762Simp		return 0;
1643191762Simp	}
1644191762Simp
1645191762Simp	/*
1646191762Simp	 * More than one MAC is only supported by BCM4309
1647191762Simp	 */
1648191762Simp	if (sc->sc_nmac != 0 &&
1649191762Simp	    sc->sc_pci_did != PCI_PRODUCT_BROADCOM_BCM4309) {
1650191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1651191762Simp			"ignore second MAC");
1652191762Simp		return 0;
1653191762Simp	}
1654191762Simp
1655191762Simp	mac = &sc->sc_mac[sc->sc_nmac];
1656191762Simp
1657191762Simp	/* XXX will this happen? */
1658191762Simp	if (BWI_REGWIN_EXIST(&mac->mac_regwin)) {
1659191762Simp		device_printf(sc->sc_dev, "%dth MAC already attached\n",
1660191762Simp			      sc->sc_nmac);
1661191762Simp		return 0;
1662191762Simp	}
1663191762Simp
1664191762Simp	/*
1665191762Simp	 * Test whether the revision of this MAC is supported
1666191762Simp	 */
1667191762Simp#define N(arr)	(int)(sizeof(arr) / sizeof(arr[0]))
1668191762Simp	for (i = 0; i < N(bwi_sup_macrev); ++i) {
1669191762Simp		if (bwi_sup_macrev[i] == rev)
1670191762Simp			break;
1671191762Simp	}
1672191762Simp	if (i == N(bwi_sup_macrev)) {
1673191762Simp		device_printf(sc->sc_dev, "MAC rev %u is "
1674191762Simp			      "not supported\n", rev);
1675191762Simp		return ENXIO;
1676191762Simp	}
1677191762Simp#undef N
1678191762Simp
1679191762Simp	BWI_CREATE_MAC(mac, sc, id, rev);
1680191762Simp	sc->sc_nmac++;
1681191762Simp
1682191762Simp	if (mac->mac_rev < 5) {
1683191762Simp		mac->mac_flags |= BWI_MAC_F_HAS_TXSTATS;
1684191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n",
1685191762Simp			"has TX stats");
1686191762Simp	} else {
1687191762Simp		mac->mac_flags |= BWI_MAC_F_PHYE_RESET;
1688191762Simp	}
1689191762Simp
1690191762Simp	device_printf(sc->sc_dev, "MAC: rev %u\n", rev);
1691191762Simp	return 0;
1692191762Simp}
1693191762Simp
1694191762Simpstatic __inline void
1695191762Simpbwi_mac_balance_atten(int *bbp_atten0, int *rf_atten0)
1696191762Simp{
1697191762Simp	int bbp_atten, rf_atten, rf_atten_lim = -1;
1698191762Simp
1699191762Simp	bbp_atten = *bbp_atten0;
1700191762Simp	rf_atten = *rf_atten0;
1701191762Simp
1702191762Simp	/*
1703191762Simp	 * RF attenuation affects TX power BWI_RF_ATTEN_FACTOR times
1704191762Simp	 * as much as BBP attenuation, so we try our best to keep RF
1705191762Simp	 * attenuation within range.  BBP attenuation will be clamped
1706191762Simp	 * later if it is out of range during balancing.
1707191762Simp	 *
1708191762Simp	 * BWI_RF_ATTEN_MAX0 is used as RF attenuation upper limit.
1709191762Simp	 */
1710191762Simp
1711191762Simp	/*
1712191762Simp	 * Use BBP attenuation to balance RF attenuation
1713191762Simp	 */
1714191762Simp	if (rf_atten < 0)
1715191762Simp		rf_atten_lim = 0;
1716191762Simp	else if (rf_atten > BWI_RF_ATTEN_MAX0)
1717191762Simp		rf_atten_lim = BWI_RF_ATTEN_MAX0;
1718191762Simp
1719191762Simp	if (rf_atten_lim >= 0) {
1720191762Simp		bbp_atten += (BWI_RF_ATTEN_FACTOR * (rf_atten - rf_atten_lim));
1721191762Simp		rf_atten = rf_atten_lim;
1722191762Simp	}
1723191762Simp
1724191762Simp	/*
1725191762Simp	 * If possible, use RF attenuation to balance BBP attenuation
1726191762Simp	 * NOTE: RF attenuation is still kept within range.
1727191762Simp	 */
1728191762Simp	while (rf_atten < BWI_RF_ATTEN_MAX0 && bbp_atten > BWI_BBP_ATTEN_MAX) {
1729191762Simp		bbp_atten -= BWI_RF_ATTEN_FACTOR;
1730191762Simp		++rf_atten;
1731191762Simp	}
1732191762Simp	while (rf_atten > 0 && bbp_atten < 0) {
1733191762Simp		bbp_atten += BWI_RF_ATTEN_FACTOR;
1734191762Simp		--rf_atten;
1735191762Simp	}
1736191762Simp
1737191762Simp	/* RF attenuation MUST be within range */
1738191762Simp	KASSERT(rf_atten >= 0 && rf_atten <= BWI_RF_ATTEN_MAX0,
1739191762Simp	    ("rf_atten %d", rf_atten));
1740191762Simp
1741191762Simp	/*
1742191762Simp	 * Clamp BBP attenuation
1743191762Simp	 */
1744191762Simp	if (bbp_atten < 0)
1745191762Simp		bbp_atten = 0;
1746191762Simp	else if (bbp_atten > BWI_BBP_ATTEN_MAX)
1747191762Simp		bbp_atten = BWI_BBP_ATTEN_MAX;
1748191762Simp
1749191762Simp	*rf_atten0 = rf_atten;
1750191762Simp	*bbp_atten0 = bbp_atten;
1751191762Simp}
1752191762Simp
1753191762Simpstatic void
1754191762Simpbwi_mac_adjust_tpctl(struct bwi_mac *mac, int rf_atten_adj, int bbp_atten_adj)
1755191762Simp{
1756191762Simp	struct bwi_softc *sc = mac->mac_sc;
1757191762Simp	struct bwi_rf *rf = &mac->mac_rf;
1758191762Simp	struct bwi_tpctl tpctl;
1759191762Simp	int bbp_atten, rf_atten, tp_ctrl1;
1760191762Simp
1761191762Simp	bcopy(&mac->mac_tpctl, &tpctl, sizeof(tpctl));
1762191762Simp
1763191762Simp	/* NOTE: Use signed value to do calulation */
1764191762Simp	bbp_atten = tpctl.bbp_atten;
1765191762Simp	rf_atten = tpctl.rf_atten;
1766191762Simp	tp_ctrl1 = tpctl.tp_ctrl1;
1767191762Simp
1768191762Simp	bbp_atten += bbp_atten_adj;
1769191762Simp	rf_atten += rf_atten_adj;
1770191762Simp
1771191762Simp	bwi_mac_balance_atten(&bbp_atten, &rf_atten);
1772191762Simp
1773191762Simp	if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev == 2) {
1774191762Simp		if (rf_atten <= 1) {
1775191762Simp			if (tp_ctrl1 == 0) {
1776191762Simp				tp_ctrl1 = 3;
1777191762Simp				bbp_atten += 2;
1778191762Simp				rf_atten += 2;
1779191762Simp			} else if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) {
1780191762Simp				bbp_atten +=
1781191762Simp				(BWI_RF_ATTEN_FACTOR * (rf_atten - 2));
1782191762Simp				rf_atten = 2;
1783191762Simp			}
1784191762Simp		} else if (rf_atten > 4 && tp_ctrl1 != 0) {
1785191762Simp			tp_ctrl1 = 0;
1786191762Simp			if (bbp_atten < 3) {
1787191762Simp				bbp_atten += 2;
1788191762Simp				rf_atten -= 3;
1789191762Simp			} else {
1790191762Simp				bbp_atten -= 2;
1791191762Simp				rf_atten -= 2;
1792191762Simp			}
1793191762Simp		}
1794191762Simp		bwi_mac_balance_atten(&bbp_atten, &rf_atten);
1795191762Simp	}
1796191762Simp
1797191762Simp	tpctl.bbp_atten = bbp_atten;
1798191762Simp	tpctl.rf_atten = rf_atten;
1799191762Simp	tpctl.tp_ctrl1 = tp_ctrl1;
1800191762Simp
1801191762Simp	bwi_mac_lock(mac);
1802191762Simp	bwi_mac_set_tpctl_11bg(mac, &tpctl);
1803191762Simp	bwi_mac_unlock(mac);
1804191762Simp}
1805191762Simp
1806191762Simp/*
1807191762Simp * http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower
1808191762Simp */
1809191762Simpvoid
1810191762Simpbwi_mac_calibrate_txpower(struct bwi_mac *mac, enum bwi_txpwrcb_type type)
1811191762Simp{
1812191762Simp	struct bwi_softc *sc = mac->mac_sc;
1813191762Simp	struct bwi_rf *rf = &mac->mac_rf;
1814191762Simp	int8_t tssi[4], tssi_avg, cur_txpwr;
1815191762Simp	int error, i, ofdm_tssi;
1816191762Simp	int txpwr_diff, rf_atten_adj, bbp_atten_adj;
1817191762Simp
1818191762Simp	if (!sc->sc_txpwr_calib)
1819191762Simp		return;
1820191762Simp
1821191762Simp	if (mac->mac_flags & BWI_MAC_F_TPCTL_ERROR) {
1822191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n",
1823191762Simp			"tpctl error happened, can't set txpower");
1824191762Simp		return;
1825191762Simp	}
1826191762Simp
1827191762Simp	if (BWI_IS_BRCM_BU4306(sc)) {
1828191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n",
1829191762Simp			"BU4306, can't set txpower");
1830191762Simp		return;
1831191762Simp	}
1832191762Simp
1833191762Simp	/*
1834191762Simp	 * Save latest TSSI and reset the related memory objects
1835191762Simp	 */
1836191762Simp	ofdm_tssi = 0;
1837191762Simp	error = bwi_rf_get_latest_tssi(mac, tssi, BWI_COMM_MOBJ_TSSI_DS);
1838191762Simp	if (error) {
1839191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n",
1840191762Simp			"no DS tssi");
1841191762Simp
1842191762Simp		if (mac->mac_phy.phy_mode == IEEE80211_MODE_11B) {
1843191762Simp			if (type == BWI_TXPWR_FORCE) {
1844191762Simp				rf_atten_adj = 0;
1845191762Simp				bbp_atten_adj = 1;
1846191762Simp				goto calib;
1847191762Simp			} else {
1848191762Simp				return;
1849191762Simp			}
1850191762Simp		}
1851191762Simp
1852191762Simp		error = bwi_rf_get_latest_tssi(mac, tssi,
1853191762Simp				BWI_COMM_MOBJ_TSSI_OFDM);
1854191762Simp		if (error) {
1855191762Simp			DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n",
1856191762Simp				"no OFDM tssi");
1857191762Simp			if (type == BWI_TXPWR_FORCE) {
1858191762Simp				rf_atten_adj = 0;
1859191762Simp				bbp_atten_adj = 1;
1860191762Simp				goto calib;
1861191762Simp			} else {
1862191762Simp				return;
1863191762Simp			}
1864191762Simp		}
1865191762Simp
1866191762Simp		for (i = 0; i < 4; ++i) {
1867191762Simp			tssi[i] += 0x20;
1868191762Simp			tssi[i] &= 0x3f;
1869191762Simp		}
1870191762Simp		ofdm_tssi = 1;
1871191762Simp	}
1872191762Simp	bwi_rf_clear_tssi(mac);
1873191762Simp
1874191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER,
1875191762Simp		"tssi0 %d, tssi1 %d, tssi2 %d, tssi3 %d\n",
1876191762Simp		tssi[0], tssi[1], tssi[2], tssi[3]);
1877191762Simp
1878191762Simp	/*
1879191762Simp	 * Calculate RF/BBP attenuation adjustment based on
1880191762Simp	 * the difference between desired TX power and sampled
1881191762Simp	 * TX power.
1882191762Simp	 */
1883191762Simp	/* +8 == "each incremented by 1/2" */
1884191762Simp	tssi_avg = (tssi[0] + tssi[1] + tssi[2] + tssi[3] + 8) / 4;
1885191762Simp	if (ofdm_tssi && (HFLAGS_READ(mac) & BWI_HFLAG_PWR_BOOST_DS))
1886191762Simp		tssi_avg -= 13;
1887191762Simp
1888191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "tssi avg %d\n", tssi_avg);
1889191762Simp
1890191762Simp	error = bwi_rf_tssi2dbm(mac, tssi_avg, &cur_txpwr);
1891191762Simp	if (error)
1892191762Simp		return;
1893191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "current txpower %d\n",
1894191762Simp		cur_txpwr);
1895191762Simp
1896191762Simp	txpwr_diff = rf->rf_txpower_max - cur_txpwr; /* XXX ni_txpower */
1897191762Simp
1898191762Simp	rf_atten_adj = -howmany(txpwr_diff, 8);
1899191762Simp	if (type == BWI_TXPWR_INIT) {
1900191762Simp		/*
1901191762Simp		 * Move toward EEPROM max TX power as fast as we can
1902191762Simp		 */
1903191762Simp		bbp_atten_adj = -txpwr_diff;
1904191762Simp	} else {
1905191762Simp		bbp_atten_adj = -(txpwr_diff / 2);
1906191762Simp	}
1907191762Simp	bbp_atten_adj -= (BWI_RF_ATTEN_FACTOR * rf_atten_adj);
1908191762Simp
1909191762Simp	if (rf_atten_adj == 0 && bbp_atten_adj == 0) {
1910191762Simp		DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n",
1911191762Simp			"no need to adjust RF/BBP attenuation");
1912191762Simp		/* TODO: LO */
1913191762Simp		return;
1914191762Simp	}
1915191762Simp
1916191762Simpcalib:
1917191762Simp	DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER,
1918191762Simp		"rf atten adjust %d, bbp atten adjust %d\n",
1919191762Simp		rf_atten_adj, bbp_atten_adj);
1920191762Simp	bwi_mac_adjust_tpctl(mac, rf_atten_adj, bbp_atten_adj);
1921191762Simp	/* TODO: LO */
1922191762Simp}
1923191762Simp
1924191762Simpstatic void
1925191762Simpbwi_mac_lock(struct bwi_mac *mac)
1926191762Simp{
1927191762Simp	struct bwi_softc *sc = mac->mac_sc;
1928191762Simp	struct ifnet *ifp = sc->sc_ifp;
1929191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1930191762Simp
1931191762Simp	KASSERT((mac->mac_flags & BWI_MAC_F_LOCKED) == 0,
1932191762Simp	    ("mac_flags 0x%x", mac->mac_flags));
1933191762Simp
1934191762Simp	if (mac->mac_rev < 3)
1935191762Simp		bwi_mac_stop(mac);
1936191762Simp	else if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1937191762Simp		bwi_mac_config_ps(mac);
1938191762Simp
1939191762Simp	CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK);
1940191762Simp
1941191762Simp	/* Flush pending bus write */
1942191762Simp	CSR_READ_4(sc, BWI_MAC_STATUS);
1943191762Simp	DELAY(10);
1944191762Simp
1945191762Simp	mac->mac_flags |= BWI_MAC_F_LOCKED;
1946191762Simp}
1947191762Simp
1948191762Simpstatic void
1949191762Simpbwi_mac_unlock(struct bwi_mac *mac)
1950191762Simp{
1951191762Simp	struct bwi_softc *sc = mac->mac_sc;
1952191762Simp	struct ifnet *ifp = sc->sc_ifp;
1953191762Simp	struct ieee80211com *ic = ifp->if_l2com;
1954191762Simp
1955191762Simp	KASSERT(mac->mac_flags & BWI_MAC_F_LOCKED,
1956191762Simp	    ("mac_flags 0x%x", mac->mac_flags));
1957191762Simp
1958191762Simp	CSR_READ_2(sc, BWI_PHYINFO); /* dummy read */
1959191762Simp
1960191762Simp	CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK);
1961191762Simp
1962191762Simp	if (mac->mac_rev < 3)
1963191762Simp		bwi_mac_start(mac);
1964191762Simp	else if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1965191762Simp		bwi_mac_config_ps(mac);
1966191762Simp
1967191762Simp	mac->mac_flags &= ~BWI_MAC_F_LOCKED;
1968191762Simp}
1969191762Simp
1970191762Simpvoid
1971191762Simpbwi_mac_set_promisc(struct bwi_mac *mac, int promisc)
1972191762Simp{
1973191762Simp	struct bwi_softc *sc = mac->mac_sc;
1974191762Simp
1975191762Simp	if (mac->mac_rev < 5) /* Promisc is always on */
1976191762Simp		return;
1977191762Simp
1978191762Simp	if (promisc)
1979191762Simp		CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PROMISC);
1980191762Simp	else
1981191762Simp		CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PROMISC);
1982191762Simp}
1983