if_bwn.c revision 299795
1203945Sweongyo/*-
2203945Sweongyo * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3203945Sweongyo * All rights reserved.
4203945Sweongyo *
5203945Sweongyo * Redistribution and use in source and binary forms, with or without
6203945Sweongyo * modification, are permitted provided that the following conditions
7203945Sweongyo * are met:
8203945Sweongyo * 1. Redistributions of source code must retain the above copyright
9203945Sweongyo *    notice, this list of conditions and the following disclaimer,
10203945Sweongyo *    without modification.
11203945Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12203945Sweongyo *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13203945Sweongyo *    redistribution must be conditioned upon including a substantially
14203945Sweongyo *    similar Disclaimer requirement for further binary redistribution.
15203945Sweongyo *
16203945Sweongyo * NO WARRANTY
17203945Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18203945Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19203945Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20203945Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21203945Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22203945Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23203945Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24203945Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25203945Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26203945Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27203945Sweongyo * THE POSSIBILITY OF SUCH DAMAGES.
28203945Sweongyo */
29203945Sweongyo
30203945Sweongyo#include <sys/cdefs.h>
31203945Sweongyo__FBSDID("$FreeBSD: head/sys/dev/bwn/if_bwn.c 299795 2016-05-14 23:43:43Z adrian $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39295126Sglebius#include <sys/kernel.h>
40295126Sglebius#include <sys/malloc.h>
41203945Sweongyo#include <sys/module.h>
42203945Sweongyo#include <sys/endian.h>
43203945Sweongyo#include <sys/errno.h>
44203945Sweongyo#include <sys/firmware.h>
45203945Sweongyo#include <sys/lock.h>
46203945Sweongyo#include <sys/mutex.h>
47203945Sweongyo#include <machine/bus.h>
48203945Sweongyo#include <machine/resource.h>
49203945Sweongyo#include <sys/bus.h>
50203945Sweongyo#include <sys/rman.h>
51203945Sweongyo#include <sys/socket.h>
52203945Sweongyo#include <sys/sockio.h>
53203945Sweongyo
54203945Sweongyo#include <net/ethernet.h>
55203945Sweongyo#include <net/if.h>
56257176Sglebius#include <net/if_var.h>
57203945Sweongyo#include <net/if_arp.h>
58203945Sweongyo#include <net/if_dl.h>
59203945Sweongyo#include <net/if_llc.h>
60203945Sweongyo#include <net/if_media.h>
61203945Sweongyo#include <net/if_types.h>
62203945Sweongyo
63203945Sweongyo#include <dev/pci/pcivar.h>
64203945Sweongyo#include <dev/pci/pcireg.h>
65203945Sweongyo#include <dev/siba/siba_ids.h>
66203945Sweongyo#include <dev/siba/sibareg.h>
67203945Sweongyo#include <dev/siba/sibavar.h>
68203945Sweongyo
69203945Sweongyo#include <net80211/ieee80211_var.h>
70203945Sweongyo#include <net80211/ieee80211_radiotap.h>
71203945Sweongyo#include <net80211/ieee80211_regdomain.h>
72203945Sweongyo#include <net80211/ieee80211_phy.h>
73206358Srpaulo#include <net80211/ieee80211_ratectl.h>
74203945Sweongyo
75203945Sweongyo#include <dev/bwn/if_bwnreg.h>
76203945Sweongyo#include <dev/bwn/if_bwnvar.h>
77203945Sweongyo
78298948Sadrian#include <dev/bwn/if_bwn_debug.h>
79298944Sadrian#include <dev/bwn/if_bwn_misc.h>
80299776Sadrian#include <dev/bwn/if_bwn_util.h>
81299776Sadrian#include <dev/bwn/if_bwn_phy_common.h>
82298948Sadrian#include <dev/bwn/if_bwn_phy_g.h>
83298944Sadrian#include <dev/bwn/if_bwn_phy_lp.h>
84298944Sadrian
85227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
86227309Sed    "Broadcom driver parameters");
87203945Sweongyo
88203945Sweongyo/*
89203945Sweongyo * Tunable & sysctl variables.
90203945Sweongyo */
91203945Sweongyo
92203945Sweongyo#ifdef BWN_DEBUG
93203945Sweongyostatic	int bwn_debug = 0;
94267992ShselaskySYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0,
95203945Sweongyo    "Broadcom debugging printfs");
96203945Sweongyo#endif
97203945Sweongyo
98203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
99203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
100203945Sweongyo    "uses Bad Frames Preemption");
101203945Sweongyostatic int	bwn_bluetooth = 1;
102203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
103203945Sweongyo    "turns on Bluetooth Coexistence");
104203945Sweongyostatic int	bwn_hwpctl = 0;
105203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
106203945Sweongyo    "uses H/W power control");
107203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
108203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
109203945Sweongyostatic int	bwn_usedma = 1;
110203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
111203945Sweongyo    "uses DMA");
112203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
113203945Sweongyostatic int	bwn_wme = 1;
114203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
115203945Sweongyo    "uses WME support");
116203945Sweongyo
117287197Sglebiusstatic void	bwn_attach_pre(struct bwn_softc *);
118203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
119204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
120287197Sglebiusstatic int	bwn_init(struct bwn_softc *);
121287197Sglebiusstatic void	bwn_parent(struct ieee80211com *);
122287197Sglebiusstatic void	bwn_start(struct bwn_softc *);
123287197Sglebiusstatic int	bwn_transmit(struct ieee80211com *, struct mbuf *);
124203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
125203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
126203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
127203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
128203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
129203945Sweongyo		    uint16_t);
130203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
131203945Sweongyo		    const struct bwn_channelinfo *, int);
132203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
133203945Sweongyo		    const struct ieee80211_bpf_params *);
134283540Sglebiusstatic void	bwn_updateslot(struct ieee80211com *);
135283540Sglebiusstatic void	bwn_update_promisc(struct ieee80211com *);
136203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
137203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
138203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
139203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
140203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
141203945Sweongyo		    const struct wmeParams *, uint16_t);
142203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
143203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
144203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
145203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
146228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
147228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
148203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
149203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
150287197Sglebiusstatic void	bwn_stop(struct bwn_softc *);
151203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
152203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
153203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
154203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
155203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
156203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
157203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
158203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
159203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
160203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
161203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
162203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
163203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
164203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
165203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
166203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
167203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
168203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
169203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
170203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
171203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
172203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
173203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
174203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
175203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
176203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
177203945Sweongyo		    int);
178203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
179203945Sweongyo		    struct bwn_pio_rxqueue *, int);
180203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
181203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
182203945Sweongyo		    uint16_t);
183203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
184203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
185203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
186203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
187203945Sweongyo		    const struct bwn_txstatus *);
188203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
189203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
190203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
191203945Sweongyo		    uint16_t);
192203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
193203945Sweongyo		    uint32_t);
194203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
195203945Sweongyo		    struct mbuf *);
196203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
197203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
198203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
199203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
200203945Sweongyo		    uint16_t, uint32_t);
201203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
202203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
203203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
204203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
205203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
206203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
207203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
208203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
209203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
210203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
211203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
212203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
213203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
214203945Sweongyo		    int, struct bwn_dmadesc_generic **,
215203945Sweongyo		    struct bwn_dmadesc_meta **);
216203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
217203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
218203945Sweongyo		    int, int);
219203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
220203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
221203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
222203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
223203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
224203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
225203945Sweongyo		    int, struct bwn_dmadesc_generic **,
226203945Sweongyo		    struct bwn_dmadesc_meta **);
227203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
228203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
229203945Sweongyo		    int, int);
230203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
231203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
232203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
233203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
234203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
235203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
236203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
237203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
238203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
239203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
240203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
241203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
242203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
243203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
244203945Sweongyo		    struct bwn_dmadesc_meta *);
245203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
246203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
247203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
248203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
249203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
250203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
251203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
252203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
253203945Sweongyo		    int);
254203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
255203945Sweongyo		    bus_size_t, int);
256203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
257203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
258203945Sweongyo		    const struct bwn_txstatus *);
259203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
260203945Sweongyo		    struct mbuf *);
261203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
262203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
263203945Sweongyo		    uint8_t);
264203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
265203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
266203945Sweongyo		    int, int, int);
267203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
268203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
269203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
270203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
271203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
272203945Sweongyo		    const char *, struct bwn_fwfile *);
273203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
274203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
275203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
276203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
277203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
278203945Sweongyostatic uint16_t	bwn_ant2phy(int);
279203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
280203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
281203945Sweongyo		    const uint8_t *);
282203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
283203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
284203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
285203945Sweongyo		    const uint8_t *);
286203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
287203945Sweongyo		    const uint8_t *);
288203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
289203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
290203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
291203945Sweongyo		    struct ieee80211_channel *);
292203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
293203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
294203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
295203945Sweongyostatic int	bwn_intr(void *);
296203945Sweongyostatic void	bwn_intrtask(void *, int);
297203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
298203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
299203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
300203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
301203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
302203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
303203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
304203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
305203945Sweongyostatic void	bwn_hwreset(void *, int);
306203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
307203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
308203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
309203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
310203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
311203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
312203945Sweongyo		    const struct bwn_txstatus *);
313203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
314203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
315203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
316203945Sweongyo		    struct mbuf *);
317203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
318203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
319203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
320203945Sweongyo		    uint16_t);
321203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
322203945Sweongyo		    const uint8_t);
323203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
324203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
325203945Sweongyostatic void	bwn_txpwr(void *, int);
326203945Sweongyostatic void	bwn_tasks(void *);
327203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
328203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
329203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
330203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
331203945Sweongyo		    uint8_t);
332203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
333203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
334203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
335203945Sweongyo		    int, int);
336203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
337203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
338203945Sweongyostatic void	bwn_watchdog(void *);
339203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
340203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
341203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
342203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
343203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
344203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
345203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
346203945Sweongyostatic void	bwn_led_blink_next(void *);
347203945Sweongyostatic void	bwn_led_blink_end(void *);
348203945Sweongyostatic void	bwn_rfswitch(void *);
349203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
350203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
351204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
352203945Sweongyo
353203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
354203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
355203945Sweongyo	{ -1,			0,		0 }
356203945Sweongyo};
357203945Sweongyo
358203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
359203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
360203945Sweongyo	{ -1,			0,		0 }
361203945Sweongyo};
362203945Sweongyo
363203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
364203945Sweongyo	.channels = {
365203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
366203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
367203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
368203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
369203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
370203945Sweongyo	.nchannels = 14
371203945Sweongyo};
372203945Sweongyo
373203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
374203945Sweongyo	.channels = {
375203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
376203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
377203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
378203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
379203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
380203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
381203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
382203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
383203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
384203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
385203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
386203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
387203945Sweongyo		{ 6080, 216, 30 } },
388203945Sweongyo	.nchannels = 37
389203945Sweongyo};
390203945Sweongyo
391203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
392203945Sweongyo	.channels = {
393203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
394203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
395203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
396203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
397203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
398203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
399203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
400203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
401203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
402203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
403203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
404203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
405203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
406203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
407203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
408203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
409203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
410203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
411203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
412203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
413203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
414203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
415203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
416203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
417203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
418203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
419203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
420203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
421203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
422203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
423203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
424203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
425203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
426203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
427203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
428203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
429203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
430203945Sweongyo	.nchannels = 110
431203945Sweongyo};
432203945Sweongyo
433203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
434203945Sweongyo{							\
435203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
436203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
437203945Sweongyo}
438203945Sweongyo
439203945Sweongyostatic const struct {
440203945Sweongyo	uint16_t	vid;
441203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
442203945Sweongyo} bwn_vendor_led_act[] = {
443203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
444203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
445203945Sweongyo};
446203945Sweongyo
447203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
448203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
449203945Sweongyo
450203945Sweongyo#undef VENDOR_LED_ACT
451203945Sweongyo
452203945Sweongyostatic const struct {
453203945Sweongyo	int		on_dur;
454203945Sweongyo	int		off_dur;
455203945Sweongyo} bwn_led_duration[109] = {
456203945Sweongyo	[0]	= { 400, 100 },
457203945Sweongyo	[2]	= { 150, 75 },
458203945Sweongyo	[4]	= { 90, 45 },
459203945Sweongyo	[11]	= { 66, 34 },
460203945Sweongyo	[12]	= { 53, 26 },
461203945Sweongyo	[18]	= { 42, 21 },
462203945Sweongyo	[22]	= { 35, 17 },
463203945Sweongyo	[24]	= { 32, 16 },
464203945Sweongyo	[36]	= { 21, 10 },
465203945Sweongyo	[48]	= { 16, 8 },
466203945Sweongyo	[72]	= { 11, 5 },
467203945Sweongyo	[96]	= { 9, 4 },
468203945Sweongyo	[108]	= { 7, 3 }
469203945Sweongyo};
470203945Sweongyo
471203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
472203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
473203945Sweongyo	[1] = BWN_WME_BACKGROUND,
474203945Sweongyo	[2] = BWN_WME_VOICE,
475203945Sweongyo	[3] = BWN_WME_VIDEO,
476203945Sweongyo};
477203945Sweongyo
478203945Sweongyostatic const struct siba_devid bwn_devs[] = {
479203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
480203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
481203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
482203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
483203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
484203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
485203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
486203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
487203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
488203945Sweongyo};
489203945Sweongyo
490203945Sweongyostatic int
491203945Sweongyobwn_probe(device_t dev)
492203945Sweongyo{
493203945Sweongyo	int i;
494203945Sweongyo
495298307Spfg	for (i = 0; i < nitems(bwn_devs); i++) {
496204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
497204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
498204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
499203945Sweongyo			return (BUS_PROBE_DEFAULT);
500203945Sweongyo	}
501203945Sweongyo
502203945Sweongyo	return (ENXIO);
503203945Sweongyo}
504203945Sweongyo
505203945Sweongyostatic int
506203945Sweongyobwn_attach(device_t dev)
507203945Sweongyo{
508203945Sweongyo	struct bwn_mac *mac;
509203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
510203945Sweongyo	int error, i, msic, reg;
511203945Sweongyo
512203945Sweongyo	sc->sc_dev = dev;
513203945Sweongyo#ifdef BWN_DEBUG
514203945Sweongyo	sc->sc_debug = bwn_debug;
515203945Sweongyo#endif
516203945Sweongyo
517203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
518287197Sglebius		bwn_attach_pre(sc);
519204922Sweongyo		bwn_sprom_bugfixes(dev);
520203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
521203945Sweongyo	}
522203945Sweongyo
523203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
524204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
525204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
526204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
527203945Sweongyo			device_printf(sc->sc_dev,
528203945Sweongyo			    "skip 802.11 cores\n");
529203945Sweongyo			return (ENODEV);
530203945Sweongyo		}
531203945Sweongyo	}
532203945Sweongyo
533287197Sglebius	mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO);
534203945Sweongyo	mac->mac_sc = sc;
535203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
536203945Sweongyo	if (bwn_bfp != 0)
537203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
538203945Sweongyo
539203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
540203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
541203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
542203945Sweongyo
543203945Sweongyo	error = bwn_attach_core(mac);
544203945Sweongyo	if (error)
545203945Sweongyo		goto fail0;
546203945Sweongyo	bwn_led_attach(mac);
547203945Sweongyo
548203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
549203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
550204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
551203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
552203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
553203945Sweongyo	    mac->mac_phy.rf_rev);
554203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
555203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
556203945Sweongyo		    mac->mac_method.dma.dmatype);
557203945Sweongyo	else
558203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
559203945Sweongyo
560203945Sweongyo	/*
561203945Sweongyo	 * setup PCI resources and interrupt.
562203945Sweongyo	 */
563219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
564203945Sweongyo		msic = pci_msi_count(dev);
565203945Sweongyo		if (bootverbose)
566203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
567203945Sweongyo	} else
568203945Sweongyo		msic = 0;
569203945Sweongyo
570203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
571203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
572203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
573203945Sweongyo			device_printf(sc->sc_dev,
574203945Sweongyo			    "Using %d MSI messages\n", msic);
575203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
576203945Sweongyo			mac->mac_msi = 1;
577203945Sweongyo		}
578203945Sweongyo	}
579203945Sweongyo
580203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
581203945Sweongyo	    mac->mac_res_irq);
582203945Sweongyo	if (error) {
583203945Sweongyo		device_printf(sc->sc_dev,
584203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
585203945Sweongyo		goto fail1;
586203945Sweongyo	}
587203945Sweongyo
588203945Sweongyo	if (mac->mac_msi == 0)
589203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
590203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
591203945Sweongyo		    &mac->mac_intrhand[0]);
592203945Sweongyo	else {
593203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
594203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
595203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
596203945Sweongyo			    &mac->mac_intrhand[i]);
597203945Sweongyo			if (error != 0) {
598203945Sweongyo				device_printf(sc->sc_dev,
599203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
600203945Sweongyo				break;
601203945Sweongyo			}
602203945Sweongyo		}
603203945Sweongyo	}
604203945Sweongyo
605203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
606203945Sweongyo
607203945Sweongyo	/*
608203945Sweongyo	 * calls attach-post routine
609203945Sweongyo	 */
610203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
611203945Sweongyo		bwn_attach_post(sc);
612203945Sweongyo
613203945Sweongyo	return (0);
614203945Sweongyofail1:
615203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
616203945Sweongyo		pci_release_msi(dev);
617203945Sweongyofail0:
618203945Sweongyo	free(mac, M_DEVBUF);
619203945Sweongyo	return (error);
620203945Sweongyo}
621203945Sweongyo
622203945Sweongyostatic int
623203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
624203945Sweongyo{
625203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
626203945Sweongyo
627203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
628203945Sweongyo		return (FALSE);
629203945Sweongyo
630203945Sweongyo	return (TRUE);
631203945Sweongyo}
632203945Sweongyo
633203945Sweongyostatic int
634203945Sweongyobwn_attach_post(struct bwn_softc *sc)
635203945Sweongyo{
636287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
637203945Sweongyo
638283537Sglebius	ic->ic_softc = sc;
639283527Sglebius	ic->ic_name = device_get_nameunit(sc->sc_dev);
640203945Sweongyo	/* XXX not right but it's not used anywhere important */
641203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
642203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
643203945Sweongyo	ic->ic_caps =
644203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
645203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
646204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
647203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
648203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
649203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
650203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
651299773Sadrian#if 0
652203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
653299773Sadrian#endif
654203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
655203945Sweongyo		;
656203945Sweongyo
657205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
658205141Sweongyo
659287197Sglebius	IEEE80211_ADDR_COPY(ic->ic_macaddr,
660204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
661204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
662204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
663203945Sweongyo
664287197Sglebius	/* call MI attach routine. */
665287197Sglebius	ieee80211_ifattach(ic);
666287197Sglebius
667203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
668203945Sweongyo
669203945Sweongyo	/* override default methods */
670203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
671203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
672203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
673203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
674203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
675203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
676203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
677203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
678203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
679287197Sglebius	ic->ic_transmit = bwn_transmit;
680287197Sglebius	ic->ic_parent = bwn_parent;
681203945Sweongyo
682203945Sweongyo	ieee80211_radiotap_attach(ic,
683203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
684203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
685203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
686203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
687203945Sweongyo
688204257Sweongyo	bwn_sysctl_node(sc);
689203945Sweongyo
690203945Sweongyo	if (bootverbose)
691203945Sweongyo		ieee80211_announce(ic);
692203945Sweongyo	return (0);
693203945Sweongyo}
694203945Sweongyo
695203945Sweongyostatic void
696203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
697203945Sweongyo{
698203945Sweongyo
699203945Sweongyo	if (mac->mac_phy.detach != NULL)
700203945Sweongyo		mac->mac_phy.detach(mac);
701203945Sweongyo}
702203945Sweongyo
703203945Sweongyostatic int
704203945Sweongyobwn_detach(device_t dev)
705203945Sweongyo{
706203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
707203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
708287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
709203945Sweongyo	int i;
710203945Sweongyo
711203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
712203945Sweongyo
713203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
714287197Sglebius		BWN_LOCK(sc);
715287197Sglebius		bwn_stop(sc);
716287197Sglebius		BWN_UNLOCK(sc);
717203945Sweongyo		bwn_dma_free(mac);
718203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
719203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
720203945Sweongyo		callout_drain(&sc->sc_task_ch);
721203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
722203945Sweongyo		bwn_phy_detach(mac);
723287197Sglebius		ieee80211_draintask(ic, &mac->mac_hwreset);
724287197Sglebius		ieee80211_draintask(ic, &mac->mac_txpower);
725287197Sglebius		ieee80211_ifdetach(ic);
726203945Sweongyo	}
727203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
728203945Sweongyo	taskqueue_free(sc->sc_tq);
729203945Sweongyo
730203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
731203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
732203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
733203945Sweongyo			    mac->mac_intrhand[i]);
734203945Sweongyo			mac->mac_intrhand[i] = NULL;
735203945Sweongyo		}
736203945Sweongyo	}
737203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
738203945Sweongyo	if (mac->mac_msi != 0)
739203945Sweongyo		pci_release_msi(dev);
740287197Sglebius	mbufq_drain(&sc->sc_snd);
741203945Sweongyo	BWN_LOCK_DESTROY(sc);
742203945Sweongyo	return (0);
743203945Sweongyo}
744203945Sweongyo
745287197Sglebiusstatic void
746203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
747203945Sweongyo{
748203945Sweongyo
749203945Sweongyo	BWN_LOCK_INIT(sc);
750203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
751203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
752203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
753203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
754287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
755203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
756203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
757203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
758203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
759203945Sweongyo}
760203945Sweongyo
761203945Sweongyostatic void
762204922Sweongyobwn_sprom_bugfixes(device_t dev)
763203945Sweongyo{
764203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
765204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
766204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
767204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
768204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
769203945Sweongyo
770204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
771204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
772204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
773204922Sweongyo		siba_sprom_set_bf_lo(dev,
774204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
775204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
776204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
777204922Sweongyo		siba_sprom_set_bf_lo(dev,
778204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
779204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
780203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
781203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
782203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
783203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
784203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
785203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
786203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
787204922Sweongyo			siba_sprom_set_bf_lo(dev,
788204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
789203945Sweongyo	}
790203945Sweongyo#undef	BWN_ISDEV
791203945Sweongyo}
792203945Sweongyo
793287197Sglebiusstatic void
794287197Sglebiusbwn_parent(struct ieee80211com *ic)
795203945Sweongyo{
796287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
797287197Sglebius	int startall = 0;
798203945Sweongyo
799287197Sglebius	BWN_LOCK(sc);
800287197Sglebius	if (ic->ic_nrunning > 0) {
801287197Sglebius		if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
802287197Sglebius			bwn_init(sc);
803287197Sglebius			startall = 1;
804287197Sglebius		} else
805286437Sadrian			bwn_update_promisc(ic);
806287197Sglebius	} else if (sc->sc_flags & BWN_FLAG_RUNNING)
807287197Sglebius		bwn_stop(sc);
808287197Sglebius	BWN_UNLOCK(sc);
809287197Sglebius
810287197Sglebius	if (startall)
811287197Sglebius		ieee80211_start_all(ic);
812203945Sweongyo}
813203945Sweongyo
814287197Sglebiusstatic int
815287197Sglebiusbwn_transmit(struct ieee80211com *ic, struct mbuf *m)
816203945Sweongyo{
817287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
818287197Sglebius	int error;
819203945Sweongyo
820203945Sweongyo	BWN_LOCK(sc);
821287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
822287197Sglebius		BWN_UNLOCK(sc);
823287197Sglebius		return (ENXIO);
824287197Sglebius	}
825287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
826287197Sglebius	if (error) {
827287197Sglebius		BWN_UNLOCK(sc);
828287197Sglebius		return (error);
829287197Sglebius	}
830287197Sglebius	bwn_start(sc);
831203945Sweongyo	BWN_UNLOCK(sc);
832287197Sglebius	return (0);
833203945Sweongyo}
834203945Sweongyo
835203945Sweongyostatic void
836287197Sglebiusbwn_start(struct bwn_softc *sc)
837203945Sweongyo{
838203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
839203945Sweongyo	struct ieee80211_frame *wh;
840203945Sweongyo	struct ieee80211_node *ni;
841203945Sweongyo	struct ieee80211_key *k;
842203945Sweongyo	struct mbuf *m;
843203945Sweongyo
844203945Sweongyo	BWN_ASSERT_LOCKED(sc);
845203945Sweongyo
846287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || mac == NULL ||
847203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
848203945Sweongyo		return;
849203945Sweongyo
850287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
851203945Sweongyo		if (bwn_tx_isfull(sc, m))
852203945Sweongyo			break;
853203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
854203945Sweongyo		if (ni == NULL) {
855203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
856203945Sweongyo			m_freem(m);
857287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
858203945Sweongyo			continue;
859203945Sweongyo		}
860203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
861260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
862203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
863203945Sweongyo			if (k == NULL) {
864287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
865287197Sglebius				    IFCOUNTER_OERRORS, 1);
866203945Sweongyo				ieee80211_free_node(ni);
867203945Sweongyo				m_freem(m);
868203945Sweongyo				continue;
869203945Sweongyo			}
870203945Sweongyo		}
871203945Sweongyo		wh = NULL;	/* Catch any invalid use */
872203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
873287197Sglebius			if (ni != NULL) {
874287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
875287197Sglebius				    IFCOUNTER_OERRORS, 1);
876203945Sweongyo				ieee80211_free_node(ni);
877287197Sglebius			}
878203945Sweongyo			continue;
879203945Sweongyo		}
880203945Sweongyo		sc->sc_watchdog_timer = 5;
881203945Sweongyo	}
882203945Sweongyo}
883203945Sweongyo
884203945Sweongyostatic int
885203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
886203945Sweongyo{
887203945Sweongyo	struct bwn_dma_ring *dr;
888203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
889203945Sweongyo	struct bwn_pio_txqueue *tq;
890203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
891203945Sweongyo
892203945Sweongyo	BWN_ASSERT_LOCKED(sc);
893203945Sweongyo
894203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
895203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
896203945Sweongyo		if (dr->dr_stop == 1 ||
897203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
898203945Sweongyo			dr->dr_stop = 1;
899203945Sweongyo			goto full;
900203945Sweongyo		}
901203945Sweongyo	} else {
902203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
903203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
904287197Sglebius		    pktlen > (tq->tq_size - tq->tq_used))
905203945Sweongyo			goto full;
906203945Sweongyo	}
907203945Sweongyo	return (0);
908203945Sweongyofull:
909287197Sglebius	mbufq_prepend(&sc->sc_snd, m);
910203945Sweongyo	return (1);
911203945Sweongyo}
912203945Sweongyo
913203945Sweongyostatic int
914203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
915203945Sweongyo{
916203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
917203945Sweongyo	int error;
918203945Sweongyo
919203945Sweongyo	BWN_ASSERT_LOCKED(sc);
920203945Sweongyo
921203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
922203945Sweongyo		m_freem(m);
923203945Sweongyo		return (ENXIO);
924203945Sweongyo	}
925203945Sweongyo
926203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
927203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
928203945Sweongyo	if (error) {
929203945Sweongyo		m_freem(m);
930203945Sweongyo		return (error);
931203945Sweongyo	}
932203945Sweongyo	return (0);
933203945Sweongyo}
934203945Sweongyo
935203945Sweongyostatic int
936203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
937203945Sweongyo{
938203945Sweongyo	struct bwn_pio_txpkt *tp;
939203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
940203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
941203945Sweongyo	struct bwn_txhdr txhdr;
942203945Sweongyo	struct mbuf *m_new;
943203945Sweongyo	uint32_t ctl32;
944203945Sweongyo	int error;
945203945Sweongyo	uint16_t ctl16;
946203945Sweongyo
947203945Sweongyo	BWN_ASSERT_LOCKED(sc);
948203945Sweongyo
949203945Sweongyo	/* XXX TODO send packets after DTIM */
950203945Sweongyo
951203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
952203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
953203945Sweongyo	tp->tp_ni = ni;
954203945Sweongyo	tp->tp_m = m;
955203945Sweongyo
956203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
957203945Sweongyo	if (error) {
958203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
959203945Sweongyo		return (error);
960203945Sweongyo	}
961203945Sweongyo
962203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
963203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
964203945Sweongyo	tq->tq_free--;
965203945Sweongyo
966204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
967203945Sweongyo		/*
968203945Sweongyo		 * XXX please removes m_defrag(9)
969203945Sweongyo		 */
970243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
971203945Sweongyo		if (m_new == NULL) {
972203945Sweongyo			device_printf(sc->sc_dev,
973203945Sweongyo			    "%s: can't defrag TX buffer\n",
974203945Sweongyo			    __func__);
975203945Sweongyo			return (ENOBUFS);
976203945Sweongyo		}
977203945Sweongyo		if (m_new->m_next != NULL)
978203945Sweongyo			device_printf(sc->sc_dev,
979203945Sweongyo			    "TODO: fragmented packets for PIO\n");
980203945Sweongyo		tp->tp_m = m_new;
981203945Sweongyo
982203945Sweongyo		/* send HEADER */
983203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
984203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
985203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
986203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
987203945Sweongyo		/* send BODY */
988203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
989203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
990203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
991203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
992203945Sweongyo	} else {
993203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
994203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
995203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
996203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
997203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
998203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
999203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1000203945Sweongyo	}
1001203945Sweongyo
1002203945Sweongyo	return (0);
1003203945Sweongyo}
1004203945Sweongyo
1005203945Sweongyostatic struct bwn_pio_txqueue *
1006203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1007203945Sweongyo{
1008203945Sweongyo
1009203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1010203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1011203945Sweongyo
1012203945Sweongyo	switch (prio) {
1013203945Sweongyo	case 0:
1014203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1015203945Sweongyo	case 1:
1016203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1017203945Sweongyo	case 2:
1018203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1019203945Sweongyo	case 3:
1020203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1021203945Sweongyo	}
1022203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1023204242Simp	return (NULL);
1024203945Sweongyo}
1025203945Sweongyo
1026203945Sweongyostatic int
1027203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1028203945Sweongyo{
1029203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1030203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1031203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1032203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1033203945Sweongyo	struct bwn_dmadesc_generic *desc;
1034203945Sweongyo	struct bwn_dmadesc_meta *mt;
1035203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1036203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1037203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1038203945Sweongyo
1039203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1040203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1041203945Sweongyo
1042203945Sweongyo	/* XXX send after DTIM */
1043203945Sweongyo
1044203945Sweongyo	slot = bwn_dma_getslot(dr);
1045203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1046203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1047203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1048203945Sweongyo
1049203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1050203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1051203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1052203945Sweongyo	if (error)
1053203945Sweongyo		goto fail;
1054203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1055203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1056203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1057203945Sweongyo	if (error) {
1058287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1059203945Sweongyo		    __func__, error);
1060203945Sweongyo		goto fail;
1061203945Sweongyo	}
1062203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1063203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1064203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1065203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1066203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1067203945Sweongyo
1068203945Sweongyo	slot = bwn_dma_getslot(dr);
1069203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1070203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1071203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1072203945Sweongyo	mt->mt_m = m;
1073203945Sweongyo	mt->mt_ni = ni;
1074203945Sweongyo
1075203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1076203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1077203945Sweongyo	if (error && error != EFBIG) {
1078287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1079203945Sweongyo		    __func__, error);
1080203945Sweongyo		goto fail;
1081203945Sweongyo	}
1082203945Sweongyo	if (error) {    /* error == EFBIG */
1083203945Sweongyo		struct mbuf *m_new;
1084203945Sweongyo
1085243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1086203945Sweongyo		if (m_new == NULL) {
1087287197Sglebius			device_printf(sc->sc_dev,
1088287197Sglebius			    "%s: can't defrag TX buffer\n",
1089203945Sweongyo			    __func__);
1090203945Sweongyo			error = ENOBUFS;
1091203945Sweongyo			goto fail;
1092203945Sweongyo		} else {
1093203945Sweongyo			m = m_new;
1094203945Sweongyo		}
1095203945Sweongyo
1096203945Sweongyo		mt->mt_m = m;
1097203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1098203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1099203945Sweongyo		if (error) {
1100287197Sglebius			device_printf(sc->sc_dev,
1101287197Sglebius			    "%s: can't load TX buffer (2) %d\n",
1102203945Sweongyo			    __func__, error);
1103203945Sweongyo			goto fail;
1104203945Sweongyo		}
1105203945Sweongyo	}
1106203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1107203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1108203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1109203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1110203945Sweongyo
1111203945Sweongyo	/* XXX send after DTIM */
1112203945Sweongyo
1113203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1114203945Sweongyo	return (0);
1115203945Sweongyofail:
1116203945Sweongyo	dr->dr_curslot = backup[0];
1117203945Sweongyo	dr->dr_usedslot = backup[1];
1118203945Sweongyo	return (error);
1119203945Sweongyo#undef BWN_GET_TXHDRCACHE
1120203945Sweongyo}
1121203945Sweongyo
1122203945Sweongyostatic void
1123203945Sweongyobwn_watchdog(void *arg)
1124203945Sweongyo{
1125203945Sweongyo	struct bwn_softc *sc = arg;
1126203945Sweongyo
1127203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1128287197Sglebius		device_printf(sc->sc_dev, "device timeout\n");
1129287197Sglebius		counter_u64_add(sc->sc_ic.ic_oerrors, 1);
1130203945Sweongyo	}
1131203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1132203945Sweongyo}
1133203945Sweongyo
1134203945Sweongyostatic int
1135203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1136203945Sweongyo{
1137203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1138203945Sweongyo	int error, have_bg = 0, have_a = 0;
1139203945Sweongyo	uint32_t high;
1140203945Sweongyo
1141204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1142204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1143203945Sweongyo
1144204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1145203945Sweongyo
1146204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1147299776Sadrian	bwn_reset_core(mac, !!(high & BWN_TGSHIGH_HAVE_2GHZ));
1148203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1149203945Sweongyo	if (error)
1150203945Sweongyo		goto fail;
1151203945Sweongyo
1152299792Sadrian	/* XXX need bhnd */
1153299792Sadrian	if (bwn_is_bus_siba(mac)) {
1154299792Sadrian		have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1155299792Sadrian		have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1156299792Sadrian	} else {
1157299792Sadrian		device_printf(sc->sc_dev, "%s: not siba; bailing\n", __func__);
1158299792Sadrian		error = ENXIO;
1159299792Sadrian		goto fail;
1160299792Sadrian	}
1161299792Sadrian
1162299792Sadrian#if 0
1163299792Sadrian	device_printf(sc->sc_dev, "%s: high=0x%08x, have_a=%d, have_bg=%d,"
1164299792Sadrian	    " deviceid=0x%04x, siba_deviceid=0x%04x\n",
1165299792Sadrian	    __func__,
1166299792Sadrian	    high,
1167299792Sadrian	    have_a,
1168299792Sadrian	    have_bg,
1169299792Sadrian	    siba_get_pci_device(sc->sc_dev),
1170299792Sadrian	    siba_get_chipid(sc->sc_dev));
1171299792Sadrian#endif
1172299792Sadrian
1173204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1174204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1175204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1176203945Sweongyo		have_a = have_bg = 0;
1177203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1178203945Sweongyo			have_a = 1;
1179203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1180203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1181203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1182203945Sweongyo			have_bg = 1;
1183203945Sweongyo		else
1184203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1185203945Sweongyo			    mac->mac_phy.type));
1186203945Sweongyo	}
1187203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1188203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1189203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1190203945Sweongyo		have_a = 0;
1191203945Sweongyo		have_bg = 1;
1192203945Sweongyo	}
1193203945Sweongyo
1194203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1195203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1196203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1197203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1198203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1199203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1200203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1201203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1202203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1203203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1204203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1205203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1206203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1207203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1208203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1209203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1210203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1211203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1212203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1213203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1214203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1215203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1216203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1217203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1218203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1219203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1220203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1221203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1222203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1223203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1224203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1225203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1226203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1227203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1228203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1229203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1230203945Sweongyo	} else {
1231203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1232203945Sweongyo		    mac->mac_phy.type);
1233203945Sweongyo		error = ENXIO;
1234203945Sweongyo		goto fail;
1235203945Sweongyo	}
1236203945Sweongyo
1237203945Sweongyo	mac->mac_phy.gmode = have_bg;
1238203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1239203945Sweongyo		error = mac->mac_phy.attach(mac);
1240203945Sweongyo		if (error) {
1241203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1242203945Sweongyo			goto fail;
1243203945Sweongyo		}
1244203945Sweongyo	}
1245203945Sweongyo
1246299776Sadrian	bwn_reset_core(mac, have_bg);
1247203945Sweongyo
1248203945Sweongyo	error = bwn_chiptest(mac);
1249203945Sweongyo	if (error)
1250203945Sweongyo		goto fail;
1251203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1252203945Sweongyo	if (error) {
1253203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1254203945Sweongyo		goto fail;
1255203945Sweongyo	}
1256203945Sweongyo
1257203945Sweongyo	if (sc->sc_curmac == NULL)
1258203945Sweongyo		sc->sc_curmac = mac;
1259203945Sweongyo
1260203945Sweongyo	error = bwn_dma_attach(mac);
1261203945Sweongyo	if (error != 0) {
1262203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1263203945Sweongyo		goto fail;
1264203945Sweongyo	}
1265203945Sweongyo
1266203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1267203945Sweongyo
1268204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1269203945Sweongyofail:
1270204922Sweongyo	siba_powerdown(sc->sc_dev);
1271203945Sweongyo	return (error);
1272203945Sweongyo}
1273203945Sweongyo
1274299776Sadrian/*
1275299776Sadrian * Reset - SIBA.
1276299776Sadrian *
1277299776Sadrian * XXX TODO: implement BCMA version!
1278299776Sadrian */
1279298948Sadrianvoid
1280299776Sadrianbwn_reset_core(struct bwn_mac *mac, int g_mode)
1281203945Sweongyo{
1282204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1283203945Sweongyo	uint32_t low, ctl;
1284299776Sadrian	uint32_t flags = 0;
1285203945Sweongyo
1286299776Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: g_mode=%d\n", __func__, g_mode);
1287299776Sadrian
1288203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1289299776Sadrian	if (g_mode)
1290299776Sadrian		flags |= BWN_TGSLOW_SUPPORT_G;
1291203945Sweongyo
1292299776Sadrian	/* XXX N-PHY only; and hard-code to 20MHz for now */
1293299776Sadrian	if (mac->mac_phy.type == BWN_PHYTYPE_N)
1294299776Sadrian		flags |= BWN_TGSLOW_PHY_BANDWIDTH_20MHZ;
1295299776Sadrian
1296204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1297203945Sweongyo	DELAY(2000);
1298203945Sweongyo
1299299776Sadrian	/* Take PHY out of reset */
1300204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1301203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1302204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1303204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1304203945Sweongyo	DELAY(1000);
1305204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1306204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1307203945Sweongyo	DELAY(1000);
1308203945Sweongyo
1309203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1310203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1311203945Sweongyo
1312203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1313299776Sadrian	if (g_mode)
1314203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1315203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1316203945Sweongyo}
1317203945Sweongyo
1318203945Sweongyostatic int
1319203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1320203945Sweongyo{
1321203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1322203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1323203945Sweongyo	uint32_t tmp;
1324203945Sweongyo
1325203945Sweongyo	/* PHY */
1326203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1327299776Sadrian	phy->gmode = !! (tgshigh & BWN_TGSHIGH_HAVE_2GHZ);
1328203945Sweongyo	phy->rf_on = 1;
1329203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1330203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1331203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1332203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1333203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1334203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1335203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1336203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1337203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1338203945Sweongyo		goto unsupphy;
1339203945Sweongyo
1340203945Sweongyo	/* RADIO */
1341204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1342204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1343203945Sweongyo			tmp = 0x3205017f;
1344204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1345203945Sweongyo			tmp = 0x4205017f;
1346203945Sweongyo		else
1347203945Sweongyo			tmp = 0x5205017f;
1348203945Sweongyo	} else {
1349203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1350203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1351203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1352203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1353203945Sweongyo	}
1354203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1355203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1356203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1357299792Sadrian
1358299792Sadrian	/*
1359299792Sadrian	 * For now, just always do full init (ie, what bwn has traditionally
1360299792Sadrian	 * done)
1361299792Sadrian	 */
1362299792Sadrian	phy->phy_do_full_init = 1;
1363299792Sadrian
1364203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1365203945Sweongyo		goto unsupradio;
1366203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1367203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1368203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1369203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1370203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1371203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1372203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1373203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1374203945Sweongyo		goto unsupradio;
1375203945Sweongyo
1376203945Sweongyo	return (0);
1377203945Sweongyounsupphy:
1378203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1379203945Sweongyo	    "analog %#x)\n",
1380203945Sweongyo	    phy->type, phy->rev, phy->analog);
1381203945Sweongyo	return (ENXIO);
1382203945Sweongyounsupradio:
1383203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1384203945Sweongyo	    "rev %#x)\n",
1385203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1386203945Sweongyo	return (ENXIO);
1387203945Sweongyo}
1388203945Sweongyo
1389203945Sweongyostatic int
1390203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1391203945Sweongyo{
1392203945Sweongyo#define	TESTVAL0	0x55aaaa55
1393203945Sweongyo#define	TESTVAL1	0xaa5555aa
1394203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1395203945Sweongyo	uint32_t v, backup;
1396203945Sweongyo
1397203945Sweongyo	BWN_LOCK(sc);
1398203945Sweongyo
1399203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1400203945Sweongyo
1401203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1402203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1403203945Sweongyo		goto error;
1404203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1405203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1406203945Sweongyo		goto error;
1407203945Sweongyo
1408203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1409203945Sweongyo
1410204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1411204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1412203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1413203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1414203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1415203945Sweongyo			goto error;
1416203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1417203945Sweongyo			goto error;
1418203945Sweongyo	}
1419203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1420203945Sweongyo
1421203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1422203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1423203945Sweongyo		goto error;
1424203945Sweongyo
1425203945Sweongyo	BWN_UNLOCK(sc);
1426203945Sweongyo	return (0);
1427203945Sweongyoerror:
1428203945Sweongyo	BWN_UNLOCK(sc);
1429203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1430203945Sweongyo	return (ENODEV);
1431203945Sweongyo}
1432203945Sweongyo
1433203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1434203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1435203945Sweongyo
1436203945Sweongyostatic int
1437203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1438203945Sweongyo{
1439203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1440287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1441203945Sweongyo
1442203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1443203945Sweongyo	ic->ic_nchans = 0;
1444203945Sweongyo
1445299792Sadrian	DPRINTF(sc, BWN_DEBUG_EEPROM, "%s: called; bg=%d, a=%d\n",
1446299792Sadrian	    __func__,
1447299792Sadrian	    have_bg,
1448299792Sadrian	    have_a);
1449299792Sadrian
1450203945Sweongyo	if (have_bg)
1451203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1452203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1453203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1454203945Sweongyo		if (have_a)
1455203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1456203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1457203945Sweongyo			    IEEE80211_CHAN_HTA);
1458203945Sweongyo	} else {
1459203945Sweongyo		if (have_a)
1460203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1461203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1462203945Sweongyo			    IEEE80211_CHAN_A);
1463203945Sweongyo	}
1464203945Sweongyo
1465203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1466203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1467203945Sweongyo
1468203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1469203945Sweongyo}
1470203945Sweongyo
1471298948Sadrianuint32_t
1472203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1473203945Sweongyo{
1474203945Sweongyo	uint32_t ret;
1475203945Sweongyo
1476204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1477203945Sweongyo
1478203945Sweongyo	if (way == BWN_SHARED) {
1479203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1480203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1481203945Sweongyo		if (offset & 0x0003) {
1482203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1483203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1484203945Sweongyo			ret <<= 16;
1485203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1486203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1487203945Sweongyo			goto out;
1488203945Sweongyo		}
1489203945Sweongyo		offset >>= 2;
1490203945Sweongyo	}
1491203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1492203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1493203945Sweongyoout:
1494203945Sweongyo	return (ret);
1495203945Sweongyo}
1496203945Sweongyo
1497298948Sadrianuint16_t
1498203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1499203945Sweongyo{
1500203945Sweongyo	uint16_t ret;
1501203945Sweongyo
1502204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1503203945Sweongyo
1504203945Sweongyo	if (way == BWN_SHARED) {
1505203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1506203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1507203945Sweongyo		if (offset & 0x0003) {
1508203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1509203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1510203945Sweongyo			goto out;
1511203945Sweongyo		}
1512203945Sweongyo		offset >>= 2;
1513203945Sweongyo	}
1514203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1515203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1516203945Sweongyoout:
1517203945Sweongyo
1518203945Sweongyo	return (ret);
1519203945Sweongyo}
1520203945Sweongyo
1521203945Sweongyostatic void
1522203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1523203945Sweongyo    uint16_t offset)
1524203945Sweongyo{
1525203945Sweongyo	uint32_t control;
1526203945Sweongyo
1527203945Sweongyo	control = way;
1528203945Sweongyo	control <<= 16;
1529203945Sweongyo	control |= offset;
1530203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1531203945Sweongyo}
1532203945Sweongyo
1533298948Sadrianvoid
1534203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1535203945Sweongyo    uint32_t value)
1536203945Sweongyo{
1537204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1538203945Sweongyo
1539203945Sweongyo	if (way == BWN_SHARED) {
1540203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1541203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1542203945Sweongyo		if (offset & 0x0003) {
1543203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1544203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1545203945Sweongyo				    (value >> 16) & 0xffff);
1546203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1547203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1548203945Sweongyo			return;
1549203945Sweongyo		}
1550203945Sweongyo		offset >>= 2;
1551203945Sweongyo	}
1552203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1553203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1554203945Sweongyo}
1555203945Sweongyo
1556298948Sadrianvoid
1557203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1558203945Sweongyo    uint16_t value)
1559203945Sweongyo{
1560204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1561203945Sweongyo
1562203945Sweongyo	if (way == BWN_SHARED) {
1563203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1564203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1565203945Sweongyo		if (offset & 0x0003) {
1566203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1567203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1568203945Sweongyo			return;
1569203945Sweongyo		}
1570203945Sweongyo		offset >>= 2;
1571203945Sweongyo	}
1572203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1573203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1574203945Sweongyo}
1575203945Sweongyo
1576203945Sweongyostatic void
1577203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1578203945Sweongyo    int txpow)
1579203945Sweongyo{
1580203945Sweongyo
1581203945Sweongyo	c->ic_freq = freq;
1582203945Sweongyo	c->ic_flags = flags;
1583203945Sweongyo	c->ic_ieee = ieee;
1584203945Sweongyo	c->ic_minpower = 0;
1585203945Sweongyo	c->ic_maxpower = 2 * txpow;
1586203945Sweongyo	c->ic_maxregpower = txpow;
1587203945Sweongyo}
1588203945Sweongyo
1589203945Sweongyostatic void
1590203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
1591203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
1592203945Sweongyo{
1593203945Sweongyo	struct ieee80211_channel *c;
1594203945Sweongyo	int i;
1595203945Sweongyo
1596203945Sweongyo	c = &chans[*nchans];
1597203945Sweongyo
1598203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
1599203945Sweongyo		const struct bwn_channel *hc;
1600203945Sweongyo
1601203945Sweongyo		hc = &ci->channels[i];
1602203945Sweongyo		if (*nchans >= maxchans)
1603203945Sweongyo			break;
1604203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
1605203945Sweongyo		c++, (*nchans)++;
1606203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
1607203945Sweongyo			/* g channel have a separate b-only entry */
1608203945Sweongyo			if (*nchans >= maxchans)
1609203945Sweongyo				break;
1610203945Sweongyo			c[0] = c[-1];
1611203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
1612203945Sweongyo			c++, (*nchans)++;
1613203945Sweongyo		}
1614203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
1615203945Sweongyo			/* HT g channel have a separate g-only entry */
1616203945Sweongyo			if (*nchans >= maxchans)
1617203945Sweongyo				break;
1618203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
1619203945Sweongyo			c[0] = c[-1];
1620203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1621203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1622203945Sweongyo			c++, (*nchans)++;
1623203945Sweongyo		}
1624203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
1625203945Sweongyo			/* HT a channel have a separate a-only entry */
1626203945Sweongyo			if (*nchans >= maxchans)
1627203945Sweongyo				break;
1628203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
1629203945Sweongyo			c[0] = c[-1];
1630203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1631203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1632203945Sweongyo			c++, (*nchans)++;
1633203945Sweongyo		}
1634203945Sweongyo	}
1635203945Sweongyo}
1636203945Sweongyo
1637203945Sweongyostatic int
1638203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1639203945Sweongyo	const struct ieee80211_bpf_params *params)
1640203945Sweongyo{
1641203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
1642286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1643203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1644289165Sadrian	int error;
1645203945Sweongyo
1646287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 ||
1647203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
1648203945Sweongyo		m_freem(m);
1649203945Sweongyo		return (ENETDOWN);
1650203945Sweongyo	}
1651203945Sweongyo
1652203945Sweongyo	BWN_LOCK(sc);
1653203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
1654203945Sweongyo		m_freem(m);
1655203945Sweongyo		BWN_UNLOCK(sc);
1656203945Sweongyo		return (ENOBUFS);
1657203945Sweongyo	}
1658203945Sweongyo
1659289165Sadrian	error = bwn_tx_start(sc, ni, m);
1660289165Sadrian	if (error == 0)
1661289165Sadrian		sc->sc_watchdog_timer = 5;
1662203945Sweongyo	BWN_UNLOCK(sc);
1663289165Sadrian	return (error);
1664203945Sweongyo}
1665203945Sweongyo
1666203945Sweongyo/*
1667203945Sweongyo * Callback from the 802.11 layer to update the slot time
1668203945Sweongyo * based on the current setting.  We use it to notify the
1669203945Sweongyo * firmware of ERP changes and the f/w takes care of things
1670203945Sweongyo * like slot time and preamble.
1671203945Sweongyo */
1672203945Sweongyostatic void
1673283540Sglebiusbwn_updateslot(struct ieee80211com *ic)
1674203945Sweongyo{
1675283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1676203945Sweongyo	struct bwn_mac *mac;
1677203945Sweongyo
1678203945Sweongyo	BWN_LOCK(sc);
1679287197Sglebius	if (sc->sc_flags & BWN_FLAG_RUNNING) {
1680203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
1681292165Savos		bwn_set_slot_time(mac, IEEE80211_GET_SLOTTIME(ic));
1682203945Sweongyo	}
1683203945Sweongyo	BWN_UNLOCK(sc);
1684203945Sweongyo}
1685203945Sweongyo
1686203945Sweongyo/*
1687203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
1688203945Sweongyo * Note this interface does not check the operating mode as this
1689203945Sweongyo * is an internal callback and we are expected to honor the current
1690203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
1691203945Sweongyo * mode when operating in hostap mode to do ACS).
1692203945Sweongyo */
1693203945Sweongyostatic void
1694283540Sglebiusbwn_update_promisc(struct ieee80211com *ic)
1695203945Sweongyo{
1696283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1697203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1698203945Sweongyo
1699203945Sweongyo	BWN_LOCK(sc);
1700203945Sweongyo	mac = sc->sc_curmac;
1701203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1702287197Sglebius		if (ic->ic_promisc > 0)
1703203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
1704203945Sweongyo		else
1705203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
1706203945Sweongyo		bwn_set_opmode(mac);
1707203945Sweongyo	}
1708203945Sweongyo	BWN_UNLOCK(sc);
1709203945Sweongyo}
1710203945Sweongyo
1711203945Sweongyo/*
1712203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
1713203945Sweongyo */
1714203945Sweongyostatic int
1715203945Sweongyobwn_wme_update(struct ieee80211com *ic)
1716203945Sweongyo{
1717286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1718203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1719203945Sweongyo	struct wmeParams *wmep;
1720203945Sweongyo	int i;
1721203945Sweongyo
1722203945Sweongyo	BWN_LOCK(sc);
1723203945Sweongyo	mac = sc->sc_curmac;
1724203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1725203945Sweongyo		bwn_mac_suspend(mac);
1726203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
1727203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
1728203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
1729203945Sweongyo		}
1730203945Sweongyo		bwn_mac_enable(mac);
1731203945Sweongyo	}
1732203945Sweongyo	BWN_UNLOCK(sc);
1733203945Sweongyo	return (0);
1734203945Sweongyo}
1735203945Sweongyo
1736203945Sweongyostatic void
1737203945Sweongyobwn_scan_start(struct ieee80211com *ic)
1738203945Sweongyo{
1739286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1740203945Sweongyo	struct bwn_mac *mac;
1741203945Sweongyo
1742203945Sweongyo	BWN_LOCK(sc);
1743203945Sweongyo	mac = sc->sc_curmac;
1744203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1745203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
1746203945Sweongyo		bwn_set_opmode(mac);
1747203945Sweongyo		/* disable CFP update during scan */
1748203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
1749203945Sweongyo	}
1750203945Sweongyo	BWN_UNLOCK(sc);
1751203945Sweongyo}
1752203945Sweongyo
1753203945Sweongyostatic void
1754203945Sweongyobwn_scan_end(struct ieee80211com *ic)
1755203945Sweongyo{
1756286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1757203945Sweongyo	struct bwn_mac *mac;
1758203945Sweongyo
1759203945Sweongyo	BWN_LOCK(sc);
1760203945Sweongyo	mac = sc->sc_curmac;
1761203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1762203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
1763203945Sweongyo		bwn_set_opmode(mac);
1764203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
1765203945Sweongyo	}
1766203945Sweongyo	BWN_UNLOCK(sc);
1767203945Sweongyo}
1768203945Sweongyo
1769203945Sweongyostatic void
1770203945Sweongyobwn_set_channel(struct ieee80211com *ic)
1771203945Sweongyo{
1772286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1773203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1774203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1775203945Sweongyo	int chan, error;
1776203945Sweongyo
1777203945Sweongyo	BWN_LOCK(sc);
1778203945Sweongyo
1779203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
1780203945Sweongyo	if (error)
1781216227Skevlo		goto fail;
1782203945Sweongyo	bwn_mac_suspend(mac);
1783203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
1784203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
1785203945Sweongyo	if (chan != phy->chan)
1786203945Sweongyo		bwn_switch_channel(mac, chan);
1787203945Sweongyo
1788203945Sweongyo	/* TX power level */
1789203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
1790203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
1791203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
1792203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
1793203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
1794203945Sweongyo	}
1795203945Sweongyo
1796203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
1797203945Sweongyo	if (phy->set_antenna)
1798203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
1799203945Sweongyo
1800203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
1801203945Sweongyo		if (sc->sc_rf_enabled) {
1802203945Sweongyo			bwn_rf_turnon(mac);
1803203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
1804203945Sweongyo				device_printf(sc->sc_dev,
1805213719Sjoel				    "please turn on the RF switch\n");
1806203945Sweongyo		} else
1807203945Sweongyo			bwn_rf_turnoff(mac);
1808203945Sweongyo	}
1809203945Sweongyo
1810203945Sweongyo	bwn_mac_enable(mac);
1811203945Sweongyo
1812203945Sweongyofail:
1813203945Sweongyo	/*
1814203945Sweongyo	 * Setup radio tap channel freq and flags
1815203945Sweongyo	 */
1816203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
1817203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
1818203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
1819203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
1820203945Sweongyo
1821203945Sweongyo	BWN_UNLOCK(sc);
1822203945Sweongyo}
1823203945Sweongyo
1824203945Sweongyostatic struct ieee80211vap *
1825228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
1826228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
1827228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
1828287197Sglebius    const uint8_t mac[IEEE80211_ADDR_LEN])
1829203945Sweongyo{
1830203945Sweongyo	struct ieee80211vap *vap;
1831203945Sweongyo	struct bwn_vap *bvp;
1832203945Sweongyo
1833203945Sweongyo	switch (opmode) {
1834203945Sweongyo	case IEEE80211_M_HOSTAP:
1835203945Sweongyo	case IEEE80211_M_MBSS:
1836203945Sweongyo	case IEEE80211_M_STA:
1837203945Sweongyo	case IEEE80211_M_WDS:
1838203945Sweongyo	case IEEE80211_M_MONITOR:
1839203945Sweongyo	case IEEE80211_M_IBSS:
1840203945Sweongyo	case IEEE80211_M_AHDEMO:
1841203945Sweongyo		break;
1842203945Sweongyo	default:
1843203945Sweongyo		return (NULL);
1844203945Sweongyo	}
1845203945Sweongyo
1846287197Sglebius	bvp = malloc(sizeof(struct bwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
1847203945Sweongyo	vap = &bvp->bv_vap;
1848287197Sglebius	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
1849203945Sweongyo	/* override with driver methods */
1850203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
1851203945Sweongyo	vap->iv_newstate = bwn_newstate;
1852203945Sweongyo
1853203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
1854203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
1855203945Sweongyo
1856206358Srpaulo	ieee80211_ratectl_init(vap);
1857203945Sweongyo
1858203945Sweongyo	/* complete setup */
1859203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
1860287197Sglebius	    ieee80211_media_status, mac);
1861203945Sweongyo	return (vap);
1862203945Sweongyo}
1863203945Sweongyo
1864203945Sweongyostatic void
1865203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
1866203945Sweongyo{
1867203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
1868203945Sweongyo
1869206358Srpaulo	ieee80211_ratectl_deinit(vap);
1870203945Sweongyo	ieee80211_vap_detach(vap);
1871203945Sweongyo	free(bvp, M_80211_VAP);
1872203945Sweongyo}
1873203945Sweongyo
1874203945Sweongyostatic int
1875287197Sglebiusbwn_init(struct bwn_softc *sc)
1876203945Sweongyo{
1877203945Sweongyo	struct bwn_mac *mac;
1878203945Sweongyo	int error;
1879203945Sweongyo
1880203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1881203945Sweongyo
1882299793Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
1883299793Sadrian
1884203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
1885203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
1886203945Sweongyo	sc->sc_filters = 0;
1887203945Sweongyo	bwn_wme_clear(sc);
1888203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
1889203945Sweongyo	sc->sc_rf_enabled = 1;
1890203945Sweongyo
1891203945Sweongyo	mac = sc->sc_curmac;
1892203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
1893203945Sweongyo		error = bwn_core_init(mac);
1894203945Sweongyo		if (error != 0)
1895203945Sweongyo			return (error);
1896203945Sweongyo	}
1897203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
1898203945Sweongyo		bwn_core_start(mac);
1899203945Sweongyo
1900203945Sweongyo	bwn_set_opmode(mac);
1901203945Sweongyo	bwn_set_pretbtt(mac);
1902203945Sweongyo	bwn_spu_setdelay(mac, 0);
1903203945Sweongyo	bwn_set_macaddr(mac);
1904203945Sweongyo
1905287197Sglebius	sc->sc_flags |= BWN_FLAG_RUNNING;
1906203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
1907203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
1908203945Sweongyo
1909203945Sweongyo	return (0);
1910203945Sweongyo}
1911203945Sweongyo
1912203945Sweongyostatic void
1913287197Sglebiusbwn_stop(struct bwn_softc *sc)
1914203945Sweongyo{
1915203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1916203945Sweongyo
1917203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1918203945Sweongyo
1919299793Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
1920299793Sadrian
1921203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
1922203945Sweongyo		/* XXX FIXME opmode not based on VAP */
1923203945Sweongyo		bwn_set_opmode(mac);
1924203945Sweongyo		bwn_set_macaddr(mac);
1925203945Sweongyo	}
1926203945Sweongyo
1927203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
1928203945Sweongyo		bwn_core_stop(mac);
1929203945Sweongyo
1930203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
1931203945Sweongyo	sc->sc_led_blinking = 0;
1932203945Sweongyo
1933203945Sweongyo	bwn_core_exit(mac);
1934203945Sweongyo	sc->sc_rf_enabled = 0;
1935203945Sweongyo
1936287197Sglebius	sc->sc_flags &= ~BWN_FLAG_RUNNING;
1937203945Sweongyo}
1938203945Sweongyo
1939203945Sweongyostatic void
1940203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
1941203945Sweongyo{
1942203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
1943203945Sweongyo	struct wmeParams *p;
1944203945Sweongyo	unsigned int i;
1945203945Sweongyo
1946203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
1947203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1948203945Sweongyo
1949203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
1950203945Sweongyo		p = &(sc->sc_wmeParams[i]);
1951203945Sweongyo
1952203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
1953203945Sweongyo		case BWN_WME_VOICE:
1954203945Sweongyo			p->wmep_txopLimit = 0;
1955203945Sweongyo			p->wmep_aifsn = 2;
1956203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1957203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1958203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1959203945Sweongyo			break;
1960203945Sweongyo		case BWN_WME_VIDEO:
1961203945Sweongyo			p->wmep_txopLimit = 0;
1962203945Sweongyo			p->wmep_aifsn = 2;
1963203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1964203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1965203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1966203945Sweongyo			break;
1967203945Sweongyo		case BWN_WME_BESTEFFORT:
1968203945Sweongyo			p->wmep_txopLimit = 0;
1969203945Sweongyo			p->wmep_aifsn = 3;
1970203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1971203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1972203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1973203945Sweongyo			break;
1974203945Sweongyo		case BWN_WME_BACKGROUND:
1975203945Sweongyo			p->wmep_txopLimit = 0;
1976203945Sweongyo			p->wmep_aifsn = 7;
1977203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1978203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1979203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1980203945Sweongyo			break;
1981203945Sweongyo		default:
1982203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1983203945Sweongyo		}
1984203945Sweongyo	}
1985203945Sweongyo}
1986203945Sweongyo
1987203945Sweongyostatic int
1988203945Sweongyobwn_core_init(struct bwn_mac *mac)
1989203945Sweongyo{
1990203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1991203945Sweongyo	uint64_t hf;
1992203945Sweongyo	int error;
1993203945Sweongyo
1994203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
1995203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1996203945Sweongyo
1997204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1998204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
1999299776Sadrian		bwn_reset_core(mac, mac->mac_phy.gmode);
2000203945Sweongyo
2001203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
2002203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
2003203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
2004203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
2005203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
2006203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
2007203945Sweongyo	mac->mac_stats.link_noise = -95;
2008203945Sweongyo	mac->mac_reason_intr = 0;
2009203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
2010203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
2011203945Sweongyo#ifdef BWN_DEBUG
2012203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
2013203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
2014203945Sweongyo#endif
2015203945Sweongyo	mac->mac_suspended = 1;
2016203945Sweongyo	mac->mac_task_state = 0;
2017203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
2018203945Sweongyo
2019203945Sweongyo	mac->mac_phy.init_pre(mac);
2020203945Sweongyo
2021204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
2022203945Sweongyo
2023204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
2024203945Sweongyo	bwn_bt_disable(mac);
2025203945Sweongyo	if (mac->mac_phy.prepare_hw) {
2026203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
2027203945Sweongyo		if (error)
2028203945Sweongyo			goto fail0;
2029203945Sweongyo	}
2030203945Sweongyo	error = bwn_chip_init(mac);
2031203945Sweongyo	if (error)
2032203945Sweongyo		goto fail0;
2033203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
2034204922Sweongyo	    siba_get_revid(sc->sc_dev));
2035203945Sweongyo	hf = bwn_hf_read(mac);
2036203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
2037203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
2038204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2039203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
2040203945Sweongyo		if (mac->mac_phy.rev == 1)
2041203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
2042203945Sweongyo	}
2043203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
2044203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
2045203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
2046203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
2047203945Sweongyo			hf |= BWN_HF_4318_TSSI;
2048203945Sweongyo	}
2049204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
2050203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
2051204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
2052204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
2053203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
2054203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
2055203945Sweongyo	bwn_hf_write(mac, hf);
2056203945Sweongyo
2057203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2058203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
2059203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
2060203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
2061203945Sweongyo
2062203945Sweongyo	bwn_rate_init(mac);
2063203945Sweongyo	bwn_set_phytxctl(mac);
2064203945Sweongyo
2065203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
2066203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
2067203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
2068203945Sweongyo
2069204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
2070203945Sweongyo		bwn_pio_init(mac);
2071203945Sweongyo	else
2072203945Sweongyo		bwn_dma_init(mac);
2073203945Sweongyo	bwn_wme_init(mac);
2074203945Sweongyo	bwn_spu_setdelay(mac, 1);
2075203945Sweongyo	bwn_bt_enable(mac);
2076203945Sweongyo
2077204922Sweongyo	siba_powerup(sc->sc_dev,
2078204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
2079203945Sweongyo	bwn_set_macaddr(mac);
2080203945Sweongyo	bwn_crypt_init(mac);
2081203945Sweongyo
2082203945Sweongyo	/* XXX LED initializatin */
2083203945Sweongyo
2084203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
2085203945Sweongyo
2086203945Sweongyo	return (error);
2087203945Sweongyo
2088203945Sweongyofail0:
2089204922Sweongyo	siba_powerdown(sc->sc_dev);
2090203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
2091203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2092203945Sweongyo	return (error);
2093203945Sweongyo}
2094203945Sweongyo
2095203945Sweongyostatic void
2096203945Sweongyobwn_core_start(struct bwn_mac *mac)
2097203945Sweongyo{
2098203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2099203945Sweongyo	uint32_t tmp;
2100203945Sweongyo
2101203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
2102203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2103203945Sweongyo
2104204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2105203945Sweongyo		return;
2106203945Sweongyo
2107203945Sweongyo	while (1) {
2108203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
2109203945Sweongyo		if (!(tmp & 0x00000001))
2110203945Sweongyo			break;
2111203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
2112203945Sweongyo	}
2113203945Sweongyo
2114203945Sweongyo	bwn_mac_enable(mac);
2115203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
2116203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
2117203945Sweongyo
2118203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
2119203945Sweongyo}
2120203945Sweongyo
2121203945Sweongyostatic void
2122203945Sweongyobwn_core_exit(struct bwn_mac *mac)
2123203945Sweongyo{
2124204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2125203945Sweongyo	uint32_t macctl;
2126203945Sweongyo
2127204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
2128203945Sweongyo
2129203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
2130203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2131203945Sweongyo
2132203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
2133203945Sweongyo		return;
2134203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
2135203945Sweongyo
2136203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
2137203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
2138203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
2139203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2140203945Sweongyo
2141203945Sweongyo	bwn_dma_stop(mac);
2142203945Sweongyo	bwn_pio_stop(mac);
2143203945Sweongyo	bwn_chip_exit(mac);
2144203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
2145204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
2146204922Sweongyo	siba_powerdown(sc->sc_dev);
2147203945Sweongyo}
2148203945Sweongyo
2149203945Sweongyostatic void
2150203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
2151203945Sweongyo{
2152203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2153203945Sweongyo
2154203945Sweongyo	(void)sc;
2155203945Sweongyo	/* XXX do nothing yet */
2156203945Sweongyo}
2157203945Sweongyo
2158203945Sweongyostatic int
2159203945Sweongyobwn_chip_init(struct bwn_mac *mac)
2160203945Sweongyo{
2161204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2162203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2163203945Sweongyo	uint32_t macctl;
2164203945Sweongyo	int error;
2165203945Sweongyo
2166203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
2167203945Sweongyo	if (phy->gmode)
2168203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
2169203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2170203945Sweongyo
2171203945Sweongyo	error = bwn_fw_fillinfo(mac);
2172203945Sweongyo	if (error)
2173203945Sweongyo		return (error);
2174203945Sweongyo	error = bwn_fw_loaducode(mac);
2175203945Sweongyo	if (error)
2176203945Sweongyo		return (error);
2177203945Sweongyo
2178203945Sweongyo	error = bwn_gpio_init(mac);
2179203945Sweongyo	if (error)
2180203945Sweongyo		return (error);
2181203945Sweongyo
2182203945Sweongyo	error = bwn_fw_loadinitvals(mac);
2183203945Sweongyo	if (error) {
2184204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2185203945Sweongyo		return (error);
2186203945Sweongyo	}
2187203945Sweongyo	phy->switch_analog(mac, 1);
2188203945Sweongyo	error = bwn_phy_init(mac);
2189203945Sweongyo	if (error) {
2190204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2191203945Sweongyo		return (error);
2192203945Sweongyo	}
2193203945Sweongyo	if (phy->set_im)
2194203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
2195203945Sweongyo	if (phy->set_antenna)
2196203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2197203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2198203945Sweongyo
2199203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
2200203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
2201203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
2202204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2203203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
2204203945Sweongyo
2205203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2206203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
2207203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2208203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
2209203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
2210203945Sweongyo
2211203945Sweongyo	bwn_set_opmode(mac);
2212204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
2213203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
2214203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
2215203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
2216203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
2217203945Sweongyo	} else {
2218203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
2219203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
2220203945Sweongyo	}
2221203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
2222203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
2223203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
2224203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
2225203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
2226203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
2227203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
2228299776Sadrian
2229299776Sadrian	bwn_mac_phy_clock_set(mac, true);
2230299776Sadrian
2231299776Sadrian	/* SIBA powerup */
2232299776Sadrian	/* XXX TODO: BCMA powerup */
2233204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
2234203945Sweongyo	return (error);
2235203945Sweongyo}
2236203945Sweongyo
2237203945Sweongyo/* read hostflags */
2238298944Sadrianuint64_t
2239203945Sweongyobwn_hf_read(struct bwn_mac *mac)
2240203945Sweongyo{
2241203945Sweongyo	uint64_t ret;
2242203945Sweongyo
2243203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
2244203945Sweongyo	ret <<= 16;
2245203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
2246203945Sweongyo	ret <<= 16;
2247203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
2248203945Sweongyo	return (ret);
2249203945Sweongyo}
2250203945Sweongyo
2251298944Sadrianvoid
2252203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
2253203945Sweongyo{
2254203945Sweongyo
2255203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
2256203945Sweongyo	    (value & 0x00000000ffffull));
2257203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
2258203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
2259203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
2260203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
2261203945Sweongyo}
2262203945Sweongyo
2263203945Sweongyostatic void
2264203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
2265203945Sweongyo{
2266203945Sweongyo
2267203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
2268203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
2269203945Sweongyo}
2270203945Sweongyo
2271203945Sweongyostatic void
2272203945Sweongyobwn_rate_init(struct bwn_mac *mac)
2273203945Sweongyo{
2274203945Sweongyo
2275203945Sweongyo	switch (mac->mac_phy.type) {
2276203945Sweongyo	case BWN_PHYTYPE_A:
2277203945Sweongyo	case BWN_PHYTYPE_G:
2278203945Sweongyo	case BWN_PHYTYPE_LP:
2279203945Sweongyo	case BWN_PHYTYPE_N:
2280203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
2281203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
2282203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
2283203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
2284203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
2285203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
2286203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
2287203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
2288203945Sweongyo			break;
2289203945Sweongyo		/* FALLTHROUGH */
2290203945Sweongyo	case BWN_PHYTYPE_B:
2291203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
2292203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
2293203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
2294203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
2295203945Sweongyo		break;
2296203945Sweongyo	default:
2297203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2298203945Sweongyo	}
2299203945Sweongyo}
2300203945Sweongyo
2301203945Sweongyostatic void
2302203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
2303203945Sweongyo{
2304203945Sweongyo	uint16_t offset;
2305203945Sweongyo
2306203945Sweongyo	if (ofdm) {
2307203945Sweongyo		offset = 0x480;
2308203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
2309203945Sweongyo	} else {
2310203945Sweongyo		offset = 0x4c0;
2311203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
2312203945Sweongyo	}
2313203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
2314203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
2315203945Sweongyo}
2316203945Sweongyo
2317203945Sweongyostatic uint8_t
2318203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
2319203945Sweongyo{
2320203945Sweongyo
2321203945Sweongyo	switch (bitrate) {
2322203945Sweongyo	case BWN_CCK_RATE_1MB:
2323203945Sweongyo		return (0x0a);
2324203945Sweongyo	case BWN_CCK_RATE_2MB:
2325203945Sweongyo		return (0x14);
2326203945Sweongyo	case BWN_CCK_RATE_5MB:
2327203945Sweongyo		return (0x37);
2328203945Sweongyo	case BWN_CCK_RATE_11MB:
2329203945Sweongyo		return (0x6e);
2330203945Sweongyo	}
2331203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2332203945Sweongyo	return (0);
2333203945Sweongyo}
2334203945Sweongyo
2335203945Sweongyostatic uint8_t
2336203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
2337203945Sweongyo{
2338203945Sweongyo
2339203945Sweongyo	switch (bitrate) {
2340203945Sweongyo	case BWN_OFDM_RATE_6MB:
2341203945Sweongyo		return (0xb);
2342203945Sweongyo	case BWN_OFDM_RATE_9MB:
2343203945Sweongyo		return (0xf);
2344203945Sweongyo	case BWN_OFDM_RATE_12MB:
2345203945Sweongyo		return (0xa);
2346203945Sweongyo	case BWN_OFDM_RATE_18MB:
2347203945Sweongyo		return (0xe);
2348203945Sweongyo	case BWN_OFDM_RATE_24MB:
2349203945Sweongyo		return (0x9);
2350203945Sweongyo	case BWN_OFDM_RATE_36MB:
2351203945Sweongyo		return (0xd);
2352203945Sweongyo	case BWN_OFDM_RATE_48MB:
2353203945Sweongyo		return (0x8);
2354203945Sweongyo	case BWN_OFDM_RATE_54MB:
2355203945Sweongyo		return (0xc);
2356203945Sweongyo	}
2357203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2358203945Sweongyo	return (0);
2359203945Sweongyo}
2360203945Sweongyo
2361203945Sweongyostatic void
2362203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
2363203945Sweongyo{
2364203945Sweongyo	uint16_t ctl;
2365203945Sweongyo
2366203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
2367203945Sweongyo	    BWN_TX_PHY_TXPWR);
2368203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
2369203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
2370203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
2371203945Sweongyo}
2372203945Sweongyo
2373203945Sweongyostatic void
2374203945Sweongyobwn_pio_init(struct bwn_mac *mac)
2375203945Sweongyo{
2376203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
2377203945Sweongyo
2378203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
2379203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
2380203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
2381203945Sweongyo
2382203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
2383203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
2384203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
2385203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
2386203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
2387203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
2388203945Sweongyo}
2389203945Sweongyo
2390203945Sweongyostatic void
2391203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2392203945Sweongyo    int index)
2393203945Sweongyo{
2394203945Sweongyo	struct bwn_pio_txpkt *tp;
2395204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2396203945Sweongyo	unsigned int i;
2397203945Sweongyo
2398203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
2399203945Sweongyo	tq->tq_index = index;
2400203945Sweongyo
2401203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
2402204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
2403203945Sweongyo		tq->tq_size = 1920;
2404203945Sweongyo	else {
2405203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
2406203945Sweongyo		tq->tq_size -= 80;
2407203945Sweongyo	}
2408203945Sweongyo
2409203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
2410203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2411203945Sweongyo		tp = &(tq->tq_pkts[i]);
2412203945Sweongyo		tp->tp_index = i;
2413203945Sweongyo		tp->tp_queue = tq;
2414203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
2415203945Sweongyo	}
2416203945Sweongyo}
2417203945Sweongyo
2418203945Sweongyostatic uint16_t
2419203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
2420203945Sweongyo{
2421203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2422203945Sweongyo	static const uint16_t bases[] = {
2423203945Sweongyo		BWN_PIO_BASE0,
2424203945Sweongyo		BWN_PIO_BASE1,
2425203945Sweongyo		BWN_PIO_BASE2,
2426203945Sweongyo		BWN_PIO_BASE3,
2427203945Sweongyo		BWN_PIO_BASE4,
2428203945Sweongyo		BWN_PIO_BASE5,
2429203945Sweongyo		BWN_PIO_BASE6,
2430203945Sweongyo		BWN_PIO_BASE7,
2431203945Sweongyo	};
2432203945Sweongyo	static const uint16_t bases_rev11[] = {
2433203945Sweongyo		BWN_PIO11_BASE0,
2434203945Sweongyo		BWN_PIO11_BASE1,
2435203945Sweongyo		BWN_PIO11_BASE2,
2436203945Sweongyo		BWN_PIO11_BASE3,
2437203945Sweongyo		BWN_PIO11_BASE4,
2438203945Sweongyo		BWN_PIO11_BASE5,
2439203945Sweongyo	};
2440203945Sweongyo
2441204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
2442203945Sweongyo		if (index >= N(bases_rev11))
2443203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
2444203945Sweongyo		return (bases_rev11[index]);
2445203945Sweongyo	}
2446203945Sweongyo	if (index >= N(bases))
2447203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
2448203945Sweongyo	return (bases[index]);
2449203945Sweongyo}
2450203945Sweongyo
2451203945Sweongyostatic void
2452203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
2453203945Sweongyo    int index)
2454203945Sweongyo{
2455204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2456203945Sweongyo
2457203945Sweongyo	prq->prq_mac = mac;
2458204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
2459203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
2460203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
2461203945Sweongyo}
2462203945Sweongyo
2463203945Sweongyostatic void
2464203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
2465203945Sweongyo{
2466203945Sweongyo	if (tq == NULL)
2467203945Sweongyo		return;
2468203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
2469203945Sweongyo}
2470203945Sweongyo
2471203945Sweongyostatic void
2472203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
2473203945Sweongyo{
2474203945Sweongyo
2475203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
2476203945Sweongyo}
2477203945Sweongyo
2478203945Sweongyostatic uint16_t
2479203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2480203945Sweongyo    uint16_t offset)
2481203945Sweongyo{
2482203945Sweongyo
2483203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
2484203945Sweongyo}
2485203945Sweongyo
2486203945Sweongyostatic void
2487203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
2488203945Sweongyo{
2489203945Sweongyo	uint32_t ctl;
2490203945Sweongyo	int type;
2491203945Sweongyo	uint16_t base;
2492203945Sweongyo
2493203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
2494203945Sweongyo	base = bwn_dma_base(type, idx);
2495203945Sweongyo	if (type == BWN_DMA_64BIT) {
2496203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
2497203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
2498203945Sweongyo		if (enable)
2499203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
2500203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
2501203945Sweongyo	} else {
2502203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
2503203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
2504203945Sweongyo		if (enable)
2505203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
2506203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
2507203945Sweongyo	}
2508203945Sweongyo}
2509203945Sweongyo
2510203945Sweongyostatic uint64_t
2511203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
2512203945Sweongyo{
2513203945Sweongyo	uint32_t tmp;
2514203945Sweongyo	uint16_t base;
2515203945Sweongyo
2516203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
2517203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
2518203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
2519203945Sweongyo	base = bwn_dma_base(0, 0);
2520203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
2521203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
2522203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
2523203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
2524203945Sweongyo
2525203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
2526203945Sweongyo}
2527203945Sweongyo
2528203945Sweongyostatic int
2529203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
2530203945Sweongyo{
2531203945Sweongyo
2532203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
2533203945Sweongyo		return (BWN_DMA_30BIT);
2534203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
2535203945Sweongyo		return (BWN_DMA_32BIT);
2536203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
2537203945Sweongyo		return (BWN_DMA_64BIT);
2538203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2539203945Sweongyo	return (BWN_DMA_30BIT);
2540203945Sweongyo}
2541203945Sweongyo
2542203945Sweongyostatic void
2543203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
2544203945Sweongyo{
2545203945Sweongyo	struct bwn_pio_txpkt *tp;
2546203945Sweongyo	unsigned int i;
2547203945Sweongyo
2548203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2549203945Sweongyo		tp = &(tq->tq_pkts[i]);
2550203945Sweongyo		if (tp->tp_m) {
2551203945Sweongyo			m_freem(tp->tp_m);
2552203945Sweongyo			tp->tp_m = NULL;
2553203945Sweongyo		}
2554203945Sweongyo	}
2555203945Sweongyo}
2556203945Sweongyo
2557203945Sweongyostatic uint16_t
2558203945Sweongyobwn_dma_base(int type, int controller_idx)
2559203945Sweongyo{
2560203945Sweongyo	static const uint16_t map64[] = {
2561203945Sweongyo		BWN_DMA64_BASE0,
2562203945Sweongyo		BWN_DMA64_BASE1,
2563203945Sweongyo		BWN_DMA64_BASE2,
2564203945Sweongyo		BWN_DMA64_BASE3,
2565203945Sweongyo		BWN_DMA64_BASE4,
2566203945Sweongyo		BWN_DMA64_BASE5,
2567203945Sweongyo	};
2568203945Sweongyo	static const uint16_t map32[] = {
2569203945Sweongyo		BWN_DMA32_BASE0,
2570203945Sweongyo		BWN_DMA32_BASE1,
2571203945Sweongyo		BWN_DMA32_BASE2,
2572203945Sweongyo		BWN_DMA32_BASE3,
2573203945Sweongyo		BWN_DMA32_BASE4,
2574203945Sweongyo		BWN_DMA32_BASE5,
2575203945Sweongyo	};
2576203945Sweongyo
2577203945Sweongyo	if (type == BWN_DMA_64BIT) {
2578203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
2579203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2580203945Sweongyo		return (map64[controller_idx]);
2581203945Sweongyo	}
2582203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
2583203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2584203945Sweongyo	return (map32[controller_idx]);
2585203945Sweongyo}
2586203945Sweongyo
2587203945Sweongyostatic void
2588203945Sweongyobwn_dma_init(struct bwn_mac *mac)
2589203945Sweongyo{
2590203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2591203945Sweongyo
2592203945Sweongyo	/* setup TX DMA channels. */
2593203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
2594203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
2595203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
2596203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
2597203945Sweongyo	bwn_dma_setup(dma->mcast);
2598203945Sweongyo	/* setup RX DMA channel. */
2599203945Sweongyo	bwn_dma_setup(dma->rx);
2600203945Sweongyo}
2601203945Sweongyo
2602203945Sweongyostatic struct bwn_dma_ring *
2603203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
2604203945Sweongyo    int for_tx, int type)
2605203945Sweongyo{
2606203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2607203945Sweongyo	struct bwn_dma_ring *dr;
2608203945Sweongyo	struct bwn_dmadesc_generic *desc;
2609203945Sweongyo	struct bwn_dmadesc_meta *mt;
2610203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2611203945Sweongyo	int error, i;
2612203945Sweongyo
2613203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
2614203945Sweongyo	if (dr == NULL)
2615203945Sweongyo		goto out;
2616203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
2617203945Sweongyo	if (for_tx)
2618203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
2619203945Sweongyo
2620203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
2621203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
2622203945Sweongyo	if (dr->dr_meta == NULL)
2623203945Sweongyo		goto fail0;
2624203945Sweongyo
2625203945Sweongyo	dr->dr_type = type;
2626203945Sweongyo	dr->dr_mac = mac;
2627203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
2628203945Sweongyo	dr->dr_index = controller_index;
2629203945Sweongyo	if (type == BWN_DMA_64BIT) {
2630203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
2631203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
2632203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
2633203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
2634203945Sweongyo		dr->resume = bwn_dma_64_resume;
2635203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
2636203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
2637203945Sweongyo	} else {
2638203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
2639203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
2640203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
2641203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
2642203945Sweongyo		dr->resume = bwn_dma_32_resume;
2643203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
2644203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
2645203945Sweongyo	}
2646203945Sweongyo	if (for_tx) {
2647203945Sweongyo		dr->dr_tx = 1;
2648203945Sweongyo		dr->dr_curslot = -1;
2649203945Sweongyo	} else {
2650203945Sweongyo		if (dr->dr_index == 0) {
2651203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
2652203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
2653203945Sweongyo		} else
2654203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2655203945Sweongyo	}
2656203945Sweongyo
2657203945Sweongyo	error = bwn_dma_allocringmemory(dr);
2658203945Sweongyo	if (error)
2659203945Sweongyo		goto fail2;
2660203945Sweongyo
2661203945Sweongyo	if (for_tx) {
2662203945Sweongyo		/*
2663203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
2664203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
2665203945Sweongyo		 */
2666203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
2667203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2668203945Sweongyo
2669203945Sweongyo		dr->dr_txhdr_cache =
2670203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
2671203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
2672203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
2673203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2674203945Sweongyo
2675203945Sweongyo		/*
2676203945Sweongyo		 * Create TX ring DMA stuffs
2677203945Sweongyo		 */
2678203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
2679203945Sweongyo				    BWN_ALIGN, 0,
2680203945Sweongyo				    BUS_SPACE_MAXADDR,
2681203945Sweongyo				    BUS_SPACE_MAXADDR,
2682203945Sweongyo				    NULL, NULL,
2683203945Sweongyo				    BWN_HDRSIZE(mac),
2684203945Sweongyo				    1,
2685203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
2686203945Sweongyo				    0,
2687203945Sweongyo				    NULL, NULL,
2688203945Sweongyo				    &dr->dr_txring_dtag);
2689203945Sweongyo		if (error) {
2690203945Sweongyo			device_printf(sc->sc_dev,
2691203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
2692203945Sweongyo			goto fail1;
2693203945Sweongyo		}
2694203945Sweongyo
2695203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
2696203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2697203945Sweongyo
2698203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
2699203945Sweongyo			mt->mt_m = NULL;
2700203945Sweongyo			mt->mt_ni = NULL;
2701203945Sweongyo			mt->mt_islast = 0;
2702203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
2703203945Sweongyo			    &mt->mt_dmap);
2704203945Sweongyo			if (error) {
2705203945Sweongyo				device_printf(sc->sc_dev,
2706203945Sweongyo				     "can't create RX buf DMA map\n");
2707203945Sweongyo				goto fail1;
2708203945Sweongyo			}
2709203945Sweongyo
2710203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
2711203945Sweongyo
2712203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
2713203945Sweongyo			mt->mt_m = NULL;
2714203945Sweongyo			mt->mt_ni = NULL;
2715203945Sweongyo			mt->mt_islast = 1;
2716203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
2717203945Sweongyo			    &mt->mt_dmap);
2718203945Sweongyo			if (error) {
2719203945Sweongyo				device_printf(sc->sc_dev,
2720203945Sweongyo				     "can't create RX buf DMA map\n");
2721203945Sweongyo				goto fail1;
2722203945Sweongyo			}
2723203945Sweongyo		}
2724203945Sweongyo	} else {
2725203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2726203945Sweongyo		    &dr->dr_spare_dmap);
2727203945Sweongyo		if (error) {
2728203945Sweongyo			device_printf(sc->sc_dev,
2729203945Sweongyo			    "can't create RX buf DMA map\n");
2730203945Sweongyo			goto out;		/* XXX wrong! */
2731203945Sweongyo		}
2732203945Sweongyo
2733203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
2734203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2735203945Sweongyo
2736203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2737203945Sweongyo			    &mt->mt_dmap);
2738203945Sweongyo			if (error) {
2739203945Sweongyo				device_printf(sc->sc_dev,
2740203945Sweongyo				    "can't create RX buf DMA map\n");
2741203945Sweongyo				goto out;	/* XXX wrong! */
2742203945Sweongyo			}
2743203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
2744203945Sweongyo			if (error) {
2745203945Sweongyo				device_printf(sc->sc_dev,
2746203945Sweongyo				    "failed to allocate RX buf\n");
2747203945Sweongyo				goto out;	/* XXX wrong! */
2748203945Sweongyo			}
2749203945Sweongyo		}
2750203945Sweongyo
2751203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
2752203945Sweongyo		    BUS_DMASYNC_PREWRITE);
2753203945Sweongyo
2754203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
2755203945Sweongyo	}
2756203945Sweongyo
2757203945Sweongyo      out:
2758203945Sweongyo	return (dr);
2759203945Sweongyo
2760203945Sweongyofail2:
2761203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
2762203945Sweongyofail1:
2763203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
2764203945Sweongyofail0:
2765203945Sweongyo	free(dr, M_DEVBUF);
2766203945Sweongyo	return (NULL);
2767203945Sweongyo}
2768203945Sweongyo
2769203945Sweongyostatic void
2770203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
2771203945Sweongyo{
2772203945Sweongyo
2773203945Sweongyo	if (dr == NULL)
2774203945Sweongyo		return;
2775203945Sweongyo
2776203945Sweongyo	bwn_dma_free_descbufs(*dr);
2777203945Sweongyo	bwn_dma_free_ringmemory(*dr);
2778203945Sweongyo
2779203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
2780203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
2781203945Sweongyo	free(*dr, M_DEVBUF);
2782203945Sweongyo
2783203945Sweongyo	*dr = NULL;
2784203945Sweongyo}
2785203945Sweongyo
2786203945Sweongyostatic void
2787203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
2788203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2789203945Sweongyo{
2790203945Sweongyo	struct bwn_dmadesc32 *desc;
2791203945Sweongyo
2792203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2793203945Sweongyo	desc = dr->dr_ring_descbase;
2794203945Sweongyo	desc = &(desc[slot]);
2795203945Sweongyo
2796203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2797203945Sweongyo}
2798203945Sweongyo
2799203945Sweongyostatic void
2800203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
2801203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2802203945Sweongyo    int start, int end, int irq)
2803203945Sweongyo{
2804203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
2805204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2806203945Sweongyo	uint32_t addr, addrext, ctl;
2807203945Sweongyo	int slot;
2808203945Sweongyo
2809203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
2810203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2811203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2812203945Sweongyo
2813203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
2814203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
2815204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
2816203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
2817203945Sweongyo	if (slot == dr->dr_numslots - 1)
2818203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
2819203945Sweongyo	if (start)
2820203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
2821203945Sweongyo	if (end)
2822203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
2823203945Sweongyo	if (irq)
2824203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
2825203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
2826203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
2827203945Sweongyo
2828203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
2829203945Sweongyo	desc->dma.dma32.address = htole32(addr);
2830203945Sweongyo}
2831203945Sweongyo
2832203945Sweongyostatic void
2833203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
2834203945Sweongyo{
2835203945Sweongyo
2836203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
2837203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
2838203945Sweongyo}
2839203945Sweongyo
2840203945Sweongyostatic void
2841203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
2842203945Sweongyo{
2843203945Sweongyo
2844203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2845203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
2846203945Sweongyo}
2847203945Sweongyo
2848203945Sweongyostatic void
2849203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
2850203945Sweongyo{
2851203945Sweongyo
2852203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2853203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
2854203945Sweongyo}
2855203945Sweongyo
2856203945Sweongyostatic int
2857203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
2858203945Sweongyo{
2859203945Sweongyo	uint32_t val;
2860203945Sweongyo
2861203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
2862203945Sweongyo	val &= BWN_DMA32_RXDPTR;
2863203945Sweongyo
2864203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
2865203945Sweongyo}
2866203945Sweongyo
2867203945Sweongyostatic void
2868203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
2869203945Sweongyo{
2870203945Sweongyo
2871203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
2872203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
2873203945Sweongyo}
2874203945Sweongyo
2875203945Sweongyostatic void
2876203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
2877203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2878203945Sweongyo{
2879203945Sweongyo	struct bwn_dmadesc64 *desc;
2880203945Sweongyo
2881203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2882203945Sweongyo	desc = dr->dr_ring_descbase;
2883203945Sweongyo	desc = &(desc[slot]);
2884203945Sweongyo
2885203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2886203945Sweongyo}
2887203945Sweongyo
2888203945Sweongyostatic void
2889203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
2890203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2891203945Sweongyo    int start, int end, int irq)
2892203945Sweongyo{
2893203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
2894204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2895203945Sweongyo	int slot;
2896203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
2897203945Sweongyo	uint32_t addrlo, addrhi;
2898203945Sweongyo	uint32_t addrext;
2899203945Sweongyo
2900203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
2901203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2902203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2903203945Sweongyo
2904203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
2905203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
2906203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
2907203945Sweongyo	    30;
2908204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
2909203945Sweongyo	if (slot == dr->dr_numslots - 1)
2910203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
2911203945Sweongyo	if (start)
2912203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
2913203945Sweongyo	if (end)
2914203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
2915203945Sweongyo	if (irq)
2916203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
2917203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
2918203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
2919203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
2920203945Sweongyo
2921203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
2922203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
2923203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
2924203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
2925203945Sweongyo}
2926203945Sweongyo
2927203945Sweongyostatic void
2928203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
2929203945Sweongyo{
2930203945Sweongyo
2931203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
2932203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
2933203945Sweongyo}
2934203945Sweongyo
2935203945Sweongyostatic void
2936203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
2937203945Sweongyo{
2938203945Sweongyo
2939203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
2940203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
2941203945Sweongyo}
2942203945Sweongyo
2943203945Sweongyostatic void
2944203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
2945203945Sweongyo{
2946203945Sweongyo
2947203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
2948203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
2949203945Sweongyo}
2950203945Sweongyo
2951203945Sweongyostatic int
2952203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
2953203945Sweongyo{
2954203945Sweongyo	uint32_t val;
2955203945Sweongyo
2956203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
2957203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
2958203945Sweongyo
2959203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
2960203945Sweongyo}
2961203945Sweongyo
2962203945Sweongyostatic void
2963203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
2964203945Sweongyo{
2965203945Sweongyo
2966203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
2967203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
2968203945Sweongyo}
2969203945Sweongyo
2970203945Sweongyostatic int
2971203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
2972203945Sweongyo{
2973203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
2974203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2975203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2976203945Sweongyo	int error;
2977203945Sweongyo
2978203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
2979203945Sweongyo			    BWN_ALIGN, 0,
2980203945Sweongyo			    BUS_SPACE_MAXADDR,
2981203945Sweongyo			    BUS_SPACE_MAXADDR,
2982203945Sweongyo			    NULL, NULL,
2983203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
2984203945Sweongyo			    1,
2985203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
2986203945Sweongyo			    0,
2987203945Sweongyo			    NULL, NULL,
2988203945Sweongyo			    &dr->dr_ring_dtag);
2989203945Sweongyo	if (error) {
2990203945Sweongyo		device_printf(sc->sc_dev,
2991203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
2992203945Sweongyo		return (-1);
2993203945Sweongyo	}
2994203945Sweongyo
2995203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
2996203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
2997203945Sweongyo	    &dr->dr_ring_dmap);
2998203945Sweongyo	if (error) {
2999203945Sweongyo		device_printf(sc->sc_dev,
3000203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
3001203945Sweongyo		return (-1);
3002203945Sweongyo	}
3003203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
3004203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
3005203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
3006203945Sweongyo	if (error) {
3007203945Sweongyo		device_printf(sc->sc_dev,
3008203945Sweongyo		    "can't load DMA mem: TODO free\n");
3009203945Sweongyo		return (-1);
3010203945Sweongyo	}
3011203945Sweongyo
3012203945Sweongyo	return (0);
3013203945Sweongyo}
3014203945Sweongyo
3015203945Sweongyostatic void
3016203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
3017203945Sweongyo{
3018204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3019203945Sweongyo	uint64_t ring64;
3020203945Sweongyo	uint32_t addrext, ring32, value;
3021204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
3022203945Sweongyo
3023203945Sweongyo	if (dr->dr_tx) {
3024203945Sweongyo		dr->dr_curslot = -1;
3025203945Sweongyo
3026203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3027203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
3028203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
3029203945Sweongyo			    >> 30;
3030203945Sweongyo			value = BWN_DMA64_TXENABLE;
3031203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
3032203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
3033203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
3034203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
3035203945Sweongyo			    (ring64 & 0xffffffff));
3036203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
3037203945Sweongyo			    ((ring64 >> 32) &
3038203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
3039203945Sweongyo		} else {
3040203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
3041203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
3042203945Sweongyo			value = BWN_DMA32_TXENABLE;
3043203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
3044203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
3045203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
3046203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
3047203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
3048203945Sweongyo		}
3049203945Sweongyo		return;
3050203945Sweongyo	}
3051203945Sweongyo
3052203945Sweongyo	/*
3053203945Sweongyo	 * set for RX
3054203945Sweongyo	 */
3055203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
3056203945Sweongyo
3057203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
3058203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
3059203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
3060203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
3061203945Sweongyo		value |= BWN_DMA64_RXENABLE;
3062203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
3063203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
3064203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
3065203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
3066203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
3067203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
3068203945Sweongyo		    | (trans << 1));
3069203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
3070203945Sweongyo		    sizeof(struct bwn_dmadesc64));
3071203945Sweongyo	} else {
3072203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
3073203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
3074203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
3075203945Sweongyo		value |= BWN_DMA32_RXENABLE;
3076203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
3077203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
3078203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
3079203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
3080203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
3081203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
3082203945Sweongyo		    sizeof(struct bwn_dmadesc32));
3083203945Sweongyo	}
3084203945Sweongyo}
3085203945Sweongyo
3086203945Sweongyostatic void
3087203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
3088203945Sweongyo{
3089203945Sweongyo
3090203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
3091203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
3092203945Sweongyo	    dr->dr_ring_dmap);
3093203945Sweongyo}
3094203945Sweongyo
3095203945Sweongyostatic void
3096203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
3097203945Sweongyo{
3098203945Sweongyo
3099203945Sweongyo	if (dr->dr_tx) {
3100203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3101203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3102203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
3103203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
3104203945Sweongyo		} else
3105203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
3106203945Sweongyo	} else {
3107203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3108203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3109203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
3110203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
3111203945Sweongyo		} else
3112203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
3113203945Sweongyo	}
3114203945Sweongyo}
3115203945Sweongyo
3116203945Sweongyostatic void
3117203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
3118203945Sweongyo{
3119203945Sweongyo	struct bwn_dmadesc_generic *desc;
3120203945Sweongyo	struct bwn_dmadesc_meta *meta;
3121203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
3122203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3123203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3124203945Sweongyo	int i;
3125203945Sweongyo
3126203945Sweongyo	if (!dr->dr_usedslot)
3127203945Sweongyo		return;
3128203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
3129203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
3130203945Sweongyo
3131203945Sweongyo		if (meta->mt_m == NULL) {
3132203945Sweongyo			if (!dr->dr_tx)
3133203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
3134203945Sweongyo				    __func__);
3135203945Sweongyo			continue;
3136203945Sweongyo		}
3137203945Sweongyo		if (dr->dr_tx) {
3138203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
3139203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
3140203945Sweongyo				    meta->mt_dmap);
3141203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
3142203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
3143203945Sweongyo				    meta->mt_dmap);
3144203945Sweongyo		} else
3145203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
3146203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
3147203945Sweongyo	}
3148203945Sweongyo}
3149203945Sweongyo
3150203945Sweongyostatic int
3151203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
3152203945Sweongyo    int type)
3153203945Sweongyo{
3154203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3155203945Sweongyo	uint32_t value;
3156203945Sweongyo	int i;
3157203945Sweongyo	uint16_t offset;
3158203945Sweongyo
3159203945Sweongyo	for (i = 0; i < 10; i++) {
3160203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3161203945Sweongyo		    BWN_DMA32_TXSTATUS;
3162203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3163203945Sweongyo		if (type == BWN_DMA_64BIT) {
3164203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3165203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
3166203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
3167203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
3168203945Sweongyo				break;
3169203945Sweongyo		} else {
3170203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3171203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
3172203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
3173203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
3174203945Sweongyo				break;
3175203945Sweongyo		}
3176203945Sweongyo		DELAY(1000);
3177203945Sweongyo	}
3178203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
3179203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3180203945Sweongyo	for (i = 0; i < 10; i++) {
3181203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3182203945Sweongyo						   BWN_DMA32_TXSTATUS;
3183203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3184203945Sweongyo		if (type == BWN_DMA_64BIT) {
3185203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3186203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
3187203945Sweongyo				i = -1;
3188203945Sweongyo				break;
3189203945Sweongyo			}
3190203945Sweongyo		} else {
3191203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3192203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
3193203945Sweongyo				i = -1;
3194203945Sweongyo				break;
3195203945Sweongyo			}
3196203945Sweongyo		}
3197203945Sweongyo		DELAY(1000);
3198203945Sweongyo	}
3199203945Sweongyo	if (i != -1) {
3200203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3201203945Sweongyo		return (ENODEV);
3202203945Sweongyo	}
3203203945Sweongyo	DELAY(1000);
3204203945Sweongyo
3205203945Sweongyo	return (0);
3206203945Sweongyo}
3207203945Sweongyo
3208203945Sweongyostatic int
3209203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
3210203945Sweongyo    int type)
3211203945Sweongyo{
3212203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3213203945Sweongyo	uint32_t value;
3214203945Sweongyo	int i;
3215203945Sweongyo	uint16_t offset;
3216203945Sweongyo
3217203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
3218203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3219203945Sweongyo	for (i = 0; i < 10; i++) {
3220203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
3221203945Sweongyo		    BWN_DMA32_RXSTATUS;
3222203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3223203945Sweongyo		if (type == BWN_DMA_64BIT) {
3224203945Sweongyo			value &= BWN_DMA64_RXSTAT;
3225203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
3226203945Sweongyo				i = -1;
3227203945Sweongyo				break;
3228203945Sweongyo			}
3229203945Sweongyo		} else {
3230203945Sweongyo			value &= BWN_DMA32_RXSTATE;
3231203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
3232203945Sweongyo				i = -1;
3233203945Sweongyo				break;
3234203945Sweongyo			}
3235203945Sweongyo		}
3236203945Sweongyo		DELAY(1000);
3237203945Sweongyo	}
3238203945Sweongyo	if (i != -1) {
3239203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3240203945Sweongyo		return (ENODEV);
3241203945Sweongyo	}
3242203945Sweongyo
3243203945Sweongyo	return (0);
3244203945Sweongyo}
3245203945Sweongyo
3246203945Sweongyostatic void
3247203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
3248203945Sweongyo    struct bwn_dmadesc_meta *meta)
3249203945Sweongyo{
3250203945Sweongyo
3251203945Sweongyo	if (meta->mt_m != NULL) {
3252203945Sweongyo		m_freem(meta->mt_m);
3253203945Sweongyo		meta->mt_m = NULL;
3254203945Sweongyo	}
3255203945Sweongyo	if (meta->mt_ni != NULL) {
3256203945Sweongyo		ieee80211_free_node(meta->mt_ni);
3257203945Sweongyo		meta->mt_ni = NULL;
3258203945Sweongyo	}
3259203945Sweongyo}
3260203945Sweongyo
3261203945Sweongyostatic void
3262203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3263203945Sweongyo{
3264203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
3265203945Sweongyo	unsigned char *frame;
3266203945Sweongyo
3267203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
3268203945Sweongyo	rxhdr->frame_len = 0;
3269203945Sweongyo
3270203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
3271203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
3272203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3273203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
3274203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
3275203945Sweongyo}
3276203945Sweongyo
3277203945Sweongyostatic uint8_t
3278203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3279203945Sweongyo{
3280203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
3281203945Sweongyo
3282203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
3283203945Sweongyo	    == 0xff);
3284203945Sweongyo}
3285203945Sweongyo
3286203945Sweongyostatic void
3287203945Sweongyobwn_wme_init(struct bwn_mac *mac)
3288203945Sweongyo{
3289203945Sweongyo
3290203945Sweongyo	bwn_wme_load(mac);
3291203945Sweongyo
3292203945Sweongyo	/* enable WME support. */
3293203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
3294203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
3295203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
3296203945Sweongyo}
3297203945Sweongyo
3298203945Sweongyostatic void
3299203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
3300203945Sweongyo{
3301203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3302287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3303203945Sweongyo	uint16_t delay;	/* microsec */
3304203945Sweongyo
3305203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
3306203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
3307203945Sweongyo		delay = 500;
3308203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
3309203945Sweongyo		delay = max(delay, (uint16_t)2400);
3310203945Sweongyo
3311203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
3312203945Sweongyo}
3313203945Sweongyo
3314203945Sweongyostatic void
3315203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
3316203945Sweongyo{
3317204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3318203945Sweongyo	uint64_t hf;
3319203945Sweongyo
3320203945Sweongyo	if (bwn_bluetooth == 0)
3321203945Sweongyo		return;
3322204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
3323203945Sweongyo		return;
3324203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
3325203945Sweongyo		return;
3326203945Sweongyo
3327203945Sweongyo	hf = bwn_hf_read(mac);
3328204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
3329203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
3330203945Sweongyo	else
3331203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
3332203945Sweongyo	bwn_hf_write(mac, hf);
3333203945Sweongyo}
3334203945Sweongyo
3335203945Sweongyostatic void
3336203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
3337203945Sweongyo{
3338203945Sweongyo
3339203945Sweongyo	bwn_mac_write_bssid(mac);
3340287197Sglebius	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF,
3341287197Sglebius	    mac->mac_sc->sc_ic.ic_macaddr);
3342203945Sweongyo}
3343203945Sweongyo
3344203945Sweongyostatic void
3345203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
3346203945Sweongyo{
3347203945Sweongyo	int i;
3348203945Sweongyo
3349203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
3350203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
3351203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3352203945Sweongyo
3353203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
3354203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
3355203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
3356203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
3357203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
3358203945Sweongyo		}
3359203945Sweongyo		mac->mac_key[i].keyconf = NULL;
3360203945Sweongyo	}
3361203945Sweongyo}
3362203945Sweongyo
3363203945Sweongyostatic void
3364203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
3365203945Sweongyo{
3366204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3367203945Sweongyo
3368204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
3369203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
3370203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3371203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
3372203945Sweongyo	mac->mac_ktp *= 2;
3373204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
3374204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
3375203945Sweongyo	bwn_clear_keys(mac);
3376203945Sweongyo}
3377203945Sweongyo
3378203945Sweongyostatic void
3379203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
3380203945Sweongyo{
3381204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3382203945Sweongyo
3383203945Sweongyo	bwn_phy_exit(mac);
3384204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
3385203945Sweongyo}
3386203945Sweongyo
3387203945Sweongyostatic int
3388203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
3389203945Sweongyo{
3390203945Sweongyo	int error;
3391203945Sweongyo
3392203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
3393203945Sweongyo	if (error == 0)
3394203945Sweongyo		return (0);
3395203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
3396203945Sweongyo	if (error == 0)
3397203945Sweongyo		return (0);
3398203945Sweongyo	return (error);
3399203945Sweongyo}
3400203945Sweongyo
3401203945Sweongyostatic int
3402203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
3403203945Sweongyo{
3404204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3405204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
3406203945Sweongyo
3407203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3408203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
3409203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
3410203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
3411203945Sweongyo
3412204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
3413203945Sweongyo		mask |= 0x0060;
3414203945Sweongyo		set |= 0x0060;
3415203945Sweongyo	}
3416204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
3417203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
3418203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
3419203945Sweongyo		mask |= 0x0200;
3420203945Sweongyo		set |= 0x0200;
3421203945Sweongyo	}
3422204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
3423203945Sweongyo		mask |= 0x0010;
3424204922Sweongyo
3425204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
3426204922Sweongyo	if (value == -1)
3427203945Sweongyo		return (0);
3428204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
3429203945Sweongyo
3430203945Sweongyo	return (0);
3431203945Sweongyo}
3432203945Sweongyo
3433203945Sweongyostatic int
3434203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
3435203945Sweongyo{
3436203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
3437203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
3438203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
3439203945Sweongyo	const struct bwn_fwhdr *hdr;
3440203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3441203945Sweongyo	int error;
3442203945Sweongyo
3443203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
3444203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
3445203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
3446203945Sweongyo	if (error)
3447203945Sweongyo		return (error);
3448203945Sweongyo	if (fw->initvals_band.fw) {
3449203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
3450203945Sweongyo		error = bwn_fwinitvals_write(mac,
3451203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
3452203945Sweongyo		    be32toh(hdr->size),
3453203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
3454203945Sweongyo	}
3455203945Sweongyo	return (error);
3456203945Sweongyo#undef GETFWOFFSET
3457203945Sweongyo}
3458203945Sweongyo
3459203945Sweongyostatic int
3460203945Sweongyobwn_phy_init(struct bwn_mac *mac)
3461203945Sweongyo{
3462203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3463203945Sweongyo	int error;
3464203945Sweongyo
3465203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
3466203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
3467203945Sweongyo	error = mac->mac_phy.init(mac);
3468203945Sweongyo	if (error) {
3469203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
3470203945Sweongyo		goto fail0;
3471203945Sweongyo	}
3472203945Sweongyo	error = bwn_switch_channel(mac,
3473203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
3474203945Sweongyo	if (error) {
3475203945Sweongyo		device_printf(sc->sc_dev,
3476203945Sweongyo		    "failed to switch default channel\n");
3477203945Sweongyo		goto fail1;
3478203945Sweongyo	}
3479203945Sweongyo	return (0);
3480203945Sweongyofail1:
3481203945Sweongyo	if (mac->mac_phy.exit)
3482203945Sweongyo		mac->mac_phy.exit(mac);
3483203945Sweongyofail0:
3484203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
3485203945Sweongyo
3486203945Sweongyo	return (error);
3487203945Sweongyo}
3488203945Sweongyo
3489203945Sweongyostatic void
3490203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
3491203945Sweongyo{
3492203945Sweongyo	uint16_t ant;
3493203945Sweongyo	uint16_t tmp;
3494203945Sweongyo
3495203945Sweongyo	ant = bwn_ant2phy(antenna);
3496203945Sweongyo
3497203945Sweongyo	/* For ACK/CTS */
3498203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
3499203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3500203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
3501203945Sweongyo	/* For Probe Resposes */
3502203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
3503203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3504203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
3505203945Sweongyo}
3506203945Sweongyo
3507203945Sweongyostatic void
3508203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
3509203945Sweongyo{
3510203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3511287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3512203945Sweongyo	uint32_t ctl;
3513203945Sweongyo	uint16_t cfp_pretbtt;
3514203945Sweongyo
3515203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
3516203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
3517203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
3518203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
3519203945Sweongyo	ctl |= BWN_MACCTL_STA;
3520203945Sweongyo
3521203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
3522203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
3523203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
3524203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
3525203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
3526203945Sweongyo	ctl |= sc->sc_filters;
3527203945Sweongyo
3528204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
3529203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
3530203945Sweongyo
3531203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
3532203945Sweongyo
3533203945Sweongyo	cfp_pretbtt = 2;
3534203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
3535204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
3536204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
3537203945Sweongyo			cfp_pretbtt = 100;
3538203945Sweongyo		else
3539203945Sweongyo			cfp_pretbtt = 50;
3540203945Sweongyo	}
3541203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
3542203945Sweongyo}
3543203945Sweongyo
3544203945Sweongyostatic int
3545203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
3546203945Sweongyo{
3547203945Sweongyo	uint32_t tmp;
3548203945Sweongyo	uint16_t base;
3549203945Sweongyo
3550203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3551203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3552203945Sweongyo		return (BWN_DMA_64BIT);
3553203945Sweongyo	base = bwn_dma_base(0, 0);
3554203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3555203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3556203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3557203945Sweongyo		return (BWN_DMA_32BIT);
3558203945Sweongyo
3559203945Sweongyo	return (BWN_DMA_30BIT);
3560203945Sweongyo}
3561203945Sweongyo
3562203945Sweongyostatic void
3563203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
3564203945Sweongyo{
3565203945Sweongyo	if (!error) {
3566203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
3567203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
3568203945Sweongyo	}
3569203945Sweongyo}
3570203945Sweongyo
3571298948Sadrianvoid
3572298952Sadrianbwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
3573298952Sadrian{
3574298952Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3575298952Sadrian	struct bwn_softc *sc = mac->mac_sc;
3576298952Sadrian	unsigned int i, max_loop;
3577298952Sadrian	uint16_t value;
3578298952Sadrian	uint32_t buffer[5] = {
3579298952Sadrian		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
3580298952Sadrian	};
3581298952Sadrian
3582298952Sadrian	if (ofdm) {
3583298952Sadrian		max_loop = 0x1e;
3584298952Sadrian		buffer[0] = 0x000201cc;
3585298952Sadrian	} else {
3586298952Sadrian		max_loop = 0xfa;
3587298952Sadrian		buffer[0] = 0x000b846e;
3588298952Sadrian	}
3589298952Sadrian
3590298952Sadrian	BWN_ASSERT_LOCKED(mac->mac_sc);
3591298952Sadrian
3592298952Sadrian	for (i = 0; i < 5; i++)
3593298952Sadrian		bwn_ram_write(mac, i * 4, buffer[i]);
3594298952Sadrian
3595298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0000);
3596298952Sadrian	BWN_WRITE_2(mac, 0x07c0,
3597298952Sadrian	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
3598298954Sadrian
3599298954Sadrian	value = (ofdm ? 0x41 : 0x40);
3600298952Sadrian	BWN_WRITE_2(mac, 0x050c, value);
3601298954Sadrian
3602298954Sadrian	if (phy->type == BWN_PHYTYPE_N || phy->type == BWN_PHYTYPE_LP ||
3603298954Sadrian	    phy->type == BWN_PHYTYPE_LCN)
3604298952Sadrian		BWN_WRITE_2(mac, 0x0514, 0x1a02);
3605298952Sadrian	BWN_WRITE_2(mac, 0x0508, 0x0000);
3606298952Sadrian	BWN_WRITE_2(mac, 0x050a, 0x0000);
3607298952Sadrian	BWN_WRITE_2(mac, 0x054c, 0x0000);
3608298952Sadrian	BWN_WRITE_2(mac, 0x056a, 0x0014);
3609298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0826);
3610298952Sadrian	BWN_WRITE_2(mac, 0x0500, 0x0000);
3611298954Sadrian
3612298954Sadrian	/* XXX TODO: n phy pa override? */
3613298954Sadrian
3614298954Sadrian	switch (phy->type) {
3615298954Sadrian	case BWN_PHYTYPE_N:
3616298954Sadrian	case BWN_PHYTYPE_LCN:
3617298954Sadrian		BWN_WRITE_2(mac, 0x0502, 0x00d0);
3618298954Sadrian		break;
3619298954Sadrian	case BWN_PHYTYPE_LP:
3620298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0050);
3621298954Sadrian		break;
3622298954Sadrian	default:
3623298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0030);
3624298954Sadrian		break;
3625298954Sadrian	}
3626298952Sadrian
3627298954Sadrian	/* flush */
3628298954Sadrian	BWN_READ_2(mac, 0x0502);
3629298954Sadrian
3630298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3631298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0017);
3632298952Sadrian	for (i = 0x00; i < max_loop; i++) {
3633298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3634298952Sadrian		if (value & 0x0080)
3635298952Sadrian			break;
3636298952Sadrian		DELAY(10);
3637298952Sadrian	}
3638298952Sadrian	for (i = 0x00; i < 0x0a; i++) {
3639298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3640298952Sadrian		if (value & 0x0400)
3641298952Sadrian			break;
3642298952Sadrian		DELAY(10);
3643298952Sadrian	}
3644298952Sadrian	for (i = 0x00; i < 0x19; i++) {
3645298952Sadrian		value = BWN_READ_2(mac, 0x0690);
3646298952Sadrian		if (!(value & 0x0100))
3647298952Sadrian			break;
3648298952Sadrian		DELAY(10);
3649298952Sadrian	}
3650298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3651298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0037);
3652298952Sadrian}
3653298952Sadrian
3654298952Sadrianvoid
3655203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
3656203945Sweongyo{
3657203945Sweongyo	uint32_t macctl;
3658203945Sweongyo
3659203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
3660203945Sweongyo
3661203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3662203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
3663203945Sweongyo		printf("TODO: need swap\n");
3664203945Sweongyo
3665203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
3666203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
3667203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
3668203945Sweongyo}
3669203945Sweongyo
3670298944Sadrianvoid
3671203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
3672203945Sweongyo{
3673203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3674203945Sweongyo	int i;
3675203945Sweongyo	uint32_t tmp;
3676203945Sweongyo
3677203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3678203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3679203945Sweongyo
3680203945Sweongyo	if (mac->mac_suspended == 0) {
3681203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
3682203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3683203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
3684203945Sweongyo			    & ~BWN_MACCTL_ON);
3685203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3686203945Sweongyo		for (i = 35; i; i--) {
3687203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3688203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3689203945Sweongyo				goto out;
3690203945Sweongyo			DELAY(10);
3691203945Sweongyo		}
3692203945Sweongyo		for (i = 40; i; i--) {
3693203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3694203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3695203945Sweongyo				goto out;
3696203945Sweongyo			DELAY(1000);
3697203945Sweongyo		}
3698203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
3699203945Sweongyo	}
3700203945Sweongyoout:
3701203945Sweongyo	mac->mac_suspended++;
3702203945Sweongyo}
3703203945Sweongyo
3704298944Sadrianvoid
3705203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
3706203945Sweongyo{
3707203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3708203945Sweongyo	uint16_t state;
3709203945Sweongyo
3710203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
3711203945Sweongyo	    BWN_SHARED_UCODESTAT);
3712203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
3713203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
3714203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
3715203945Sweongyo
3716203945Sweongyo	mac->mac_suspended--;
3717203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3718203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3719203945Sweongyo	if (mac->mac_suspended == 0) {
3720203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3721203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
3722203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
3723203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3724203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
3725203945Sweongyo		bwn_psctl(mac, 0);
3726203945Sweongyo	}
3727203945Sweongyo}
3728203945Sweongyo
3729298948Sadrianvoid
3730203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
3731203945Sweongyo{
3732204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3733203945Sweongyo	int i;
3734203945Sweongyo	uint16_t ucstat;
3735203945Sweongyo
3736203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
3737203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3738203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
3739203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3740203945Sweongyo
3741203945Sweongyo	/* XXX forcibly awake and hwps-off */
3742203945Sweongyo
3743203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3744203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
3745203945Sweongyo	    ~BWN_MACCTL_HWPS);
3746203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
3747204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
3748203945Sweongyo		for (i = 0; i < 100; i++) {
3749203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
3750203945Sweongyo			    BWN_SHARED_UCODESTAT);
3751203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
3752203945Sweongyo				break;
3753203945Sweongyo			DELAY(10);
3754203945Sweongyo		}
3755203945Sweongyo	}
3756203945Sweongyo}
3757203945Sweongyo
3758203945Sweongyostatic int
3759203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
3760203945Sweongyo{
3761203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3762203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3763204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
3764203945Sweongyo	const char *filename;
3765203945Sweongyo	uint32_t high;
3766203945Sweongyo	int error;
3767203945Sweongyo
3768203945Sweongyo	/* microcode */
3769299780Sadrian	filename = NULL;
3770299780Sadrian	switch (rev) {
3771299780Sadrian	case 42:
3772299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_AC)
3773299780Sadrian			filename = "ucode42";
3774299780Sadrian		break;
3775299780Sadrian	case 40:
3776299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_AC)
3777299780Sadrian			filename = "ucode40";
3778299780Sadrian		break;
3779299780Sadrian	case 33:
3780299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_LCN40)
3781299780Sadrian			filename = "ucode33_lcn40";
3782299780Sadrian		break;
3783299780Sadrian	case 30:
3784299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3785299780Sadrian			filename = "ucode30_mimo";
3786299780Sadrian		break;
3787299780Sadrian	case 29:
3788299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_HT)
3789299780Sadrian			filename = "ucode29_mimo";
3790299780Sadrian		break;
3791299780Sadrian	case 26:
3792299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_HT)
3793299780Sadrian			filename = "ucode26_mimo";
3794299780Sadrian		break;
3795299780Sadrian	case 28:
3796299780Sadrian	case 25:
3797299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3798299780Sadrian			filename = "ucode25_mimo";
3799299780Sadrian		else if (mac->mac_phy.type == BWN_PHYTYPE_LCN)
3800299780Sadrian			filename = "ucode25_lcn";
3801299780Sadrian		break;
3802299780Sadrian	case 24:
3803299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_LCN)
3804299780Sadrian			filename = "ucode24_lcn";
3805299780Sadrian		break;
3806299780Sadrian	case 23:
3807299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3808299780Sadrian			filename = "ucode16_mimo";
3809299780Sadrian		break;
3810299780Sadrian	case 16:
3811299780Sadrian	case 17:
3812299780Sadrian	case 18:
3813299780Sadrian	case 19:
3814299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3815299780Sadrian			filename = "ucode16_mimo";
3816299780Sadrian		else if (mac->mac_phy.type == BWN_PHYTYPE_LP)
3817299780Sadrian			filename = "ucode16_lp";
3818299780Sadrian		break;
3819299780Sadrian	case 15:
3820299780Sadrian		filename = "ucode15";
3821299780Sadrian		break;
3822299780Sadrian	case 14:
3823299780Sadrian		filename = "ucode14";
3824299780Sadrian		break;
3825299780Sadrian	case 13:
3826299780Sadrian		filename = "ucode13";
3827299780Sadrian		break;
3828299780Sadrian	case 12:
3829299780Sadrian	case 11:
3830299780Sadrian		filename = "ucode11";
3831299780Sadrian		break;
3832299780Sadrian	case 10:
3833299780Sadrian	case 9:
3834299780Sadrian	case 8:
3835299780Sadrian	case 7:
3836299780Sadrian	case 6:
3837299780Sadrian	case 5:
3838203945Sweongyo		filename = "ucode5";
3839299780Sadrian		break;
3840299780Sadrian	default:
3841203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
3842203945Sweongyo		bwn_release_firmware(mac);
3843203945Sweongyo		return (EOPNOTSUPP);
3844203945Sweongyo	}
3845299780Sadrian
3846299780Sadrian	device_printf(sc->sc_dev, "ucode fw: %s\n", filename);
3847203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
3848203945Sweongyo	if (error) {
3849203945Sweongyo		bwn_release_firmware(mac);
3850203945Sweongyo		return (error);
3851203945Sweongyo	}
3852203945Sweongyo
3853203945Sweongyo	/* PCM */
3854203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
3855203945Sweongyo	if (rev >= 5 && rev <= 10) {
3856203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
3857203945Sweongyo		if (error == ENOENT)
3858203945Sweongyo			fw->no_pcmfile = 1;
3859203945Sweongyo		else if (error) {
3860203945Sweongyo			bwn_release_firmware(mac);
3861203945Sweongyo			return (error);
3862203945Sweongyo		}
3863203945Sweongyo	} else if (rev < 11) {
3864203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
3865203945Sweongyo		return (EOPNOTSUPP);
3866203945Sweongyo	}
3867203945Sweongyo
3868203945Sweongyo	/* initvals */
3869204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
3870203945Sweongyo	switch (mac->mac_phy.type) {
3871203945Sweongyo	case BWN_PHYTYPE_A:
3872203945Sweongyo		if (rev < 5 || rev > 10)
3873203945Sweongyo			goto fail1;
3874203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
3875203945Sweongyo			filename = "a0g1initvals5";
3876203945Sweongyo		else
3877203945Sweongyo			filename = "a0g0initvals5";
3878203945Sweongyo		break;
3879203945Sweongyo	case BWN_PHYTYPE_G:
3880203945Sweongyo		if (rev >= 5 && rev <= 10)
3881203945Sweongyo			filename = "b0g0initvals5";
3882203945Sweongyo		else if (rev >= 13)
3883203945Sweongyo			filename = "b0g0initvals13";
3884203945Sweongyo		else
3885203945Sweongyo			goto fail1;
3886203945Sweongyo		break;
3887203945Sweongyo	case BWN_PHYTYPE_LP:
3888203945Sweongyo		if (rev == 13)
3889203945Sweongyo			filename = "lp0initvals13";
3890203945Sweongyo		else if (rev == 14)
3891203945Sweongyo			filename = "lp0initvals14";
3892203945Sweongyo		else if (rev >= 15)
3893203945Sweongyo			filename = "lp0initvals15";
3894203945Sweongyo		else
3895203945Sweongyo			goto fail1;
3896203945Sweongyo		break;
3897203945Sweongyo	case BWN_PHYTYPE_N:
3898299780Sadrian		if (rev == 30)
3899299780Sadrian			filename = "n16initvals30";
3900299780Sadrian		else if (rev == 28 || rev == 25)
3901299780Sadrian			filename = "n0initvals25";
3902299780Sadrian		else if (rev == 24)
3903299780Sadrian			filename = "n0initvals24";
3904299780Sadrian		else if (rev == 23)
3905299780Sadrian			filename = "n0initvals16";
3906299780Sadrian		else if (rev >= 16 && rev <= 18)
3907299780Sadrian			filename = "n0initvals16";
3908299780Sadrian		else if (rev >= 11 && rev <= 12)
3909203945Sweongyo			filename = "n0initvals11";
3910203945Sweongyo		else
3911203945Sweongyo			goto fail1;
3912203945Sweongyo		break;
3913203945Sweongyo	default:
3914203945Sweongyo		goto fail1;
3915203945Sweongyo	}
3916203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
3917203945Sweongyo	if (error) {
3918203945Sweongyo		bwn_release_firmware(mac);
3919203945Sweongyo		return (error);
3920203945Sweongyo	}
3921203945Sweongyo
3922203945Sweongyo	/* bandswitch initvals */
3923203945Sweongyo	switch (mac->mac_phy.type) {
3924203945Sweongyo	case BWN_PHYTYPE_A:
3925203945Sweongyo		if (rev >= 5 && rev <= 10) {
3926203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
3927203945Sweongyo				filename = "a0g1bsinitvals5";
3928203945Sweongyo			else
3929203945Sweongyo				filename = "a0g0bsinitvals5";
3930203945Sweongyo		} else if (rev >= 11)
3931203945Sweongyo			filename = NULL;
3932203945Sweongyo		else
3933203945Sweongyo			goto fail1;
3934203945Sweongyo		break;
3935203945Sweongyo	case BWN_PHYTYPE_G:
3936203945Sweongyo		if (rev >= 5 && rev <= 10)
3937203945Sweongyo			filename = "b0g0bsinitvals5";
3938203945Sweongyo		else if (rev >= 11)
3939203945Sweongyo			filename = NULL;
3940203945Sweongyo		else
3941203945Sweongyo			goto fail1;
3942203945Sweongyo		break;
3943203945Sweongyo	case BWN_PHYTYPE_LP:
3944203945Sweongyo		if (rev == 13)
3945203945Sweongyo			filename = "lp0bsinitvals13";
3946203945Sweongyo		else if (rev == 14)
3947203945Sweongyo			filename = "lp0bsinitvals14";
3948203945Sweongyo		else if (rev >= 15)
3949203945Sweongyo			filename = "lp0bsinitvals15";
3950203945Sweongyo		else
3951203945Sweongyo			goto fail1;
3952203945Sweongyo		break;
3953203945Sweongyo	case BWN_PHYTYPE_N:
3954299780Sadrian		if (rev == 30)
3955299780Sadrian			filename = "n16bsinitvals30";
3956299780Sadrian		else if (rev == 28 || rev == 25)
3957299780Sadrian			filename = "n0bsinitvals25";
3958299780Sadrian		else if (rev == 24)
3959299780Sadrian			filename = "n0bsinitvals24";
3960299780Sadrian		else if (rev == 23)
3961299780Sadrian			filename = "n0bsinitvals16";
3962299780Sadrian		else if (rev >= 16 && rev <= 18)
3963299780Sadrian			filename = "n0bsinitvals16";
3964299780Sadrian		else if (rev >= 11 && rev <= 12)
3965203945Sweongyo			filename = "n0bsinitvals11";
3966203945Sweongyo		else
3967203945Sweongyo			goto fail1;
3968203945Sweongyo		break;
3969203945Sweongyo	default:
3970299780Sadrian		device_printf(sc->sc_dev, "unknown phy (%d)\n",
3971299780Sadrian		    mac->mac_phy.type);
3972203945Sweongyo		goto fail1;
3973203945Sweongyo	}
3974203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
3975203945Sweongyo	if (error) {
3976203945Sweongyo		bwn_release_firmware(mac);
3977203945Sweongyo		return (error);
3978203945Sweongyo	}
3979203945Sweongyo	return (0);
3980203945Sweongyofail1:
3981299780Sadrian	device_printf(sc->sc_dev, "no INITVALS for rev %d, phy.type %d\n",
3982299780Sadrian	    rev, mac->mac_phy.type);
3983203945Sweongyo	bwn_release_firmware(mac);
3984203945Sweongyo	return (EOPNOTSUPP);
3985203945Sweongyo}
3986203945Sweongyo
3987203945Sweongyostatic int
3988203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
3989203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
3990203945Sweongyo{
3991203945Sweongyo	const struct bwn_fwhdr *hdr;
3992203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3993203945Sweongyo	const struct firmware *fw;
3994203945Sweongyo	char namebuf[64];
3995203945Sweongyo
3996203945Sweongyo	if (name == NULL) {
3997203945Sweongyo		bwn_do_release_fw(bfw);
3998203945Sweongyo		return (0);
3999203945Sweongyo	}
4000203945Sweongyo	if (bfw->filename != NULL) {
4001203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
4002203945Sweongyo			return (0);
4003203945Sweongyo		bwn_do_release_fw(bfw);
4004203945Sweongyo	}
4005203945Sweongyo
4006204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
4007204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
4008204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
4009203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
4010203945Sweongyo	fw = firmware_get(namebuf);
4011203945Sweongyo	if (fw == NULL) {
4012203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
4013203945Sweongyo		    namebuf);
4014203945Sweongyo		return (ENOENT);
4015203945Sweongyo	}
4016203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
4017203945Sweongyo		goto fail;
4018203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
4019203945Sweongyo	switch (hdr->type) {
4020203945Sweongyo	case BWN_FWTYPE_UCODE:
4021203945Sweongyo	case BWN_FWTYPE_PCM:
4022203945Sweongyo		if (be32toh(hdr->size) !=
4023203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
4024203945Sweongyo			goto fail;
4025203945Sweongyo		/* FALLTHROUGH */
4026203945Sweongyo	case BWN_FWTYPE_IV:
4027203945Sweongyo		if (hdr->ver != 1)
4028203945Sweongyo			goto fail;
4029203945Sweongyo		break;
4030203945Sweongyo	default:
4031203945Sweongyo		goto fail;
4032203945Sweongyo	}
4033203945Sweongyo	bfw->filename = name;
4034203945Sweongyo	bfw->fw = fw;
4035203945Sweongyo	bfw->type = type;
4036203945Sweongyo	return (0);
4037203945Sweongyofail:
4038203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
4039203945Sweongyo	if (fw != NULL)
4040203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
4041203945Sweongyo	return (EPROTO);
4042203945Sweongyo}
4043203945Sweongyo
4044203945Sweongyostatic void
4045203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
4046203945Sweongyo{
4047203945Sweongyo
4048203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
4049203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
4050203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
4051203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
4052203945Sweongyo}
4053203945Sweongyo
4054203945Sweongyostatic void
4055203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
4056203945Sweongyo{
4057203945Sweongyo
4058203945Sweongyo	if (bfw->fw != NULL)
4059203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
4060203945Sweongyo	bfw->fw = NULL;
4061203945Sweongyo	bfw->filename = NULL;
4062203945Sweongyo}
4063203945Sweongyo
4064203945Sweongyostatic int
4065203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
4066203945Sweongyo{
4067203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
4068203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
4069203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
4070203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
4071203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4072203945Sweongyo	const uint32_t *data;
4073203945Sweongyo	unsigned int i;
4074203945Sweongyo	uint32_t ctl;
4075203945Sweongyo	uint16_t date, fwcaps, time;
4076203945Sweongyo	int error = 0;
4077203945Sweongyo
4078203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4079203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
4080203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
4081203945Sweongyo	    __LINE__));
4082203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4083203945Sweongyo	for (i = 0; i < 64; i++)
4084203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
4085203945Sweongyo	for (i = 0; i < 4096; i += 2)
4086203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
4087203945Sweongyo
4088203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
4089203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
4090203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
4091203945Sweongyo	     i++) {
4092203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
4093203945Sweongyo		DELAY(10);
4094203945Sweongyo	}
4095203945Sweongyo
4096203945Sweongyo	if (mac->mac_fw.pcm.fw) {
4097203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
4098203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
4099203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
4100203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
4101203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
4102203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
4103203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
4104203945Sweongyo			DELAY(10);
4105203945Sweongyo		}
4106203945Sweongyo	}
4107203945Sweongyo
4108203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
4109203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4110203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
4111203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
4112203945Sweongyo
4113203945Sweongyo	for (i = 0; i < 21; i++) {
4114203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
4115203945Sweongyo			break;
4116203945Sweongyo		if (i >= 20) {
4117203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
4118203945Sweongyo			error = ENXIO;
4119203945Sweongyo			goto error;
4120203945Sweongyo		}
4121203945Sweongyo		DELAY(50000);
4122203945Sweongyo	}
4123203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
4124203945Sweongyo
4125203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
4126203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
4127203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
4128203945Sweongyo		error = EOPNOTSUPP;
4129203945Sweongyo		goto error;
4130203945Sweongyo	}
4131299110Sadrian
4132299110Sadrian	/*
4133299110Sadrian	 * Determine firmware header version; needed for TX/RX packet
4134299110Sadrian	 * handling.
4135299110Sadrian	 */
4136299110Sadrian	if (mac->mac_fw.rev >= 598)
4137299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_598;
4138299110Sadrian	else if (mac->mac_fw.rev >= 410)
4139299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_410;
4140299110Sadrian	else
4141299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_351;
4142299110Sadrian
4143299110Sadrian	/*
4144299110Sadrian	 * We don't support rev 598 or later; that requires
4145299110Sadrian	 * another round of changes to the TX/RX descriptor
4146299110Sadrian	 * and status layout.
4147299110Sadrian	 *
4148299110Sadrian	 * So, complain this is the case and exit out, rather
4149299110Sadrian	 * than attaching and then failing.
4150299110Sadrian	 */
4151299110Sadrian	if (mac->mac_fw.fw_hdr_format == BWN_FW_HDR_598) {
4152299110Sadrian		device_printf(sc->sc_dev,
4153299110Sadrian		    "firmware is too new (>=598); not supported\n");
4154299110Sadrian		error = EOPNOTSUPP;
4155299110Sadrian		goto error;
4156299110Sadrian	}
4157299110Sadrian
4158203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
4159203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
4160203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
4161203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
4162203945Sweongyo	if (bwn_wme != 0)
4163203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
4164203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
4165203945Sweongyo
4166203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
4167203945Sweongyo	if (mac->mac_fw.opensource == 0) {
4168203945Sweongyo		device_printf(sc->sc_dev,
4169203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
4170203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
4171203945Sweongyo		if (mac->mac_fw.no_pcmfile)
4172203945Sweongyo			device_printf(sc->sc_dev,
4173203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
4174203945Sweongyo	} else {
4175203945Sweongyo		mac->mac_fw.patch = time;
4176203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
4177203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
4178203945Sweongyo			device_printf(sc->sc_dev,
4179203945Sweongyo			    "disabling HW crypto acceleration\n");
4180203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
4181203945Sweongyo		}
4182203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
4183203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
4184203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
4185203945Sweongyo		}
4186203945Sweongyo	}
4187203945Sweongyo
4188203945Sweongyo	if (BWN_ISOLDFMT(mac))
4189203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
4190203945Sweongyo
4191203945Sweongyo	return (0);
4192203945Sweongyo
4193203945Sweongyoerror:
4194203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4195203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
4196203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
4197203945Sweongyo
4198203945Sweongyo	return (error);
4199203945Sweongyo#undef GETFWSIZE
4200203945Sweongyo#undef GETFWOFFSET
4201203945Sweongyo}
4202203945Sweongyo
4203203945Sweongyo/* OpenFirmware only */
4204203945Sweongyostatic uint16_t
4205203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
4206203945Sweongyo{
4207203945Sweongyo
4208203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
4209203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4210203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
4211203945Sweongyo}
4212203945Sweongyo
4213203945Sweongyostatic int
4214203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
4215203945Sweongyo    size_t count, size_t array_size)
4216203945Sweongyo{
4217203945Sweongyo#define	GET_NEXTIV16(iv)						\
4218203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4219203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
4220203945Sweongyo#define	GET_NEXTIV32(iv)						\
4221203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4222203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
4223203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4224203945Sweongyo	const struct bwn_fwinitvals *iv;
4225203945Sweongyo	uint16_t offset;
4226203945Sweongyo	size_t i;
4227203945Sweongyo	uint8_t bit32;
4228203945Sweongyo
4229203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
4230203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4231203945Sweongyo	iv = ivals;
4232203945Sweongyo	for (i = 0; i < count; i++) {
4233203945Sweongyo		if (array_size < sizeof(iv->offset_size))
4234203945Sweongyo			goto fail;
4235203945Sweongyo		array_size -= sizeof(iv->offset_size);
4236203945Sweongyo		offset = be16toh(iv->offset_size);
4237203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
4238203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
4239203945Sweongyo		if (offset >= 0x1000)
4240203945Sweongyo			goto fail;
4241203945Sweongyo		if (bit32) {
4242203945Sweongyo			if (array_size < sizeof(iv->data.d32))
4243203945Sweongyo				goto fail;
4244203945Sweongyo			array_size -= sizeof(iv->data.d32);
4245203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
4246203945Sweongyo			iv = GET_NEXTIV32(iv);
4247203945Sweongyo		} else {
4248203945Sweongyo
4249203945Sweongyo			if (array_size < sizeof(iv->data.d16))
4250203945Sweongyo				goto fail;
4251203945Sweongyo			array_size -= sizeof(iv->data.d16);
4252203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
4253203945Sweongyo
4254203945Sweongyo			iv = GET_NEXTIV16(iv);
4255203945Sweongyo		}
4256203945Sweongyo	}
4257203945Sweongyo	if (array_size != 0)
4258203945Sweongyo		goto fail;
4259203945Sweongyo	return (0);
4260203945Sweongyofail:
4261203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
4262203945Sweongyo	return (EPROTO);
4263203945Sweongyo#undef GET_NEXTIV16
4264203945Sweongyo#undef GET_NEXTIV32
4265203945Sweongyo}
4266203945Sweongyo
4267298948Sadrianint
4268203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
4269203945Sweongyo{
4270203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
4271203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4272287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4273203945Sweongyo	uint16_t channelcookie, savedcookie;
4274203945Sweongyo	int error;
4275203945Sweongyo
4276203945Sweongyo	if (chan == 0xffff)
4277203945Sweongyo		chan = phy->get_default_chan(mac);
4278203945Sweongyo
4279203945Sweongyo	channelcookie = chan;
4280203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
4281203945Sweongyo		channelcookie |= 0x100;
4282203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
4283203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
4284203945Sweongyo	error = phy->switch_channel(mac, chan);
4285203945Sweongyo	if (error)
4286203945Sweongyo		goto fail;
4287203945Sweongyo
4288203945Sweongyo	mac->mac_phy.chan = chan;
4289203945Sweongyo	DELAY(8000);
4290203945Sweongyo	return (0);
4291203945Sweongyofail:
4292203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
4293203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
4294203945Sweongyo	return (error);
4295203945Sweongyo}
4296203945Sweongyo
4297203945Sweongyostatic uint16_t
4298203945Sweongyobwn_ant2phy(int antenna)
4299203945Sweongyo{
4300203945Sweongyo
4301203945Sweongyo	switch (antenna) {
4302203945Sweongyo	case BWN_ANT0:
4303203945Sweongyo		return (BWN_TX_PHY_ANT0);
4304203945Sweongyo	case BWN_ANT1:
4305203945Sweongyo		return (BWN_TX_PHY_ANT1);
4306203945Sweongyo	case BWN_ANT2:
4307203945Sweongyo		return (BWN_TX_PHY_ANT2);
4308203945Sweongyo	case BWN_ANT3:
4309203945Sweongyo		return (BWN_TX_PHY_ANT3);
4310203945Sweongyo	case BWN_ANTAUTO:
4311203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
4312203945Sweongyo	}
4313203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4314203945Sweongyo	return (0);
4315203945Sweongyo}
4316203945Sweongyo
4317203945Sweongyostatic void
4318203945Sweongyobwn_wme_load(struct bwn_mac *mac)
4319203945Sweongyo{
4320203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4321203945Sweongyo	int i;
4322203945Sweongyo
4323203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
4324203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4325203945Sweongyo
4326203945Sweongyo	bwn_mac_suspend(mac);
4327203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
4328203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
4329203945Sweongyo		    bwn_wme_shm_offsets[i]);
4330203945Sweongyo	bwn_mac_enable(mac);
4331203945Sweongyo}
4332203945Sweongyo
4333203945Sweongyostatic void
4334203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
4335203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
4336203945Sweongyo{
4337203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
4338203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4339203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
4340203945Sweongyo	int slot, tmp;
4341203945Sweongyo	unsigned int i;
4342203945Sweongyo
4343203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
4344203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4345203945Sweongyo
4346203945Sweongyo	memset(&params, 0, sizeof(params));
4347203945Sweongyo
4348203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
4349203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
4350203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
4351203945Sweongyo
4352203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
4353203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4354203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
4355203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4356203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
4357203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
4358203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
4359203945Sweongyo
4360203945Sweongyo	for (i = 0; i < N(params); i++) {
4361203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
4362203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
4363203945Sweongyo			    shm_offset + (i * 2));
4364203945Sweongyo			tmp |= 0x100;
4365203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4366203945Sweongyo			    tmp);
4367203945Sweongyo		} else {
4368203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4369203945Sweongyo			    params[i]);
4370203945Sweongyo		}
4371203945Sweongyo	}
4372203945Sweongyo}
4373203945Sweongyo
4374203945Sweongyostatic void
4375203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
4376203945Sweongyo{
4377203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4378203945Sweongyo	uint32_t tmp;
4379203945Sweongyo	int i;
4380203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
4381203945Sweongyo
4382203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
4383287197Sglebius	memcpy(mac_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
4384203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
4385203945Sweongyo	    IEEE80211_ADDR_LEN);
4386203945Sweongyo
4387203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
4388203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
4389203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
4390203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
4391203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
4392203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
4393203945Sweongyo	}
4394203945Sweongyo}
4395203945Sweongyo
4396203945Sweongyostatic void
4397203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
4398203945Sweongyo    const uint8_t *macaddr)
4399203945Sweongyo{
4400203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
4401203945Sweongyo	uint16_t data;
4402203945Sweongyo
4403203945Sweongyo	if (!mac)
4404203945Sweongyo		macaddr = zero;
4405203945Sweongyo
4406203945Sweongyo	offset |= 0x0020;
4407203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
4408203945Sweongyo
4409203945Sweongyo	data = macaddr[0];
4410203945Sweongyo	data |= macaddr[1] << 8;
4411203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4412203945Sweongyo	data = macaddr[2];
4413203945Sweongyo	data |= macaddr[3] << 8;
4414203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4415203945Sweongyo	data = macaddr[4];
4416203945Sweongyo	data |= macaddr[5] << 8;
4417203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4418203945Sweongyo}
4419203945Sweongyo
4420203945Sweongyostatic void
4421203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4422203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
4423203945Sweongyo{
4424203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
4425203945Sweongyo	uint8_t per_sta_keys_start = 8;
4426203945Sweongyo
4427203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4428203945Sweongyo		per_sta_keys_start = 4;
4429203945Sweongyo
4430203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
4431203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4432203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
4433203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4434203945Sweongyo
4435203945Sweongyo	if (index >= per_sta_keys_start)
4436203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
4437203945Sweongyo	if (key)
4438203945Sweongyo		memcpy(buf, key, key_len);
4439203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
4440203945Sweongyo	if (index >= per_sta_keys_start)
4441203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
4442203945Sweongyo
4443203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
4444203945Sweongyo}
4445203945Sweongyo
4446203945Sweongyostatic void
4447203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
4448203945Sweongyo{
4449204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4450203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
4451203945Sweongyo	uint8_t start = 8;
4452203945Sweongyo
4453203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4454203945Sweongyo		start = 4;
4455203945Sweongyo
4456203945Sweongyo	KASSERT(index >= start,
4457203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4458203945Sweongyo	index -= start;
4459203945Sweongyo
4460203945Sweongyo	if (addr) {
4461203945Sweongyo		addrtmp[0] = addr[0];
4462203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
4463203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
4464203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
4465203945Sweongyo		addrtmp[1] = addr[4];
4466203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
4467203945Sweongyo	}
4468203945Sweongyo
4469204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
4470203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
4471203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
4472203945Sweongyo	} else {
4473203945Sweongyo		if (index >= 8) {
4474203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
4475203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
4476203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
4477203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
4478203945Sweongyo		}
4479203945Sweongyo	}
4480203945Sweongyo}
4481203945Sweongyo
4482203945Sweongyostatic void
4483203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4484203945Sweongyo    const uint8_t *key)
4485203945Sweongyo{
4486203945Sweongyo	unsigned int i;
4487203945Sweongyo	uint32_t offset;
4488203945Sweongyo	uint16_t kidx, value;
4489203945Sweongyo
4490203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
4491203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
4492203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
4493203945Sweongyo
4494203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
4495203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
4496203945Sweongyo		value = key[i];
4497203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
4498203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
4499203945Sweongyo	}
4500203945Sweongyo}
4501203945Sweongyo
4502203945Sweongyostatic void
4503203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
4504203945Sweongyo{
4505203945Sweongyo
4506203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4507203945Sweongyo	if (mac->mac_phy.exit != NULL)
4508203945Sweongyo		mac->mac_phy.exit(mac);
4509203945Sweongyo}
4510203945Sweongyo
4511203945Sweongyostatic void
4512203945Sweongyobwn_dma_free(struct bwn_mac *mac)
4513203945Sweongyo{
4514203945Sweongyo	struct bwn_dma *dma;
4515203945Sweongyo
4516203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
4517203945Sweongyo		return;
4518203945Sweongyo	dma = &mac->mac_method.dma;
4519203945Sweongyo
4520203945Sweongyo	bwn_dma_ringfree(&dma->rx);
4521203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
4522203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
4523203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
4524203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
4525203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
4526203945Sweongyo}
4527203945Sweongyo
4528203945Sweongyostatic void
4529203945Sweongyobwn_core_stop(struct bwn_mac *mac)
4530203945Sweongyo{
4531203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4532203945Sweongyo
4533203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4534203945Sweongyo
4535203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
4536203945Sweongyo		return;
4537203945Sweongyo
4538203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
4539203945Sweongyo	callout_stop(&sc->sc_task_ch);
4540203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
4541203945Sweongyo	sc->sc_watchdog_timer = 0;
4542203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4543203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
4544203945Sweongyo	bwn_mac_suspend(mac);
4545203945Sweongyo
4546203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
4547203945Sweongyo}
4548203945Sweongyo
4549203945Sweongyostatic int
4550203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
4551203945Sweongyo{
4552203945Sweongyo	struct bwn_mac *up_dev = NULL;
4553203945Sweongyo	struct bwn_mac *down_dev;
4554203945Sweongyo	struct bwn_mac *mac;
4555203945Sweongyo	int err, status;
4556203945Sweongyo	uint8_t gmode;
4557203945Sweongyo
4558203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4559203945Sweongyo
4560203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
4561203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
4562203945Sweongyo		    mac->mac_phy.supports_2ghz) {
4563203945Sweongyo			up_dev = mac;
4564203945Sweongyo			gmode = 1;
4565203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
4566203945Sweongyo		    mac->mac_phy.supports_5ghz) {
4567203945Sweongyo			up_dev = mac;
4568203945Sweongyo			gmode = 0;
4569203945Sweongyo		} else {
4570203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4571203945Sweongyo			return (EINVAL);
4572203945Sweongyo		}
4573203945Sweongyo		if (up_dev != NULL)
4574203945Sweongyo			break;
4575203945Sweongyo	}
4576203945Sweongyo	if (up_dev == NULL) {
4577203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
4578203945Sweongyo		return (ENODEV);
4579203945Sweongyo	}
4580203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
4581203945Sweongyo		return (0);
4582203945Sweongyo
4583299793Sadrian	DPRINTF(sc, BWN_DEBUG_RF | BWN_DEBUG_PHY | BWN_DEBUG_RESET,
4584299793Sadrian	    "switching to %s-GHz band\n",
4585203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4586203945Sweongyo
4587216227Skevlo	down_dev = sc->sc_curmac;
4588203945Sweongyo	status = down_dev->mac_status;
4589203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4590203945Sweongyo		bwn_core_stop(down_dev);
4591203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
4592203945Sweongyo		bwn_core_exit(down_dev);
4593203945Sweongyo
4594203945Sweongyo	if (down_dev != up_dev)
4595203945Sweongyo		bwn_phy_reset(down_dev);
4596203945Sweongyo
4597203945Sweongyo	up_dev->mac_phy.gmode = gmode;
4598203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
4599203945Sweongyo		err = bwn_core_init(up_dev);
4600203945Sweongyo		if (err) {
4601203945Sweongyo			device_printf(sc->sc_dev,
4602203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
4603203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4604203945Sweongyo			goto fail;
4605203945Sweongyo		}
4606203945Sweongyo	}
4607203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4608203945Sweongyo		bwn_core_start(up_dev);
4609203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
4610203945Sweongyo	sc->sc_curmac = up_dev;
4611203945Sweongyo
4612203945Sweongyo	return (0);
4613203945Sweongyofail:
4614203945Sweongyo	sc->sc_curmac = NULL;
4615203945Sweongyo	return (err);
4616203945Sweongyo}
4617203945Sweongyo
4618203945Sweongyostatic void
4619203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
4620203945Sweongyo{
4621203945Sweongyo
4622299793Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
4623299793Sadrian
4624203945Sweongyo	bwn_mac_suspend(mac);
4625203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4626203945Sweongyo	mac->mac_phy.rf_on = 1;
4627203945Sweongyo	bwn_mac_enable(mac);
4628203945Sweongyo}
4629203945Sweongyo
4630203945Sweongyostatic void
4631203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
4632203945Sweongyo{
4633203945Sweongyo
4634299793Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
4635299793Sadrian
4636203945Sweongyo	bwn_mac_suspend(mac);
4637203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4638203945Sweongyo	mac->mac_phy.rf_on = 0;
4639203945Sweongyo	bwn_mac_enable(mac);
4640203945Sweongyo}
4641203945Sweongyo
4642299776Sadrian/*
4643299776Sadrian * SSB PHY reset.
4644299776Sadrian *
4645299776Sadrian * XXX TODO: BCMA PHY reset.
4646299776Sadrian */
4647203945Sweongyostatic void
4648203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
4649203945Sweongyo{
4650204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4651203945Sweongyo
4652204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4653204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
4654203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
4655203945Sweongyo	DELAY(1000);
4656204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4657299776Sadrian	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC));
4658203945Sweongyo	DELAY(1000);
4659203945Sweongyo}
4660203945Sweongyo
4661203945Sweongyostatic int
4662203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
4663203945Sweongyo{
4664203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
4665203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
4666203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
4667286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
4668203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
4669203945Sweongyo	int error;
4670203945Sweongyo
4671203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
4672203945Sweongyo	    ieee80211_state_name[vap->iv_state],
4673203945Sweongyo	    ieee80211_state_name[nstate]);
4674203945Sweongyo
4675203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
4676203945Sweongyo	if (error != 0)
4677203945Sweongyo		return (error);
4678203945Sweongyo
4679203945Sweongyo	BWN_LOCK(sc);
4680203945Sweongyo
4681203945Sweongyo	bwn_led_newstate(mac, nstate);
4682203945Sweongyo
4683203945Sweongyo	/*
4684203945Sweongyo	 * Clear the BSSID when we stop a STA
4685203945Sweongyo	 */
4686203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
4687203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
4688203945Sweongyo			/*
4689203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
4690203945Sweongyo			 * the same AP, this will reinialize things
4691203945Sweongyo			 * correctly...
4692203945Sweongyo			 */
4693203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
4694203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
4695203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
4696203945Sweongyo				bwn_set_macaddr(mac);
4697203945Sweongyo			}
4698203945Sweongyo		}
4699203945Sweongyo	}
4700203945Sweongyo
4701204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
4702204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
4703203945Sweongyo		/* XXX nothing to do? */
4704203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
4705203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
4706203945Sweongyo		bwn_set_opmode(mac);
4707203945Sweongyo		bwn_set_pretbtt(mac);
4708203945Sweongyo		bwn_spu_setdelay(mac, 0);
4709203945Sweongyo		bwn_set_macaddr(mac);
4710203945Sweongyo	}
4711203945Sweongyo
4712203945Sweongyo	BWN_UNLOCK(sc);
4713203945Sweongyo
4714203945Sweongyo	return (error);
4715203945Sweongyo}
4716203945Sweongyo
4717203945Sweongyostatic void
4718203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
4719203945Sweongyo{
4720203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4721287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4722203945Sweongyo	uint16_t pretbtt;
4723203945Sweongyo
4724203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
4725203945Sweongyo		pretbtt = 2;
4726203945Sweongyo	else
4727203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
4728203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
4729203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
4730203945Sweongyo}
4731203945Sweongyo
4732203945Sweongyostatic int
4733203945Sweongyobwn_intr(void *arg)
4734203945Sweongyo{
4735203945Sweongyo	struct bwn_mac *mac = arg;
4736203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4737203945Sweongyo	uint32_t reason;
4738203945Sweongyo
4739204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4740204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
4741203945Sweongyo		return (FILTER_STRAY);
4742203945Sweongyo
4743203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
4744203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
4745203945Sweongyo		return (FILTER_STRAY);
4746203945Sweongyo	reason &= mac->mac_intr_mask;
4747203945Sweongyo	if (reason == 0)
4748203945Sweongyo		return (FILTER_HANDLED);
4749203945Sweongyo
4750203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
4751203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
4752203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
4753203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
4754203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
4755203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
4756203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
4757203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
4758203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
4759203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
4760203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
4761203945Sweongyo
4762203945Sweongyo	/* Disable interrupts. */
4763203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4764203945Sweongyo
4765203945Sweongyo	mac->mac_reason_intr = reason;
4766203945Sweongyo
4767203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4768203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4769203945Sweongyo
4770296272Sjhb	taskqueue_enqueue(sc->sc_tq, &mac->mac_intrtask);
4771203945Sweongyo	return (FILTER_HANDLED);
4772203945Sweongyo}
4773203945Sweongyo
4774203945Sweongyostatic void
4775203945Sweongyobwn_intrtask(void *arg, int npending)
4776203945Sweongyo{
4777203945Sweongyo	struct bwn_mac *mac = arg;
4778203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4779203945Sweongyo	uint32_t merged = 0;
4780203945Sweongyo	int i, tx = 0, rx = 0;
4781203945Sweongyo
4782203945Sweongyo	BWN_LOCK(sc);
4783204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4784204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
4785203945Sweongyo		BWN_UNLOCK(sc);
4786203945Sweongyo		return;
4787203945Sweongyo	}
4788203945Sweongyo
4789203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
4790203945Sweongyo		merged |= mac->mac_reason[i];
4791203945Sweongyo
4792203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
4793203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
4794203945Sweongyo
4795203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
4796203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
4797203945Sweongyo		mac->mac_phy.txerrors--;
4798203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
4799203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
4800203945Sweongyo			bwn_restart(mac, "PHY TX errors");
4801203945Sweongyo		}
4802203945Sweongyo	}
4803203945Sweongyo
4804203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
4805203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
4806203945Sweongyo			device_printf(sc->sc_dev,
4807203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
4808203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4809203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4810203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4811203945Sweongyo			bwn_restart(mac, "DMA error");
4812203945Sweongyo			BWN_UNLOCK(sc);
4813203945Sweongyo			return;
4814203945Sweongyo		}
4815203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
4816203945Sweongyo			device_printf(sc->sc_dev,
4817203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
4818203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4819203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4820203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4821203945Sweongyo		}
4822203945Sweongyo	}
4823203945Sweongyo
4824203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
4825203945Sweongyo		bwn_intr_ucode_debug(mac);
4826203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
4827203945Sweongyo		bwn_intr_tbtt_indication(mac);
4828203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
4829203945Sweongyo		bwn_intr_atim_end(mac);
4830203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
4831203945Sweongyo		bwn_intr_beacon(mac);
4832203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
4833203945Sweongyo		bwn_intr_pmq(mac);
4834203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
4835203945Sweongyo		bwn_intr_noise(mac);
4836203945Sweongyo
4837203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
4838203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
4839203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
4840203945Sweongyo			rx = 1;
4841203945Sweongyo		}
4842203945Sweongyo	} else
4843203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
4844203945Sweongyo
4845203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4846203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4847203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4848203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4849203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4850203945Sweongyo
4851203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
4852203945Sweongyo		bwn_intr_txeof(mac);
4853203945Sweongyo		tx = 1;
4854203945Sweongyo	}
4855203945Sweongyo
4856203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
4857203945Sweongyo
4858203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
4859203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
4860203945Sweongyo
4861203945Sweongyo		if (tx && rx) {
4862203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
4863203945Sweongyo				evt = BWN_LED_EVENT_RX;
4864203945Sweongyo			else
4865203945Sweongyo				evt = BWN_LED_EVENT_TX;
4866203945Sweongyo		} else if (tx) {
4867203945Sweongyo			evt = BWN_LED_EVENT_TX;
4868203945Sweongyo		} else if (rx) {
4869203945Sweongyo			evt = BWN_LED_EVENT_RX;
4870203945Sweongyo		} else if (rx == 0) {
4871203945Sweongyo			evt = BWN_LED_EVENT_POLL;
4872203945Sweongyo		}
4873203945Sweongyo
4874203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
4875203945Sweongyo			bwn_led_event(mac, evt);
4876203945Sweongyo       }
4877203945Sweongyo
4878287197Sglebius	if (mbufq_first(&sc->sc_snd) != NULL)
4879287197Sglebius		bwn_start(sc);
4880203945Sweongyo
4881203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4882203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4883203945Sweongyo
4884203945Sweongyo	BWN_UNLOCK(sc);
4885203945Sweongyo}
4886203945Sweongyo
4887203945Sweongyostatic void
4888203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
4889203945Sweongyo{
4890203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4891287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4892203945Sweongyo
4893203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
4894203945Sweongyo		return;
4895203945Sweongyo
4896203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
4897203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
4898203945Sweongyo}
4899203945Sweongyo
4900203945Sweongyostatic void
4901203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
4902203945Sweongyo{
4903203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4904203945Sweongyo	uint16_t reason;
4905203945Sweongyo
4906203945Sweongyo	if (mac->mac_fw.opensource == 0)
4907203945Sweongyo		return;
4908203945Sweongyo
4909203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
4910203945Sweongyo	switch (reason) {
4911203945Sweongyo	case BWN_DEBUGINTR_PANIC:
4912203945Sweongyo		bwn_handle_fwpanic(mac);
4913203945Sweongyo		break;
4914203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
4915203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
4916203945Sweongyo		break;
4917203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
4918203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
4919203945Sweongyo		break;
4920203945Sweongyo	case BWN_DEBUGINTR_MARKER:
4921203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
4922203945Sweongyo		break;
4923203945Sweongyo	default:
4924203945Sweongyo		device_printf(sc->sc_dev,
4925203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
4926203945Sweongyo	}
4927203945Sweongyo
4928203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
4929203945Sweongyo	    BWN_DEBUGINTR_ACK);
4930203945Sweongyo}
4931203945Sweongyo
4932203945Sweongyostatic void
4933203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
4934203945Sweongyo{
4935203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4936287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4937203945Sweongyo
4938203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
4939203945Sweongyo		bwn_psctl(mac, 0);
4940203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
4941203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
4942203945Sweongyo}
4943203945Sweongyo
4944203945Sweongyostatic void
4945203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
4946203945Sweongyo{
4947203945Sweongyo
4948203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
4949203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
4950203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
4951203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
4952203945Sweongyo	}
4953203945Sweongyo}
4954203945Sweongyo
4955203945Sweongyostatic void
4956203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
4957203945Sweongyo{
4958203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4959287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4960203945Sweongyo	uint32_t cmd, beacon0, beacon1;
4961203945Sweongyo
4962203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4963203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4964203945Sweongyo		return;
4965203945Sweongyo
4966203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
4967203945Sweongyo
4968203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
4969203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
4970203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
4971203945Sweongyo
4972203945Sweongyo	if (beacon0 && beacon1) {
4973203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
4974203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
4975203945Sweongyo		return;
4976203945Sweongyo	}
4977203945Sweongyo
4978203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
4979203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
4980203945Sweongyo		bwn_load_beacon0(mac);
4981203945Sweongyo		bwn_load_beacon1(mac);
4982203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
4983203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
4984203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4985203945Sweongyo	} else {
4986203945Sweongyo		if (!beacon0) {
4987203945Sweongyo			bwn_load_beacon0(mac);
4988203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
4989203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
4990203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4991203945Sweongyo		} else if (!beacon1) {
4992203945Sweongyo			bwn_load_beacon1(mac);
4993203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
4994203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
4995203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4996203945Sweongyo		}
4997203945Sweongyo	}
4998203945Sweongyo}
4999203945Sweongyo
5000203945Sweongyostatic void
5001203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
5002203945Sweongyo{
5003203945Sweongyo	uint32_t tmp;
5004203945Sweongyo
5005203945Sweongyo	while (1) {
5006203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
5007203945Sweongyo		if (!(tmp & 0x00000008))
5008203945Sweongyo			break;
5009203945Sweongyo	}
5010203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
5011203945Sweongyo}
5012203945Sweongyo
5013203945Sweongyostatic void
5014203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
5015203945Sweongyo{
5016203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5017203945Sweongyo	uint16_t tmp;
5018203945Sweongyo	uint8_t noise[4];
5019203945Sweongyo	uint8_t i, j;
5020203945Sweongyo	int32_t average;
5021203945Sweongyo
5022203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
5023203945Sweongyo		return;
5024203945Sweongyo
5025203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
5026203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
5027203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
5028203945Sweongyo	    noise[3] == 0x7f)
5029203945Sweongyo		goto new;
5030203945Sweongyo
5031203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
5032203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5033203945Sweongyo	i = mac->mac_noise.noi_nsamples;
5034203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
5035203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
5036203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
5037203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
5038203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
5039203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
5040203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
5041203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
5042203945Sweongyo	mac->mac_noise.noi_nsamples++;
5043203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
5044203945Sweongyo		average = 0;
5045203945Sweongyo		for (i = 0; i < 8; i++) {
5046203945Sweongyo			for (j = 0; j < 4; j++)
5047203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
5048203945Sweongyo		}
5049203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
5050203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
5051203945Sweongyo		if (tmp >= 8)
5052203945Sweongyo			average += 2;
5053203945Sweongyo		else
5054203945Sweongyo			average -= 25;
5055203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
5056203945Sweongyo
5057203945Sweongyo		mac->mac_stats.link_noise = average;
5058203945Sweongyo		mac->mac_noise.noi_running = 0;
5059203945Sweongyo		return;
5060203945Sweongyo	}
5061203945Sweongyonew:
5062203945Sweongyo	bwn_noise_gensample(mac);
5063203945Sweongyo}
5064203945Sweongyo
5065203945Sweongyostatic int
5066203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
5067203945Sweongyo{
5068203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
5069203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5070203945Sweongyo	unsigned int i;
5071203945Sweongyo
5072203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5073203945Sweongyo
5074203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
5075203945Sweongyo		return (0);
5076203945Sweongyo
5077203945Sweongyo	for (i = 0; i < 5000; i++) {
5078203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
5079203945Sweongyo			break;
5080203945Sweongyo	}
5081203945Sweongyo	if (i >= 5000)
5082203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
5083203945Sweongyo	return ((i > 0) ? 1 : 0);
5084203945Sweongyo}
5085203945Sweongyo
5086203945Sweongyostatic void
5087203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
5088203945Sweongyo{
5089203945Sweongyo	int slot, curslot;
5090203945Sweongyo
5091203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
5092203945Sweongyo	curslot = dr->get_curslot(dr);
5093203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
5094203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5095203945Sweongyo
5096203945Sweongyo	slot = dr->dr_curslot;
5097203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
5098203945Sweongyo		bwn_dma_rxeof(dr, &slot);
5099203945Sweongyo
5100203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
5101203945Sweongyo	    BUS_DMASYNC_PREWRITE);
5102203945Sweongyo
5103203945Sweongyo	dr->set_curslot(dr, slot);
5104203945Sweongyo	dr->dr_curslot = slot;
5105203945Sweongyo}
5106203945Sweongyo
5107203945Sweongyostatic void
5108203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
5109203945Sweongyo{
5110203945Sweongyo	struct bwn_txstatus stat;
5111203945Sweongyo	uint32_t stat0, stat1;
5112203945Sweongyo	uint16_t tmp;
5113203945Sweongyo
5114203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
5115203945Sweongyo
5116203945Sweongyo	while (1) {
5117203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
5118203945Sweongyo		if (!(stat0 & 0x00000001))
5119203945Sweongyo			break;
5120203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
5121203945Sweongyo
5122299036Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT,
5123299036Sadrian		    "%s: stat0=0x%08x, stat1=0x%08x\n",
5124299036Sadrian		    __func__,
5125299036Sadrian		    stat0,
5126299036Sadrian		    stat1);
5127299036Sadrian
5128203945Sweongyo		stat.cookie = (stat0 >> 16);
5129203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
5130203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
5131203945Sweongyo		tmp = (stat0 & 0x0000ffff);
5132203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
5133203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
5134203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
5135203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
5136203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
5137203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
5138203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
5139203945Sweongyo
5140299782Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT,
5141299782Sadrian		    "%s: cookie=%d, seq=%d, phystat=0x%02x, framecnt=%d, "
5142299782Sadrian		    "rtscnt=%d, sreason=%d, pm=%d, im=%d, ampdu=%d, ack=%d\n",
5143299782Sadrian		    __func__,
5144299782Sadrian		    stat.cookie,
5145299782Sadrian		    stat.seq,
5146299782Sadrian		    stat.phy_stat,
5147299782Sadrian		    stat.framecnt,
5148299782Sadrian		    stat.rtscnt,
5149299782Sadrian		    stat.sreason,
5150299782Sadrian		    stat.pm,
5151299782Sadrian		    stat.im,
5152299782Sadrian		    stat.ampdu,
5153299782Sadrian		    stat.ack);
5154299782Sadrian
5155203945Sweongyo		bwn_handle_txeof(mac, &stat);
5156203945Sweongyo	}
5157203945Sweongyo}
5158203945Sweongyo
5159203945Sweongyostatic void
5160203945Sweongyobwn_hwreset(void *arg, int npending)
5161203945Sweongyo{
5162203945Sweongyo	struct bwn_mac *mac = arg;
5163203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5164203945Sweongyo	int error = 0;
5165203945Sweongyo	int prev_status;
5166203945Sweongyo
5167203945Sweongyo	BWN_LOCK(sc);
5168203945Sweongyo
5169203945Sweongyo	prev_status = mac->mac_status;
5170203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5171203945Sweongyo		bwn_core_stop(mac);
5172203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
5173203945Sweongyo		bwn_core_exit(mac);
5174203945Sweongyo
5175203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
5176203945Sweongyo		error = bwn_core_init(mac);
5177203945Sweongyo		if (error)
5178203945Sweongyo			goto out;
5179203945Sweongyo	}
5180203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5181203945Sweongyo		bwn_core_start(mac);
5182203945Sweongyoout:
5183203945Sweongyo	if (error) {
5184203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
5185203945Sweongyo		sc->sc_curmac = NULL;
5186203945Sweongyo	}
5187203945Sweongyo	BWN_UNLOCK(sc);
5188203945Sweongyo}
5189203945Sweongyo
5190203945Sweongyostatic void
5191203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
5192203945Sweongyo{
5193203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5194203945Sweongyo	uint16_t reason;
5195203945Sweongyo
5196203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
5197203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
5198203945Sweongyo
5199203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
5200203945Sweongyo		bwn_restart(mac, "ucode panic");
5201203945Sweongyo}
5202203945Sweongyo
5203203945Sweongyostatic void
5204203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
5205203945Sweongyo{
5206203945Sweongyo
5207203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5208203945Sweongyo}
5209203945Sweongyo
5210203945Sweongyostatic void
5211203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
5212203945Sweongyo{
5213203945Sweongyo
5214203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5215203945Sweongyo}
5216203945Sweongyo
5217203945Sweongyostatic uint32_t
5218203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
5219203945Sweongyo{
5220203945Sweongyo	uint32_t val = 0;
5221203945Sweongyo
5222203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
5223203945Sweongyo	val <<= 16;
5224203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
5225203945Sweongyo
5226203945Sweongyo	return (val);
5227203945Sweongyo}
5228203945Sweongyo
5229203945Sweongyostatic void
5230203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
5231203945Sweongyo{
5232203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
5233203945Sweongyo
5234203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
5235203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
5236203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
5237203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
5238203945Sweongyo}
5239203945Sweongyo
5240203945Sweongyostatic int
5241203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
5242203945Sweongyo{
5243204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5244203945Sweongyo
5245203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
5246203945Sweongyo}
5247203945Sweongyo
5248203945Sweongyostatic int
5249203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
5250203945Sweongyo{
5251204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5252203945Sweongyo
5253203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
5254203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5255203945Sweongyo	if (slot == dr->dr_numslots - 1)
5256203945Sweongyo		return (0);
5257203945Sweongyo	return (slot + 1);
5258203945Sweongyo}
5259203945Sweongyo
5260203945Sweongyostatic void
5261203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
5262203945Sweongyo{
5263203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5264203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5265203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5266203945Sweongyo	struct bwn_dmadesc_generic *desc;
5267203945Sweongyo	struct bwn_dmadesc_meta *meta;
5268203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
5269203945Sweongyo	struct mbuf *m;
5270203945Sweongyo	uint32_t macstat;
5271203945Sweongyo	int32_t tmp;
5272203945Sweongyo	int cnt = 0;
5273203945Sweongyo	uint16_t len;
5274203945Sweongyo
5275203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
5276203945Sweongyo
5277203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
5278203945Sweongyo	m = meta->mt_m;
5279203945Sweongyo
5280203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
5281287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5282203945Sweongyo		return;
5283203945Sweongyo	}
5284203945Sweongyo
5285203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
5286203945Sweongyo	len = le16toh(rxhdr->frame_len);
5287203945Sweongyo	if (len <= 0) {
5288287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5289203945Sweongyo		return;
5290203945Sweongyo	}
5291203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
5292203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
5293203945Sweongyo		bwn_dma_set_redzone(dr, m);
5294203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5295203945Sweongyo		    BUS_DMASYNC_PREWRITE);
5296203945Sweongyo		return;
5297203945Sweongyo	}
5298203945Sweongyo	if (len > dr->dr_rx_bufsize) {
5299203945Sweongyo		tmp = len;
5300203945Sweongyo		while (1) {
5301203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
5302203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
5303203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5304203945Sweongyo			    BUS_DMASYNC_PREWRITE);
5305203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
5306203945Sweongyo			cnt++;
5307203945Sweongyo			tmp -= dr->dr_rx_bufsize;
5308203945Sweongyo			if (tmp <= 0)
5309203945Sweongyo				break;
5310203945Sweongyo		}
5311203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
5312203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
5313203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
5314203945Sweongyo		return;
5315203945Sweongyo	}
5316203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
5317203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5318203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5319203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
5320203945Sweongyo			return;
5321203945Sweongyo		}
5322203945Sweongyo	}
5323203945Sweongyo
5324203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
5325203945Sweongyo	m_adj(m, dr->dr_frameoffset);
5326203945Sweongyo
5327203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
5328203945Sweongyo}
5329203945Sweongyo
5330203945Sweongyostatic void
5331203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
5332203945Sweongyo{
5333203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5334204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
5335203945Sweongyo
5336203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
5337203945Sweongyo
5338203945Sweongyo	if (status->im)
5339203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
5340203945Sweongyo	if (status->ampdu)
5341203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
5342203945Sweongyo	if (status->rtscnt) {
5343203945Sweongyo		if (status->rtscnt == 0xf)
5344204257Sweongyo			stats->rtsfail++;
5345203945Sweongyo		else
5346204257Sweongyo			stats->rts++;
5347203945Sweongyo	}
5348203945Sweongyo
5349203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
5350203945Sweongyo		bwn_dma_handle_txeof(mac, status);
5351203945Sweongyo	} else {
5352203945Sweongyo		bwn_pio_handle_txeof(mac, status);
5353203945Sweongyo	}
5354203945Sweongyo
5355203945Sweongyo	bwn_phy_txpower_check(mac, 0);
5356203945Sweongyo}
5357203945Sweongyo
5358203945Sweongyostatic uint8_t
5359203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
5360203945Sweongyo{
5361203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
5362203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5363203945Sweongyo	struct bwn_rxhdr4 rxhdr;
5364203945Sweongyo	struct mbuf *m;
5365203945Sweongyo	uint32_t ctl32, macstat, v32;
5366203945Sweongyo	unsigned int i, padding;
5367209888Sweongyo	uint16_t ctl16, len, totlen, v16;
5368203945Sweongyo	unsigned char *mp;
5369203945Sweongyo	char *data;
5370203945Sweongyo
5371203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
5372203945Sweongyo
5373203945Sweongyo	if (prq->prq_rev >= 8) {
5374203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5375203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
5376203945Sweongyo			return (0);
5377203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5378203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
5379203945Sweongyo		for (i = 0; i < 10; i++) {
5380203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5381203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
5382203945Sweongyo				goto ready;
5383203945Sweongyo			DELAY(10);
5384203945Sweongyo		}
5385203945Sweongyo	} else {
5386203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5387203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
5388203945Sweongyo			return (0);
5389203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
5390203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
5391203945Sweongyo		for (i = 0; i < 10; i++) {
5392203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5393203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
5394203945Sweongyo				goto ready;
5395203945Sweongyo			DELAY(10);
5396203945Sweongyo		}
5397203945Sweongyo	}
5398203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
5399203945Sweongyo	return (1);
5400203945Sweongyoready:
5401203945Sweongyo	if (prq->prq_rev >= 8)
5402204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5403203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5404203945Sweongyo	else
5405204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5406203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5407203945Sweongyo	len = le16toh(rxhdr.frame_len);
5408203945Sweongyo	if (len > 0x700) {
5409203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
5410203945Sweongyo		goto error;
5411203945Sweongyo	}
5412203945Sweongyo	if (len == 0) {
5413203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
5414203945Sweongyo		goto error;
5415203945Sweongyo	}
5416203945Sweongyo
5417203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
5418203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5419203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5420203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
5421203945Sweongyo			goto error;
5422203945Sweongyo		}
5423203945Sweongyo	}
5424203945Sweongyo
5425203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5426209888Sweongyo	totlen = len + padding;
5427209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
5428243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5429203945Sweongyo	if (m == NULL) {
5430203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
5431203945Sweongyo		goto error;
5432203945Sweongyo	}
5433203945Sweongyo	mp = mtod(m, unsigned char *);
5434203945Sweongyo	if (prq->prq_rev >= 8) {
5435209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
5436203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5437209888Sweongyo		if (totlen & 3) {
5438203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
5439209888Sweongyo			data = &(mp[totlen - 1]);
5440209888Sweongyo			switch (totlen & 3) {
5441203945Sweongyo			case 3:
5442203945Sweongyo				*data = (v32 >> 16);
5443203945Sweongyo				data--;
5444203945Sweongyo			case 2:
5445203945Sweongyo				*data = (v32 >> 8);
5446203945Sweongyo				data--;
5447203945Sweongyo			case 1:
5448203945Sweongyo				*data = v32;
5449203945Sweongyo			}
5450203945Sweongyo		}
5451203945Sweongyo	} else {
5452209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
5453203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5454209888Sweongyo		if (totlen & 1) {
5455203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
5456209888Sweongyo			mp[totlen - 1] = v16;
5457203945Sweongyo		}
5458203945Sweongyo	}
5459203945Sweongyo
5460209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
5461203945Sweongyo
5462203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
5463203945Sweongyo
5464203945Sweongyo	return (1);
5465203945Sweongyoerror:
5466203945Sweongyo	if (prq->prq_rev >= 8)
5467203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5468203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
5469203945Sweongyo	else
5470203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
5471203945Sweongyo	return (1);
5472203945Sweongyo}
5473203945Sweongyo
5474203945Sweongyostatic int
5475203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
5476203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
5477203945Sweongyo{
5478203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5479203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5480203945Sweongyo	struct bwn_rxhdr4 *hdr;
5481203945Sweongyo	bus_dmamap_t map;
5482203945Sweongyo	bus_addr_t paddr;
5483203945Sweongyo	struct mbuf *m;
5484203945Sweongyo	int error;
5485203945Sweongyo
5486243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5487203945Sweongyo	if (m == NULL) {
5488203945Sweongyo		error = ENOBUFS;
5489203945Sweongyo
5490203945Sweongyo		/*
5491203945Sweongyo		 * If the NIC is up and running, we need to:
5492203945Sweongyo		 * - Clear RX buffer's header.
5493203945Sweongyo		 * - Restore RX descriptor settings.
5494203945Sweongyo		 */
5495203945Sweongyo		if (init)
5496203945Sweongyo			return (error);
5497203945Sweongyo		else
5498203945Sweongyo			goto back;
5499203945Sweongyo	}
5500203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
5501203945Sweongyo
5502203945Sweongyo	bwn_dma_set_redzone(dr, m);
5503203945Sweongyo
5504203945Sweongyo	/*
5505203945Sweongyo	 * Try to load RX buf into temporary DMA map
5506203945Sweongyo	 */
5507203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
5508203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
5509203945Sweongyo	if (error) {
5510203945Sweongyo		m_freem(m);
5511203945Sweongyo
5512203945Sweongyo		/*
5513203945Sweongyo		 * See the comment above
5514203945Sweongyo		 */
5515203945Sweongyo		if (init)
5516203945Sweongyo			return (error);
5517203945Sweongyo		else
5518203945Sweongyo			goto back;
5519203945Sweongyo	}
5520203945Sweongyo
5521203945Sweongyo	if (!init)
5522203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
5523203945Sweongyo	meta->mt_m = m;
5524203945Sweongyo	meta->mt_paddr = paddr;
5525203945Sweongyo
5526203945Sweongyo	/*
5527203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
5528203945Sweongyo	 */
5529203945Sweongyo	map = meta->mt_dmap;
5530203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
5531203945Sweongyo	dr->dr_spare_dmap = map;
5532203945Sweongyo
5533203945Sweongyoback:
5534203945Sweongyo	/*
5535203945Sweongyo	 * Clear RX buf header
5536203945Sweongyo	 */
5537203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
5538203945Sweongyo	bzero(hdr, sizeof(*hdr));
5539203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5540203945Sweongyo	    BUS_DMASYNC_PREWRITE);
5541203945Sweongyo
5542203945Sweongyo	/*
5543203945Sweongyo	 * Setup RX buf descriptor
5544203945Sweongyo	 */
5545250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
5546203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
5547203945Sweongyo	return (error);
5548203945Sweongyo}
5549203945Sweongyo
5550203945Sweongyostatic void
5551203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
5552203945Sweongyo		 bus_size_t mapsz __unused, int error)
5553203945Sweongyo{
5554203945Sweongyo
5555203945Sweongyo	if (!error) {
5556203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
5557203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
5558203945Sweongyo	}
5559203945Sweongyo}
5560203945Sweongyo
5561203945Sweongyostatic int
5562203945Sweongyobwn_hwrate2ieeerate(int rate)
5563203945Sweongyo{
5564203945Sweongyo
5565203945Sweongyo	switch (rate) {
5566203945Sweongyo	case BWN_CCK_RATE_1MB:
5567203945Sweongyo		return (2);
5568203945Sweongyo	case BWN_CCK_RATE_2MB:
5569203945Sweongyo		return (4);
5570203945Sweongyo	case BWN_CCK_RATE_5MB:
5571203945Sweongyo		return (11);
5572203945Sweongyo	case BWN_CCK_RATE_11MB:
5573203945Sweongyo		return (22);
5574203945Sweongyo	case BWN_OFDM_RATE_6MB:
5575203945Sweongyo		return (12);
5576203945Sweongyo	case BWN_OFDM_RATE_9MB:
5577203945Sweongyo		return (18);
5578203945Sweongyo	case BWN_OFDM_RATE_12MB:
5579203945Sweongyo		return (24);
5580203945Sweongyo	case BWN_OFDM_RATE_18MB:
5581203945Sweongyo		return (36);
5582203945Sweongyo	case BWN_OFDM_RATE_24MB:
5583203945Sweongyo		return (48);
5584203945Sweongyo	case BWN_OFDM_RATE_36MB:
5585203945Sweongyo		return (72);
5586203945Sweongyo	case BWN_OFDM_RATE_48MB:
5587203945Sweongyo		return (96);
5588203945Sweongyo	case BWN_OFDM_RATE_54MB:
5589203945Sweongyo		return (108);
5590203945Sweongyo	default:
5591203945Sweongyo		printf("Ooops\n");
5592203945Sweongyo		return (0);
5593203945Sweongyo	}
5594203945Sweongyo}
5595203945Sweongyo
5596299110Sadrian/*
5597299110Sadrian * Post process the RX provided RSSI.
5598299110Sadrian *
5599299110Sadrian * Valid for A, B, G, LP PHYs.
5600299110Sadrian */
5601299110Sadrianstatic int8_t
5602299131Sadrianbwn_rx_rssi_calc(struct bwn_mac *mac, uint8_t in_rssi,
5603299110Sadrian    int ofdm, int adjust_2053, int adjust_2050)
5604299110Sadrian{
5605299110Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5606299110Sadrian	struct bwn_phy_g *gphy = &phy->phy_g;
5607299110Sadrian	int tmp;
5608299110Sadrian
5609299110Sadrian	switch (phy->rf_ver) {
5610299110Sadrian	case 0x2050:
5611299110Sadrian		if (ofdm) {
5612299110Sadrian			tmp = in_rssi;
5613299110Sadrian			if (tmp > 127)
5614299110Sadrian				tmp -= 256;
5615299110Sadrian			tmp = tmp * 73 / 64;
5616299110Sadrian			if (adjust_2050)
5617299110Sadrian				tmp += 25;
5618299110Sadrian			else
5619299110Sadrian				tmp -= 3;
5620299110Sadrian		} else {
5621299110Sadrian			if (siba_sprom_get_bf_lo(mac->mac_sc->sc_dev)
5622299110Sadrian			    & BWN_BFL_RSSI) {
5623299110Sadrian				if (in_rssi > 63)
5624299110Sadrian					in_rssi = 63;
5625299110Sadrian				tmp = gphy->pg_nrssi_lt[in_rssi];
5626299110Sadrian				tmp = (31 - tmp) * -131 / 128 - 57;
5627299110Sadrian			} else {
5628299110Sadrian				tmp = in_rssi;
5629299110Sadrian				tmp = (31 - tmp) * -149 / 128 - 68;
5630299110Sadrian			}
5631299110Sadrian			if (phy->type == BWN_PHYTYPE_G && adjust_2050)
5632299110Sadrian				tmp += 25;
5633299110Sadrian		}
5634299110Sadrian		break;
5635299110Sadrian	case 0x2060:
5636299110Sadrian		if (in_rssi > 127)
5637299110Sadrian			tmp = in_rssi - 256;
5638299110Sadrian		else
5639299110Sadrian			tmp = in_rssi;
5640299110Sadrian		break;
5641299110Sadrian	default:
5642299110Sadrian		tmp = in_rssi;
5643299110Sadrian		tmp = (tmp - 11) * 103 / 64;
5644299110Sadrian		if (adjust_2053)
5645299110Sadrian			tmp -= 109;
5646299110Sadrian		else
5647299110Sadrian			tmp -= 83;
5648299110Sadrian	}
5649299110Sadrian
5650299110Sadrian	return (tmp);
5651299110Sadrian}
5652299110Sadrian
5653203945Sweongyostatic void
5654203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
5655203945Sweongyo{
5656203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
5657203945Sweongyo	struct bwn_plcp6 *plcp;
5658203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5659203945Sweongyo	struct ieee80211_frame_min *wh;
5660203945Sweongyo	struct ieee80211_node *ni;
5661287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5662203945Sweongyo	uint32_t macstat;
5663204242Simp	int padding, rate, rssi = 0, noise = 0, type;
5664203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
5665203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
5666204242Simp	static int rx_mac_dec_rpt = 0;
5667203945Sweongyo
5668203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5669203945Sweongyo
5670203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
5671203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
5672299110Sadrian
5673299110Sadrian	/* XXX Note: mactime, macstat, chanstat need fixing for fw 598 */
5674203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
5675203945Sweongyo	chanstat = le16toh(rxhdr->channel);
5676299110Sadrian
5677203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
5678203945Sweongyo
5679203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
5680203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
5681203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
5682203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
5683203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
5684203945Sweongyo		goto drop;
5685203945Sweongyo
5686203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5687203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
5688204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5689204081Sweongyo		    m->m_pkthdr.len);
5690203945Sweongyo		goto drop;
5691203945Sweongyo	}
5692203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
5693203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
5694203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
5695204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5696204081Sweongyo		    m->m_pkthdr.len);
5697203945Sweongyo		goto drop;
5698203945Sweongyo	}
5699203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
5700203945Sweongyo
5701204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
5702204081Sweongyo		device_printf(sc->sc_dev,
5703204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
5704204081Sweongyo		    BWN_ISOLDFMT(mac),
5705204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
5706203945Sweongyo
5707203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
5708203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
5709203945Sweongyo		    phytype == BWN_PHYTYPE_A);
5710203945Sweongyo	else
5711203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
5712203945Sweongyo	if (rate == -1) {
5713203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
5714203945Sweongyo			goto drop;
5715203945Sweongyo	}
5716203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
5717203945Sweongyo
5718299110Sadrian	/* rssi/noise */
5719299110Sadrian	switch (phytype) {
5720299110Sadrian	case BWN_PHYTYPE_A:
5721299110Sadrian	case BWN_PHYTYPE_B:
5722299110Sadrian	case BWN_PHYTYPE_G:
5723299110Sadrian	case BWN_PHYTYPE_LP:
5724299110Sadrian		rssi = bwn_rx_rssi_calc(mac, rxhdr->phy.abg.rssi,
5725299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_OFDM),
5726299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_GAINCTL),
5727299110Sadrian		    !! (phystat3 & BWN_RX_PHYST3_TRSTATE));
5728299110Sadrian		break;
5729299795Sadrian	case BWN_PHYTYPE_N:
5730299795Sadrian		/* Broadcom has code for min/avg, but always used max */
5731299795Sadrian		if (rxhdr->phy.n.power0 == 16 || rxhdr->phy.n.power0 == 32)
5732299795Sadrian			rssi = max(rxhdr->phy.n.power1, rxhdr->ps2.n.power2);
5733299795Sadrian		else
5734299795Sadrian			rssi = max(rxhdr->phy.n.power0, rxhdr->phy.n.power1);
5735299795Sadrian		break;
5736299110Sadrian	default:
5737299110Sadrian		/* XXX TODO: implement rssi for other PHYs */
5738299110Sadrian		break;
5739299110Sadrian	}
5740299110Sadrian
5741299110Sadrian	noise = mac->mac_stats.link_noise;
5742299110Sadrian
5743203945Sweongyo	/* RX radio tap */
5744203945Sweongyo	if (ieee80211_radiotap_active(ic))
5745203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
5746203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
5747203945Sweongyo
5748203945Sweongyo	BWN_UNLOCK(sc);
5749203945Sweongyo
5750203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
5751203945Sweongyo	if (ni != NULL) {
5752203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
5753203945Sweongyo		ieee80211_free_node(ni);
5754203945Sweongyo	} else
5755203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
5756203945Sweongyo
5757203945Sweongyo	BWN_LOCK(sc);
5758203945Sweongyo	return;
5759203945Sweongyodrop:
5760203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
5761203945Sweongyo}
5762203945Sweongyo
5763203945Sweongyostatic void
5764203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
5765203945Sweongyo    const struct bwn_txstatus *status)
5766203945Sweongyo{
5767203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5768203945Sweongyo	struct bwn_dma_ring *dr;
5769203945Sweongyo	struct bwn_dmadesc_generic *desc;
5770203945Sweongyo	struct bwn_dmadesc_meta *meta;
5771203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5772203945Sweongyo	int slot;
5773299032Sadrian	int retrycnt = 0;
5774203945Sweongyo
5775203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5776203945Sweongyo
5777203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
5778203945Sweongyo	if (dr == NULL) {
5779203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
5780203945Sweongyo		return;
5781203945Sweongyo	}
5782203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
5783203945Sweongyo
5784203945Sweongyo	while (1) {
5785203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
5786203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5787203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
5788203945Sweongyo
5789203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
5790203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
5791203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
5792203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
5793203945Sweongyo
5794203945Sweongyo		if (meta->mt_islast) {
5795203945Sweongyo			KASSERT(meta->mt_m != NULL,
5796203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5797203945Sweongyo
5798299782Sadrian			/*
5799299782Sadrian			 * If we don't get an ACK, then we should log the
5800299782Sadrian			 * full framecnt.  That may be 0 if it's a PHY
5801299782Sadrian			 * failure, so ensure that gets logged as some
5802299782Sadrian			 * retry attempt.
5803299782Sadrian			 */
5804299782Sadrian			if (status->ack) {
5805299782Sadrian				retrycnt = status->framecnt - 1;
5806299782Sadrian			} else {
5807299782Sadrian				retrycnt = status->framecnt;
5808299782Sadrian				if (retrycnt == 0)
5809299782Sadrian					retrycnt = 1;
5810299782Sadrian			}
5811299032Sadrian			ieee80211_ratectl_tx_complete(meta->mt_ni->ni_vap, meta->mt_ni,
5812299032Sadrian			    status->ack ?
5813299032Sadrian			      IEEE80211_RATECTL_TX_SUCCESS :
5814299032Sadrian			      IEEE80211_RATECTL_TX_FAILURE,
5815299032Sadrian			    &retrycnt, 0);
5816287197Sglebius			ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
5817287197Sglebius			meta->mt_ni = NULL;
5818203945Sweongyo			meta->mt_m = NULL;
5819287197Sglebius		} else
5820203945Sweongyo			KASSERT(meta->mt_m == NULL,
5821203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5822203945Sweongyo
5823203945Sweongyo		dr->dr_usedslot--;
5824287197Sglebius		if (meta->mt_islast)
5825203945Sweongyo			break;
5826203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
5827203945Sweongyo	}
5828203945Sweongyo	sc->sc_watchdog_timer = 0;
5829203945Sweongyo	if (dr->dr_stop) {
5830203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
5831203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5832203945Sweongyo		dr->dr_stop = 0;
5833203945Sweongyo	}
5834203945Sweongyo}
5835203945Sweongyo
5836203945Sweongyostatic void
5837203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
5838203945Sweongyo    const struct bwn_txstatus *status)
5839203945Sweongyo{
5840203945Sweongyo	struct bwn_pio_txqueue *tq;
5841203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
5842203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5843299032Sadrian	int retrycnt = 0;
5844203945Sweongyo
5845203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5846203945Sweongyo
5847203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
5848203945Sweongyo	if (tq == NULL)
5849203945Sweongyo		return;
5850203945Sweongyo
5851203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
5852203945Sweongyo	tq->tq_free++;
5853203945Sweongyo
5854203945Sweongyo	if (tp->tp_ni != NULL) {
5855203945Sweongyo		/*
5856203945Sweongyo		 * Do any tx complete callback.  Note this must
5857203945Sweongyo		 * be done before releasing the node reference.
5858203945Sweongyo		 */
5859299032Sadrian
5860299782Sadrian		/*
5861299782Sadrian		 * If we don't get an ACK, then we should log the
5862299782Sadrian		 * full framecnt.  That may be 0 if it's a PHY
5863299782Sadrian		 * failure, so ensure that gets logged as some
5864299782Sadrian		 * retry attempt.
5865299782Sadrian		 */
5866299782Sadrian		if (status->ack) {
5867299782Sadrian			retrycnt = status->framecnt - 1;
5868299782Sadrian		} else {
5869299782Sadrian			retrycnt = status->framecnt;
5870299782Sadrian			if (retrycnt == 0)
5871299782Sadrian				retrycnt = 1;
5872299782Sadrian		}
5873299032Sadrian		ieee80211_ratectl_tx_complete(tp->tp_ni->ni_vap, tp->tp_ni,
5874299032Sadrian		    status->ack ?
5875299032Sadrian		      IEEE80211_RATECTL_TX_SUCCESS :
5876299032Sadrian		      IEEE80211_RATECTL_TX_FAILURE,
5877299032Sadrian		    &retrycnt, 0);
5878299032Sadrian
5879203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
5880203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
5881203945Sweongyo		ieee80211_free_node(tp->tp_ni);
5882203945Sweongyo		tp->tp_ni = NULL;
5883203945Sweongyo	}
5884203945Sweongyo	m_freem(tp->tp_m);
5885203945Sweongyo	tp->tp_m = NULL;
5886203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
5887203945Sweongyo
5888203945Sweongyo	sc->sc_watchdog_timer = 0;
5889203945Sweongyo}
5890203945Sweongyo
5891203945Sweongyostatic void
5892203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
5893203945Sweongyo{
5894203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5895203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5896287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5897203945Sweongyo	unsigned long now;
5898299794Sadrian	bwn_txpwr_result_t result;
5899203945Sweongyo
5900203945Sweongyo	BWN_GETTIME(now);
5901203945Sweongyo
5902297409Sadrian	if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime))
5903203945Sweongyo		return;
5904203945Sweongyo	phy->nexttime = now + 2 * 1000;
5905203945Sweongyo
5906204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
5907204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
5908203945Sweongyo		return;
5909203945Sweongyo
5910203945Sweongyo	if (phy->recalc_txpwr != NULL) {
5911203945Sweongyo		result = phy->recalc_txpwr(mac,
5912203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
5913203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
5914203945Sweongyo			return;
5915203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
5916203945Sweongyo		    ("%s: fail", __func__));
5917203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
5918203945Sweongyo
5919203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
5920203945Sweongyo	}
5921203945Sweongyo}
5922203945Sweongyo
5923203945Sweongyostatic uint16_t
5924203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
5925203945Sweongyo{
5926203945Sweongyo
5927203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
5928203945Sweongyo}
5929203945Sweongyo
5930203945Sweongyostatic uint32_t
5931203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
5932203945Sweongyo{
5933203945Sweongyo
5934203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
5935203945Sweongyo}
5936203945Sweongyo
5937203945Sweongyostatic void
5938203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
5939203945Sweongyo{
5940203945Sweongyo
5941203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
5942203945Sweongyo}
5943203945Sweongyo
5944203945Sweongyostatic void
5945203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
5946203945Sweongyo{
5947203945Sweongyo
5948203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
5949203945Sweongyo}
5950203945Sweongyo
5951203945Sweongyostatic int
5952203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
5953203945Sweongyo{
5954203945Sweongyo
5955203945Sweongyo	switch (rate) {
5956203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
5957203945Sweongyo	case 12:
5958203945Sweongyo		return (BWN_OFDM_RATE_6MB);
5959203945Sweongyo	case 18:
5960203945Sweongyo		return (BWN_OFDM_RATE_9MB);
5961203945Sweongyo	case 24:
5962203945Sweongyo		return (BWN_OFDM_RATE_12MB);
5963203945Sweongyo	case 36:
5964203945Sweongyo		return (BWN_OFDM_RATE_18MB);
5965203945Sweongyo	case 48:
5966203945Sweongyo		return (BWN_OFDM_RATE_24MB);
5967203945Sweongyo	case 72:
5968203945Sweongyo		return (BWN_OFDM_RATE_36MB);
5969203945Sweongyo	case 96:
5970203945Sweongyo		return (BWN_OFDM_RATE_48MB);
5971203945Sweongyo	case 108:
5972203945Sweongyo		return (BWN_OFDM_RATE_54MB);
5973203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
5974203945Sweongyo	case 2:
5975203945Sweongyo		return (BWN_CCK_RATE_1MB);
5976203945Sweongyo	case 4:
5977203945Sweongyo		return (BWN_CCK_RATE_2MB);
5978203945Sweongyo	case 11:
5979203945Sweongyo		return (BWN_CCK_RATE_5MB);
5980203945Sweongyo	case 22:
5981203945Sweongyo		return (BWN_CCK_RATE_11MB);
5982203945Sweongyo	}
5983203945Sweongyo
5984203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
5985203945Sweongyo	return (BWN_CCK_RATE_1MB);
5986203945Sweongyo}
5987203945Sweongyo
5988203945Sweongyostatic int
5989203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
5990203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
5991203945Sweongyo{
5992203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
5993203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5994203945Sweongyo	struct ieee80211_frame *wh;
5995203945Sweongyo	struct ieee80211_frame *protwh;
5996203945Sweongyo	struct ieee80211_frame_cts *cts;
5997203945Sweongyo	struct ieee80211_frame_rts *rts;
5998203945Sweongyo	const struct ieee80211_txparam *tp;
5999203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
6000287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
6001203945Sweongyo	struct mbuf *mprot;
6002203945Sweongyo	unsigned int len;
6003203945Sweongyo	uint32_t macctl = 0;
6004203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
6005203945Sweongyo	uint16_t phyctl = 0;
6006203945Sweongyo	uint8_t rate, rate_fb;
6007203945Sweongyo
6008203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
6009203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
6010203945Sweongyo
6011203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
6012203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
6013203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
6014203945Sweongyo
6015203945Sweongyo	/*
6016203945Sweongyo	 * Find TX rate
6017203945Sweongyo	 */
6018203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
6019203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
6020203945Sweongyo		rate = rate_fb = tp->mgmtrate;
6021203945Sweongyo	else if (ismcast)
6022203945Sweongyo		rate = rate_fb = tp->mcastrate;
6023203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
6024203945Sweongyo		rate = rate_fb = tp->ucastrate;
6025203945Sweongyo	else {
6026299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
6027206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
6028203945Sweongyo		rate = ni->ni_txrate;
6029203945Sweongyo
6030203945Sweongyo		if (rix > 0)
6031203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
6032203945Sweongyo			    IEEE80211_RATE_VAL;
6033203945Sweongyo		else
6034203945Sweongyo			rate_fb = rate;
6035203945Sweongyo	}
6036203945Sweongyo
6037203945Sweongyo	sc->sc_tx_rate = rate;
6038203945Sweongyo
6039299032Sadrian	/* Note: this maps the select ieee80211 rate to hardware rate */
6040203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
6041203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
6042203945Sweongyo
6043203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
6044203945Sweongyo	    bwn_plcp_getcck(rate);
6045203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
6046203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
6047203945Sweongyo
6048299032Sadrian	/* XXX rate/rate_fb is the hardware rate */
6049203945Sweongyo	if ((rate_fb == rate) ||
6050203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
6051203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
6052203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
6053203945Sweongyo	else
6054203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
6055203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
6056203945Sweongyo
6057203945Sweongyo	/* XXX TX encryption */
6058203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
6059203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
6060203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
6061203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
6062203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
6063203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
6064203945Sweongyo
6065203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
6066203945Sweongyo	    BWN_TX_EFT_FB_CCK;
6067203945Sweongyo	txhdr->chan = phy->chan;
6068203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
6069203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
6070299032Sadrian	/* XXX preamble? obey net80211 */
6071203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
6072203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
6073203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
6074203945Sweongyo
6075203945Sweongyo	/* XXX TX antenna selection */
6076203945Sweongyo
6077203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
6078203945Sweongyo	case 0:
6079203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
6080203945Sweongyo		break;
6081203945Sweongyo	case 1:
6082203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
6083203945Sweongyo		break;
6084203945Sweongyo	case 2:
6085203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
6086203945Sweongyo		break;
6087203945Sweongyo	case 3:
6088203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
6089203945Sweongyo		break;
6090203945Sweongyo	case 4:
6091203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
6092203945Sweongyo		break;
6093203945Sweongyo	default:
6094203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6095203945Sweongyo	}
6096203945Sweongyo
6097203945Sweongyo	if (!ismcast)
6098203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
6099203945Sweongyo
6100203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
6101203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
6102203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
6103203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
6104203945Sweongyo
6105203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
6106203945Sweongyo		/* XXX RTS rate is always 1MB??? */
6107299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
6108203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
6109203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
6110203945Sweongyo
6111299032Sadrian		/* XXX 'rate' here is hardware rate now, not the net80211 rate */
6112203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
6113203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
6114203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
6115203945Sweongyo
6116203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
6117203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
6118203945Sweongyo			    (txhdr->body.old.rts_frame) :
6119203945Sweongyo			    (txhdr->body.new.rts_frame));
6120203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
6121203945Sweongyo			    protdur);
6122203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
6123203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
6124203945Sweongyo			    mprot->m_pkthdr.len);
6125203945Sweongyo			m_freem(mprot);
6126203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
6127203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
6128203945Sweongyo		} else {
6129203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
6130203945Sweongyo			    (txhdr->body.old.rts_frame) :
6131203945Sweongyo			    (txhdr->body.new.rts_frame));
6132299032Sadrian			/* XXX rate/rate_fb is the hardware rate */
6133203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
6134203945Sweongyo			    isshort);
6135203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
6136203945Sweongyo			    wh->i_addr2, protdur);
6137203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
6138203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
6139203945Sweongyo			    mprot->m_pkthdr.len);
6140203945Sweongyo			m_freem(mprot);
6141203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
6142203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
6143203945Sweongyo		}
6144203945Sweongyo		len += IEEE80211_CRC_LEN;
6145203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
6146203945Sweongyo		    &txhdr->body.old.rts_plcp :
6147203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
6148203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
6149203945Sweongyo		    rts_rate_fb);
6150203945Sweongyo
6151203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
6152203945Sweongyo		    (&txhdr->body.old.rts_frame) :
6153203945Sweongyo		    (&txhdr->body.new.rts_frame));
6154203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
6155203945Sweongyo
6156203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
6157203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
6158203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
6159203945Sweongyo		} else {
6160203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
6161203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
6162203945Sweongyo		}
6163203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
6164203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
6165203945Sweongyo	}
6166203945Sweongyo
6167203945Sweongyo	if (BWN_ISOLDFMT(mac))
6168203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
6169203945Sweongyo	else
6170203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
6171203945Sweongyo
6172203945Sweongyo	txhdr->macctl = htole32(macctl);
6173203945Sweongyo	txhdr->phyctl = htole16(phyctl);
6174203945Sweongyo
6175203945Sweongyo	/*
6176203945Sweongyo	 * TX radio tap
6177203945Sweongyo	 */
6178203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
6179203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
6180260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
6181203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
6182203945Sweongyo		if (isshort &&
6183203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
6184203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
6185203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
6186203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
6187203945Sweongyo
6188203945Sweongyo		ieee80211_radiotap_tx(vap, m);
6189203945Sweongyo	}
6190203945Sweongyo
6191203945Sweongyo	return (0);
6192203945Sweongyo}
6193203945Sweongyo
6194203945Sweongyostatic void
6195203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
6196203945Sweongyo    const uint8_t rate)
6197203945Sweongyo{
6198203945Sweongyo	uint32_t d, plen;
6199203945Sweongyo	uint8_t *raw = plcp->o.raw;
6200203945Sweongyo
6201203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
6202203945Sweongyo		d = bwn_plcp_getofdm(rate);
6203203945Sweongyo		KASSERT(!(octets & 0xf000),
6204203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6205203945Sweongyo		d |= (octets << 5);
6206203945Sweongyo		plcp->o.data = htole32(d);
6207203945Sweongyo	} else {
6208203945Sweongyo		plen = octets * 16 / rate;
6209203945Sweongyo		if ((octets * 16 % rate) > 0) {
6210203945Sweongyo			plen++;
6211203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
6212203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
6213203945Sweongyo				raw[1] = 0x84;
6214203945Sweongyo			} else
6215203945Sweongyo				raw[1] = 0x04;
6216203945Sweongyo		} else
6217203945Sweongyo			raw[1] = 0x04;
6218203945Sweongyo		plcp->o.data |= htole32(plen << 16);
6219203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
6220203945Sweongyo	}
6221203945Sweongyo}
6222203945Sweongyo
6223203945Sweongyostatic uint8_t
6224203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
6225203945Sweongyo{
6226204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6227203945Sweongyo	uint8_t mask;
6228203945Sweongyo
6229203945Sweongyo	if (n == 0)
6230203945Sweongyo		return (0);
6231203945Sweongyo	if (mac->mac_phy.gmode)
6232204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
6233203945Sweongyo	else
6234204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
6235203945Sweongyo	if (!(mask & (1 << (n - 1))))
6236203945Sweongyo		return (0);
6237203945Sweongyo	return (n);
6238203945Sweongyo}
6239203945Sweongyo
6240299028Sadrian/*
6241299028Sadrian * Return a fallback rate for the given rate.
6242299028Sadrian *
6243299028Sadrian * Note: Don't fall back from OFDM to CCK.
6244299028Sadrian */
6245203945Sweongyostatic uint8_t
6246203945Sweongyobwn_get_fbrate(uint8_t bitrate)
6247203945Sweongyo{
6248203945Sweongyo	switch (bitrate) {
6249299028Sadrian	/* CCK */
6250203945Sweongyo	case BWN_CCK_RATE_1MB:
6251203945Sweongyo		return (BWN_CCK_RATE_1MB);
6252203945Sweongyo	case BWN_CCK_RATE_2MB:
6253203945Sweongyo		return (BWN_CCK_RATE_1MB);
6254203945Sweongyo	case BWN_CCK_RATE_5MB:
6255203945Sweongyo		return (BWN_CCK_RATE_2MB);
6256203945Sweongyo	case BWN_CCK_RATE_11MB:
6257203945Sweongyo		return (BWN_CCK_RATE_5MB);
6258299028Sadrian
6259299028Sadrian	/* OFDM */
6260203945Sweongyo	case BWN_OFDM_RATE_6MB:
6261299028Sadrian		return (BWN_OFDM_RATE_6MB);
6262203945Sweongyo	case BWN_OFDM_RATE_9MB:
6263203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6264203945Sweongyo	case BWN_OFDM_RATE_12MB:
6265203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6266203945Sweongyo	case BWN_OFDM_RATE_18MB:
6267203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6268203945Sweongyo	case BWN_OFDM_RATE_24MB:
6269203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6270203945Sweongyo	case BWN_OFDM_RATE_36MB:
6271203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6272203945Sweongyo	case BWN_OFDM_RATE_48MB:
6273203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6274203945Sweongyo	case BWN_OFDM_RATE_54MB:
6275203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6276203945Sweongyo	}
6277203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6278203945Sweongyo	return (0);
6279203945Sweongyo}
6280203945Sweongyo
6281203945Sweongyostatic uint32_t
6282203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6283203945Sweongyo    uint32_t ctl, const void *_data, int len)
6284203945Sweongyo{
6285204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6286203945Sweongyo	uint32_t value = 0;
6287203945Sweongyo	const uint8_t *data = _data;
6288203945Sweongyo
6289203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
6290203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
6291203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6292203945Sweongyo
6293204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
6294203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
6295203945Sweongyo	if (len & 3) {
6296203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
6297203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
6298203945Sweongyo		data = &(data[len - 1]);
6299203945Sweongyo		switch (len & 3) {
6300203945Sweongyo		case 3:
6301203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
6302203945Sweongyo			value |= (uint32_t)(*data) << 16;
6303203945Sweongyo			data--;
6304203945Sweongyo		case 2:
6305203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
6306203945Sweongyo			value |= (uint32_t)(*data) << 8;
6307203945Sweongyo			data--;
6308203945Sweongyo		case 1:
6309203945Sweongyo			value |= (uint32_t)(*data);
6310203945Sweongyo		}
6311203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6312203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
6313203945Sweongyo	}
6314203945Sweongyo
6315203945Sweongyo	return (ctl);
6316203945Sweongyo}
6317203945Sweongyo
6318203945Sweongyostatic void
6319203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6320203945Sweongyo    uint16_t offset, uint32_t value)
6321203945Sweongyo{
6322203945Sweongyo
6323203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
6324203945Sweongyo}
6325203945Sweongyo
6326203945Sweongyostatic uint16_t
6327203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6328203945Sweongyo    uint16_t ctl, const void *_data, int len)
6329203945Sweongyo{
6330204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6331203945Sweongyo	const uint8_t *data = _data;
6332203945Sweongyo
6333203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6334203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6335203945Sweongyo
6336204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
6337203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
6338203945Sweongyo	if (len & 1) {
6339203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6340203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6341203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
6342203945Sweongyo	}
6343203945Sweongyo
6344203945Sweongyo	return (ctl);
6345203945Sweongyo}
6346203945Sweongyo
6347203945Sweongyostatic uint16_t
6348203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6349203945Sweongyo    uint16_t ctl, struct mbuf *m0)
6350203945Sweongyo{
6351203945Sweongyo	int i, j = 0;
6352203945Sweongyo	uint16_t data = 0;
6353203945Sweongyo	const uint8_t *buf;
6354203945Sweongyo	struct mbuf *m = m0;
6355203945Sweongyo
6356203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6357203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6358203945Sweongyo
6359203945Sweongyo	for (; m != NULL; m = m->m_next) {
6360203945Sweongyo		buf = mtod(m, const uint8_t *);
6361203945Sweongyo		for (i = 0; i < m->m_len; i++) {
6362203945Sweongyo			if (!((j++) % 2))
6363203945Sweongyo				data |= buf[i];
6364203945Sweongyo			else {
6365203945Sweongyo				data |= (buf[i] << 8);
6366203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6367203945Sweongyo				data = 0;
6368203945Sweongyo			}
6369203945Sweongyo		}
6370203945Sweongyo	}
6371203945Sweongyo	if (m0->m_pkthdr.len % 2) {
6372203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6373203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6374203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6375203945Sweongyo	}
6376203945Sweongyo
6377203945Sweongyo	return (ctl);
6378203945Sweongyo}
6379203945Sweongyo
6380203945Sweongyostatic void
6381203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
6382203945Sweongyo{
6383203945Sweongyo
6384203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
6385203945Sweongyo		return;
6386203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
6387203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
6388203945Sweongyo}
6389203945Sweongyo
6390203945Sweongyostatic struct bwn_dma_ring *
6391203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
6392203945Sweongyo{
6393203945Sweongyo
6394203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
6395203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6396203945Sweongyo
6397203945Sweongyo	switch (prio) {
6398203945Sweongyo	case 3:
6399203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
6400203945Sweongyo	case 2:
6401203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
6402203945Sweongyo	case 0:
6403203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6404203945Sweongyo	case 1:
6405203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
6406203945Sweongyo	}
6407203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6408204242Simp	return (NULL);
6409203945Sweongyo}
6410203945Sweongyo
6411203945Sweongyostatic int
6412203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
6413203945Sweongyo{
6414203945Sweongyo	int slot;
6415203945Sweongyo
6416204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
6417203945Sweongyo
6418203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
6419203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
6420203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
6421203945Sweongyo
6422203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
6423203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
6424203945Sweongyo	dr->dr_curslot = slot;
6425203945Sweongyo	dr->dr_usedslot++;
6426203945Sweongyo
6427203945Sweongyo	return (slot);
6428203945Sweongyo}
6429203945Sweongyo
6430203945Sweongyostatic struct bwn_pio_txqueue *
6431203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
6432203945Sweongyo    struct bwn_pio_txpkt **pack)
6433203945Sweongyo{
6434203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
6435203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
6436203945Sweongyo	unsigned int index;
6437203945Sweongyo
6438203945Sweongyo	switch (cookie & 0xf000) {
6439203945Sweongyo	case 0x1000:
6440203945Sweongyo		tq = &pio->wme[WME_AC_BK];
6441203945Sweongyo		break;
6442203945Sweongyo	case 0x2000:
6443203945Sweongyo		tq = &pio->wme[WME_AC_BE];
6444203945Sweongyo		break;
6445203945Sweongyo	case 0x3000:
6446203945Sweongyo		tq = &pio->wme[WME_AC_VI];
6447203945Sweongyo		break;
6448203945Sweongyo	case 0x4000:
6449203945Sweongyo		tq = &pio->wme[WME_AC_VO];
6450203945Sweongyo		break;
6451203945Sweongyo	case 0x5000:
6452203945Sweongyo		tq = &pio->mcast;
6453203945Sweongyo		break;
6454203945Sweongyo	}
6455203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
6456203945Sweongyo	if (tq == NULL)
6457203945Sweongyo		return (NULL);
6458203945Sweongyo	index = (cookie & 0x0fff);
6459203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
6460203945Sweongyo	if (index >= N(tq->tq_pkts))
6461203945Sweongyo		return (NULL);
6462203945Sweongyo	*pack = &tq->tq_pkts[index];
6463203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
6464203945Sweongyo	return (tq);
6465203945Sweongyo}
6466203945Sweongyo
6467203945Sweongyostatic void
6468203945Sweongyobwn_txpwr(void *arg, int npending)
6469203945Sweongyo{
6470203945Sweongyo	struct bwn_mac *mac = arg;
6471203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6472203945Sweongyo
6473203945Sweongyo	BWN_LOCK(sc);
6474203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
6475203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
6476203945Sweongyo		mac->mac_phy.set_txpwr(mac);
6477203945Sweongyo	BWN_UNLOCK(sc);
6478203945Sweongyo}
6479203945Sweongyo
6480203945Sweongyostatic void
6481203945Sweongyobwn_task_15s(struct bwn_mac *mac)
6482203945Sweongyo{
6483203945Sweongyo	uint16_t reg;
6484203945Sweongyo
6485203945Sweongyo	if (mac->mac_fw.opensource) {
6486203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
6487203945Sweongyo		if (reg) {
6488203945Sweongyo			bwn_restart(mac, "fw watchdog");
6489203945Sweongyo			return;
6490203945Sweongyo		}
6491203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
6492203945Sweongyo	}
6493203945Sweongyo	if (mac->mac_phy.task_15s)
6494203945Sweongyo		mac->mac_phy.task_15s(mac);
6495203945Sweongyo
6496203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
6497203945Sweongyo}
6498203945Sweongyo
6499203945Sweongyostatic void
6500203945Sweongyobwn_task_30s(struct bwn_mac *mac)
6501203945Sweongyo{
6502203945Sweongyo
6503203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
6504203945Sweongyo		return;
6505203945Sweongyo	mac->mac_noise.noi_running = 1;
6506203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
6507203945Sweongyo
6508203945Sweongyo	bwn_noise_gensample(mac);
6509203945Sweongyo}
6510203945Sweongyo
6511203945Sweongyostatic void
6512203945Sweongyobwn_task_60s(struct bwn_mac *mac)
6513203945Sweongyo{
6514203945Sweongyo
6515203945Sweongyo	if (mac->mac_phy.task_60s)
6516203945Sweongyo		mac->mac_phy.task_60s(mac);
6517203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
6518203945Sweongyo}
6519203945Sweongyo
6520203945Sweongyostatic void
6521203945Sweongyobwn_tasks(void *arg)
6522203945Sweongyo{
6523203945Sweongyo	struct bwn_mac *mac = arg;
6524203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6525203945Sweongyo
6526203945Sweongyo	BWN_ASSERT_LOCKED(sc);
6527203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
6528203945Sweongyo		return;
6529203945Sweongyo
6530203945Sweongyo	if (mac->mac_task_state % 4 == 0)
6531203945Sweongyo		bwn_task_60s(mac);
6532203945Sweongyo	if (mac->mac_task_state % 2 == 0)
6533203945Sweongyo		bwn_task_30s(mac);
6534203945Sweongyo	bwn_task_15s(mac);
6535203945Sweongyo
6536203945Sweongyo	mac->mac_task_state++;
6537203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
6538203945Sweongyo}
6539203945Sweongyo
6540203945Sweongyostatic int
6541203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
6542203945Sweongyo{
6543203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6544203945Sweongyo
6545203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
6546203945Sweongyo
6547203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
6548203945Sweongyo	case 0xb:
6549203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6550203945Sweongyo	case 0xf:
6551203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6552203945Sweongyo	case 0xa:
6553203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6554203945Sweongyo	case 0xe:
6555203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6556203945Sweongyo	case 0x9:
6557203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6558203945Sweongyo	case 0xd:
6559203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6560203945Sweongyo	case 0x8:
6561203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6562203945Sweongyo	case 0xc:
6563203945Sweongyo		return (BWN_OFDM_RATE_54MB);
6564203945Sweongyo	}
6565203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
6566203945Sweongyo	    plcp->o.raw[0] & 0xf);
6567203945Sweongyo	return (-1);
6568203945Sweongyo}
6569203945Sweongyo
6570203945Sweongyostatic int
6571203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
6572203945Sweongyo{
6573203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6574203945Sweongyo
6575203945Sweongyo	switch (plcp->o.raw[0]) {
6576203945Sweongyo	case 0x0a:
6577203945Sweongyo		return (BWN_CCK_RATE_1MB);
6578203945Sweongyo	case 0x14:
6579203945Sweongyo		return (BWN_CCK_RATE_2MB);
6580203945Sweongyo	case 0x37:
6581203945Sweongyo		return (BWN_CCK_RATE_5MB);
6582203945Sweongyo	case 0x6e:
6583203945Sweongyo		return (BWN_CCK_RATE_11MB);
6584203945Sweongyo	}
6585203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
6586203945Sweongyo	return (-1);
6587203945Sweongyo}
6588203945Sweongyo
6589203945Sweongyostatic void
6590203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
6591203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
6592203945Sweongyo    int rssi, int noise)
6593203945Sweongyo{
6594203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6595203945Sweongyo	const struct ieee80211_frame_min *wh;
6596203945Sweongyo	uint64_t tsf;
6597203945Sweongyo	uint16_t low_mactime_now;
6598203945Sweongyo
6599203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
6600203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
6601203945Sweongyo
6602203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
6603260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
6604203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
6605203945Sweongyo
6606203945Sweongyo	bwn_tsf_read(mac, &tsf);
6607203945Sweongyo	low_mactime_now = tsf;
6608203945Sweongyo	tsf = tsf & ~0xffffULL;
6609203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
6610203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
6611203945Sweongyo		tsf -= 0x10000;
6612203945Sweongyo
6613203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
6614203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
6615203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
6616203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
6617203945Sweongyo}
6618203945Sweongyo
6619203945Sweongyostatic void
6620203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
6621203945Sweongyo{
6622203945Sweongyo	uint32_t low, high;
6623203945Sweongyo
6624204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
6625203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6626203945Sweongyo
6627203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
6628203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
6629203945Sweongyo	*tsf = high;
6630203945Sweongyo	*tsf <<= 32;
6631203945Sweongyo	*tsf |= low;
6632203945Sweongyo}
6633203945Sweongyo
6634203945Sweongyostatic int
6635203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
6636203945Sweongyo{
6637203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
6638203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6639203945Sweongyo	bus_addr_t lowaddr = 0;
6640203945Sweongyo	int error;
6641203945Sweongyo
6642204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
6643203945Sweongyo		return (0);
6644203945Sweongyo
6645204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
6646203945Sweongyo
6647203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
6648203945Sweongyo
6649203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
6650203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
6651203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
6652203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
6653203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
6654203945Sweongyo	else
6655203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
6656203945Sweongyo
6657203945Sweongyo	/*
6658203945Sweongyo	 * Create top level DMA tag
6659203945Sweongyo	 */
6660203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
6661203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
6662203945Sweongyo			       lowaddr,			/* lowaddr */
6663203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
6664203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
6665280347Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
6666203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
6667203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
6668203945Sweongyo			       0,			/* flags */
6669203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
6670203945Sweongyo			       &dma->parent_dtag);
6671203945Sweongyo	if (error) {
6672203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
6673203945Sweongyo		return (error);
6674203945Sweongyo	}
6675203945Sweongyo
6676203945Sweongyo	/*
6677203945Sweongyo	 * Create TX/RX mbuf DMA tag
6678203945Sweongyo	 */
6679203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6680203945Sweongyo				1,
6681203945Sweongyo				0,
6682203945Sweongyo				BUS_SPACE_MAXADDR,
6683203945Sweongyo				BUS_SPACE_MAXADDR,
6684203945Sweongyo				NULL, NULL,
6685203945Sweongyo				MCLBYTES,
6686203945Sweongyo				1,
6687203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6688203945Sweongyo				0,
6689203945Sweongyo				NULL, NULL,
6690203945Sweongyo				&dma->rxbuf_dtag);
6691203945Sweongyo	if (error) {
6692203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
6693203945Sweongyo		goto fail0;
6694203945Sweongyo	}
6695203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6696203945Sweongyo				1,
6697203945Sweongyo				0,
6698203945Sweongyo				BUS_SPACE_MAXADDR,
6699203945Sweongyo				BUS_SPACE_MAXADDR,
6700203945Sweongyo				NULL, NULL,
6701203945Sweongyo				MCLBYTES,
6702203945Sweongyo				1,
6703203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6704203945Sweongyo				0,
6705203945Sweongyo				NULL, NULL,
6706203945Sweongyo				&dma->txbuf_dtag);
6707203945Sweongyo	if (error) {
6708203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
6709203945Sweongyo		goto fail1;
6710203945Sweongyo	}
6711203945Sweongyo
6712203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
6713203945Sweongyo	if (!dma->wme[WME_AC_BK])
6714203945Sweongyo		goto fail2;
6715203945Sweongyo
6716203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
6717203945Sweongyo	if (!dma->wme[WME_AC_BE])
6718203945Sweongyo		goto fail3;
6719203945Sweongyo
6720203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
6721203945Sweongyo	if (!dma->wme[WME_AC_VI])
6722203945Sweongyo		goto fail4;
6723203945Sweongyo
6724203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
6725203945Sweongyo	if (!dma->wme[WME_AC_VO])
6726203945Sweongyo		goto fail5;
6727203945Sweongyo
6728203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
6729203945Sweongyo	if (!dma->mcast)
6730203945Sweongyo		goto fail6;
6731203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
6732203945Sweongyo	if (!dma->rx)
6733203945Sweongyo		goto fail7;
6734203945Sweongyo
6735203945Sweongyo	return (error);
6736203945Sweongyo
6737203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
6738203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
6739203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
6740203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
6741203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
6742203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
6743203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
6744203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
6745203945Sweongyo	return (error);
6746203945Sweongyo}
6747203945Sweongyo
6748203945Sweongyostatic struct bwn_dma_ring *
6749203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
6750203945Sweongyo    uint16_t cookie, int *slot)
6751203945Sweongyo{
6752203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
6753203945Sweongyo	struct bwn_dma_ring *dr;
6754203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6755203945Sweongyo
6756203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
6757203945Sweongyo
6758203945Sweongyo	switch (cookie & 0xf000) {
6759203945Sweongyo	case 0x1000:
6760203945Sweongyo		dr = dma->wme[WME_AC_BK];
6761203945Sweongyo		break;
6762203945Sweongyo	case 0x2000:
6763203945Sweongyo		dr = dma->wme[WME_AC_BE];
6764203945Sweongyo		break;
6765203945Sweongyo	case 0x3000:
6766203945Sweongyo		dr = dma->wme[WME_AC_VI];
6767203945Sweongyo		break;
6768203945Sweongyo	case 0x4000:
6769203945Sweongyo		dr = dma->wme[WME_AC_VO];
6770203945Sweongyo		break;
6771203945Sweongyo	case 0x5000:
6772203945Sweongyo		dr = dma->mcast;
6773203945Sweongyo		break;
6774203945Sweongyo	default:
6775204242Simp		dr = NULL;
6776203945Sweongyo		KASSERT(0 == 1,
6777203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
6778203945Sweongyo	}
6779203945Sweongyo	*slot = (cookie & 0x0fff);
6780203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
6781203945Sweongyo		/*
6782203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
6783203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
6784203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
6785203945Sweongyo		 */
6786203945Sweongyo		KASSERT(status->seq == dma->lastseq,
6787203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6788203945Sweongyo		device_printf(sc->sc_dev,
6789203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
6790203945Sweongyo		    dr->dr_numslots);
6791203945Sweongyo		return (NULL);
6792203945Sweongyo	}
6793203945Sweongyo	dma->lastseq = status->seq;
6794203945Sweongyo	return (dr);
6795203945Sweongyo}
6796203945Sweongyo
6797203945Sweongyostatic void
6798203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
6799203945Sweongyo{
6800203945Sweongyo	struct bwn_dma *dma;
6801203945Sweongyo
6802203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
6803203945Sweongyo		return;
6804203945Sweongyo	dma = &mac->mac_method.dma;
6805203945Sweongyo
6806203945Sweongyo	bwn_dma_ringstop(&dma->rx);
6807203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
6808203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
6809203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
6810203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
6811203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
6812203945Sweongyo}
6813203945Sweongyo
6814203945Sweongyostatic void
6815203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
6816203945Sweongyo{
6817203945Sweongyo
6818203945Sweongyo	if (dr == NULL)
6819203945Sweongyo		return;
6820203945Sweongyo
6821203945Sweongyo	bwn_dma_cleanup(*dr);
6822203945Sweongyo}
6823203945Sweongyo
6824203945Sweongyostatic void
6825203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
6826203945Sweongyo{
6827203945Sweongyo	struct bwn_pio *pio;
6828203945Sweongyo
6829203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
6830203945Sweongyo		return;
6831203945Sweongyo	pio = &mac->mac_method.pio;
6832203945Sweongyo
6833203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
6834203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
6835203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
6836203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
6837203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
6838203945Sweongyo}
6839203945Sweongyo
6840203945Sweongyostatic void
6841203945Sweongyobwn_led_attach(struct bwn_mac *mac)
6842203945Sweongyo{
6843203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6844203945Sweongyo	const uint8_t *led_act = NULL;
6845203945Sweongyo	uint16_t val[BWN_LED_MAX];
6846203945Sweongyo	int i;
6847203945Sweongyo
6848203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
6849203945Sweongyo	sc->sc_led_blink = 1;
6850203945Sweongyo
6851203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
6852204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
6853204922Sweongyo		    bwn_vendor_led_act[i].vid) {
6854203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
6855203945Sweongyo			break;
6856203945Sweongyo		}
6857203945Sweongyo	}
6858203945Sweongyo	if (led_act == NULL)
6859203945Sweongyo		led_act = bwn_default_led_act;
6860203945Sweongyo
6861204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
6862204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
6863204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
6864204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
6865203945Sweongyo
6866203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
6867203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
6868203945Sweongyo
6869203945Sweongyo		if (val[i] == 0xff) {
6870203945Sweongyo			led->led_act = led_act[i];
6871203945Sweongyo		} else {
6872203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
6873203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
6874203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
6875203945Sweongyo		}
6876203945Sweongyo		led->led_mask = (1 << i);
6877203945Sweongyo
6878203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
6879203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
6880203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
6881203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
6882203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
6883203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
6884203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
6885203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
6886203945Sweongyo
6887203945Sweongyo			if (sc->sc_blink_led == NULL) {
6888203945Sweongyo				sc->sc_blink_led = led;
6889203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
6890203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
6891203945Sweongyo			}
6892203945Sweongyo		}
6893203945Sweongyo
6894203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
6895203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
6896203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
6897203945Sweongyo	}
6898203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
6899203945Sweongyo}
6900203945Sweongyo
6901203945Sweongyostatic __inline uint16_t
6902203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
6903203945Sweongyo{
6904203945Sweongyo
6905203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
6906203945Sweongyo		on = !on;
6907203945Sweongyo	if (on)
6908203945Sweongyo		val |= led->led_mask;
6909203945Sweongyo	else
6910203945Sweongyo		val &= ~led->led_mask;
6911203945Sweongyo	return val;
6912203945Sweongyo}
6913203945Sweongyo
6914203945Sweongyostatic void
6915203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
6916203945Sweongyo{
6917203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6918287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
6919203945Sweongyo	uint16_t val;
6920203945Sweongyo	int i;
6921203945Sweongyo
6922203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
6923203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
6924203945Sweongyo		sc->sc_led_blinking = 0;
6925203945Sweongyo	}
6926203945Sweongyo
6927287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0)
6928203945Sweongyo		return;
6929203945Sweongyo
6930203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
6931203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
6932203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
6933203945Sweongyo		int on;
6934203945Sweongyo
6935203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
6936203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
6937203945Sweongyo			continue;
6938203945Sweongyo
6939203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
6940203945Sweongyo		    nstate != IEEE80211_S_INIT)
6941203945Sweongyo			continue;
6942203945Sweongyo
6943203945Sweongyo		switch (led->led_act) {
6944203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
6945203945Sweongyo			on = 1;
6946203945Sweongyo			break;
6947203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
6948203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
6949203945Sweongyo			on = 0;
6950203945Sweongyo			break;
6951203945Sweongyo		default:
6952203945Sweongyo			on = 1;
6953203945Sweongyo			switch (nstate) {
6954203945Sweongyo			case IEEE80211_S_INIT:
6955203945Sweongyo				on = 0;
6956203945Sweongyo				break;
6957203945Sweongyo			case IEEE80211_S_RUN:
6958203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
6959203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
6960203945Sweongyo					on = 0;
6961203945Sweongyo				break;
6962203945Sweongyo			default:
6963203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
6964203945Sweongyo					on = 0;
6965203945Sweongyo				break;
6966203945Sweongyo			}
6967203945Sweongyo			break;
6968203945Sweongyo		}
6969203945Sweongyo
6970203945Sweongyo		val = bwn_led_onoff(led, val, on);
6971203945Sweongyo	}
6972203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
6973203945Sweongyo}
6974203945Sweongyo
6975203945Sweongyostatic void
6976203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
6977203945Sweongyo{
6978203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6979204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
6980204922Sweongyo	int rate;
6981203945Sweongyo
6982204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
6983204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
6984204922Sweongyo			return;
6985204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
6986204922Sweongyo			return;
6987204922Sweongyo	}
6988203945Sweongyo
6989204922Sweongyo	sc->sc_led_ticks = ticks;
6990204922Sweongyo	if (sc->sc_led_blinking)
6991204922Sweongyo		return;
6992203945Sweongyo
6993204922Sweongyo	switch (event) {
6994204922Sweongyo	case BWN_LED_EVENT_RX:
6995204922Sweongyo		rate = sc->sc_rx_rate;
6996204922Sweongyo		break;
6997204922Sweongyo	case BWN_LED_EVENT_TX:
6998204922Sweongyo		rate = sc->sc_tx_rate;
6999204922Sweongyo		break;
7000204922Sweongyo	case BWN_LED_EVENT_POLL:
7001204922Sweongyo		rate = 0;
7002204922Sweongyo		break;
7003204922Sweongyo	default:
7004204922Sweongyo		panic("unknown LED event %d\n", event);
7005204922Sweongyo		break;
7006204922Sweongyo	}
7007204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
7008204922Sweongyo	    bwn_led_duration[rate].off_dur);
7009203945Sweongyo}
7010203945Sweongyo
7011203945Sweongyostatic void
7012203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
7013203945Sweongyo{
7014203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7015204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
7016204922Sweongyo	uint16_t val;
7017203945Sweongyo
7018204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
7019204922Sweongyo	val = bwn_led_onoff(led, val, 1);
7020204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
7021203945Sweongyo
7022204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
7023204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
7024204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
7025204922Sweongyo	}
7026203945Sweongyo
7027204922Sweongyo	sc->sc_led_blinking = 1;
7028204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
7029203945Sweongyo
7030204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
7031203945Sweongyo}
7032203945Sweongyo
7033203945Sweongyostatic void
7034203945Sweongyobwn_led_blink_next(void *arg)
7035203945Sweongyo{
7036203945Sweongyo	struct bwn_mac *mac = arg;
7037204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7038204922Sweongyo	uint16_t val;
7039203945Sweongyo
7040204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
7041204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
7042204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
7043203945Sweongyo
7044204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
7045204922Sweongyo	    bwn_led_blink_end, mac);
7046203945Sweongyo}
7047203945Sweongyo
7048203945Sweongyostatic void
7049203945Sweongyobwn_led_blink_end(void *arg)
7050203945Sweongyo{
7051203945Sweongyo	struct bwn_mac *mac = arg;
7052204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7053203945Sweongyo
7054204922Sweongyo	sc->sc_led_blinking = 0;
7055203945Sweongyo}
7056203945Sweongyo
7057203945Sweongyostatic int
7058203945Sweongyobwn_suspend(device_t dev)
7059203945Sweongyo{
7060203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
7061203945Sweongyo
7062287197Sglebius	BWN_LOCK(sc);
7063287197Sglebius	bwn_stop(sc);
7064287197Sglebius	BWN_UNLOCK(sc);
7065203945Sweongyo	return (0);
7066203945Sweongyo}
7067203945Sweongyo
7068203945Sweongyostatic int
7069203945Sweongyobwn_resume(device_t dev)
7070203945Sweongyo{
7071203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
7072287197Sglebius	int error = EDOOFUS;
7073203945Sweongyo
7074287197Sglebius	BWN_LOCK(sc);
7075287197Sglebius	if (sc->sc_ic.ic_nrunning > 0)
7076287197Sglebius		error = bwn_init(sc);
7077287197Sglebius	BWN_UNLOCK(sc);
7078287197Sglebius	if (error == 0)
7079287197Sglebius		ieee80211_start_all(&sc->sc_ic);
7080203945Sweongyo	return (0);
7081203945Sweongyo}
7082203945Sweongyo
7083203945Sweongyostatic void
7084203945Sweongyobwn_rfswitch(void *arg)
7085203945Sweongyo{
7086203945Sweongyo	struct bwn_softc *sc = arg;
7087203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
7088203945Sweongyo	int cur = 0, prev = 0;
7089203945Sweongyo
7090203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
7091203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
7092203945Sweongyo
7093285436Sadrian	if (mac->mac_phy.rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
7094203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
7095203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
7096203945Sweongyo			cur = 1;
7097203945Sweongyo	} else {
7098203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
7099203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
7100203945Sweongyo			cur = 1;
7101203945Sweongyo	}
7102203945Sweongyo
7103203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
7104203945Sweongyo		prev = 1;
7105203945Sweongyo
7106203945Sweongyo	if (cur != prev) {
7107203945Sweongyo		if (cur)
7108203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
7109203945Sweongyo		else
7110203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
7111203945Sweongyo
7112203945Sweongyo		device_printf(sc->sc_dev,
7113203945Sweongyo		    "status of RF switch is changed to %s\n",
7114203945Sweongyo		    cur ? "ON" : "OFF");
7115203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
7116203945Sweongyo			if (cur)
7117203945Sweongyo				bwn_rf_turnon(mac);
7118203945Sweongyo			else
7119203945Sweongyo				bwn_rf_turnoff(mac);
7120203945Sweongyo		}
7121203945Sweongyo	}
7122203945Sweongyo
7123203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
7124203945Sweongyo}
7125203945Sweongyo
7126203945Sweongyostatic void
7127204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
7128204257Sweongyo{
7129204257Sweongyo	device_t dev = sc->sc_dev;
7130204257Sweongyo	struct bwn_mac *mac;
7131204257Sweongyo	struct bwn_stats *stats;
7132204257Sweongyo
7133204257Sweongyo	/* XXX assume that count of MAC is only 1. */
7134204257Sweongyo
7135204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
7136204257Sweongyo		return;
7137204257Sweongyo	stats = &mac->mac_stats;
7138204257Sweongyo
7139217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7140204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7141204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
7142217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7143204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7144204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
7145217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7146204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7147204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
7148204257Sweongyo
7149204257Sweongyo#ifdef BWN_DEBUG
7150204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
7151204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7152204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
7153204257Sweongyo#endif
7154204257Sweongyo}
7155204257Sweongyo
7156203945Sweongyostatic device_method_t bwn_methods[] = {
7157203945Sweongyo	/* Device interface */
7158203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
7159203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
7160203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
7161203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
7162203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
7163227848Smarius	DEVMETHOD_END
7164203945Sweongyo};
7165203945Sweongyostatic driver_t bwn_driver = {
7166203945Sweongyo	"bwn",
7167203945Sweongyo	bwn_methods,
7168203945Sweongyo	sizeof(struct bwn_softc)
7169203945Sweongyo};
7170203945Sweongyostatic devclass_t bwn_devclass;
7171203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
7172203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
7173203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
7174203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
7175203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
7176299097SadrianMODULE_VERSION(bwn, 1);
7177