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