if_bwn.c revision 299131
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 299131 2016-05-05 19:40:26Z 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>
80298948Sadrian#include <dev/bwn/if_bwn_phy_g.h>
81298944Sadrian#include <dev/bwn/if_bwn_phy_lp.h>
82298944Sadrian
83227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
84227309Sed    "Broadcom driver parameters");
85203945Sweongyo
86203945Sweongyo/*
87203945Sweongyo * Tunable & sysctl variables.
88203945Sweongyo */
89203945Sweongyo
90203945Sweongyo#ifdef BWN_DEBUG
91203945Sweongyostatic	int bwn_debug = 0;
92267992ShselaskySYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0,
93203945Sweongyo    "Broadcom debugging printfs");
94203945Sweongyo#endif
95203945Sweongyo
96203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
97203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
98203945Sweongyo    "uses Bad Frames Preemption");
99203945Sweongyostatic int	bwn_bluetooth = 1;
100203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
101203945Sweongyo    "turns on Bluetooth Coexistence");
102203945Sweongyostatic int	bwn_hwpctl = 0;
103203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
104203945Sweongyo    "uses H/W power control");
105203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
106203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
107203945Sweongyostatic int	bwn_usedma = 1;
108203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
109203945Sweongyo    "uses DMA");
110203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
111203945Sweongyostatic int	bwn_wme = 1;
112203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
113203945Sweongyo    "uses WME support");
114203945Sweongyo
115287197Sglebiusstatic void	bwn_attach_pre(struct bwn_softc *);
116203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
117204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
118287197Sglebiusstatic int	bwn_init(struct bwn_softc *);
119287197Sglebiusstatic void	bwn_parent(struct ieee80211com *);
120287197Sglebiusstatic void	bwn_start(struct bwn_softc *);
121287197Sglebiusstatic int	bwn_transmit(struct ieee80211com *, struct mbuf *);
122203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
123203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
124203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
125203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
126203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
127203945Sweongyo		    uint16_t);
128203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
129203945Sweongyo		    const struct bwn_channelinfo *, int);
130203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
131203945Sweongyo		    const struct ieee80211_bpf_params *);
132283540Sglebiusstatic void	bwn_updateslot(struct ieee80211com *);
133283540Sglebiusstatic void	bwn_update_promisc(struct ieee80211com *);
134203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
135203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
136203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
137203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
138203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
139203945Sweongyo		    const struct wmeParams *, uint16_t);
140203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
141203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
142203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
143203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
144228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
145228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
146203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
147203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
148287197Sglebiusstatic void	bwn_stop(struct bwn_softc *);
149203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
150203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
151203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
152203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
153203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
154203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
155203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
156203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
157203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
158203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
159203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
160203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
161203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
162203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
163203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
164203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
165203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
166203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
167203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
168203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
169203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
170203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
171203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
172203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
173203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
174203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
175203945Sweongyo		    int);
176203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
177203945Sweongyo		    struct bwn_pio_rxqueue *, int);
178203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
179203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
180203945Sweongyo		    uint16_t);
181203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
182203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
183203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
184203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
185203945Sweongyo		    const struct bwn_txstatus *);
186203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
187203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
188203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
189203945Sweongyo		    uint16_t);
190203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
191203945Sweongyo		    uint32_t);
192203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
193203945Sweongyo		    struct mbuf *);
194203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
195203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
196203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
197203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
198203945Sweongyo		    uint16_t, uint32_t);
199203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
200203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
201203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
202203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
203203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
204203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
205203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
206203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
207203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
208203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
209203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
210203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
211203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
212203945Sweongyo		    int, struct bwn_dmadesc_generic **,
213203945Sweongyo		    struct bwn_dmadesc_meta **);
214203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
215203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
216203945Sweongyo		    int, int);
217203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
218203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
219203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
220203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
221203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
222203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
223203945Sweongyo		    int, struct bwn_dmadesc_generic **,
224203945Sweongyo		    struct bwn_dmadesc_meta **);
225203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
226203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
227203945Sweongyo		    int, int);
228203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
229203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
230203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
231203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
232203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
233203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
234203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
235203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
236203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
237203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
238203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
239203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
240203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
241203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
242203945Sweongyo		    struct bwn_dmadesc_meta *);
243203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
244203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
245203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
246203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
247203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
248203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
249203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
250203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
251203945Sweongyo		    int);
252203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
253203945Sweongyo		    bus_size_t, int);
254203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
255203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
256203945Sweongyo		    const struct bwn_txstatus *);
257203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
258203945Sweongyo		    struct mbuf *);
259203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
260203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
261203945Sweongyo		    uint8_t);
262203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
263203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
264203945Sweongyo		    int, int, int);
265203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
266203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
267203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
268203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
269203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
270203945Sweongyo		    const char *, struct bwn_fwfile *);
271203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
272203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
273203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
274203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
275203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
276203945Sweongyostatic uint16_t	bwn_ant2phy(int);
277203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
278203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
279203945Sweongyo		    const uint8_t *);
280203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
281203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
282203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
283203945Sweongyo		    const uint8_t *);
284203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
285203945Sweongyo		    const uint8_t *);
286203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
287203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
288203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
289203945Sweongyo		    struct ieee80211_channel *);
290203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
291203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
292203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
293203945Sweongyostatic int	bwn_intr(void *);
294203945Sweongyostatic void	bwn_intrtask(void *, int);
295203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
296203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
297203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
298203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
299203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
300203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
301203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
302203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
303203945Sweongyostatic void	bwn_hwreset(void *, int);
304203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
305203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
306203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
307203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
308203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
309203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
310203945Sweongyo		    const struct bwn_txstatus *);
311203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
312203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
313203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
314203945Sweongyo		    struct mbuf *);
315203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
316203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
317203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
318203945Sweongyo		    uint16_t);
319203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
320203945Sweongyo		    const uint8_t);
321203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
322203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
323203945Sweongyostatic void	bwn_txpwr(void *, int);
324203945Sweongyostatic void	bwn_tasks(void *);
325203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
326203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
327203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
328203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
329203945Sweongyo		    uint8_t);
330203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
331203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
332203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
333203945Sweongyo		    int, int);
334203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
335203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
336203945Sweongyostatic void	bwn_watchdog(void *);
337203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
338203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
339203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
340203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
341203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
342203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
343203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
344203945Sweongyostatic void	bwn_led_blink_next(void *);
345203945Sweongyostatic void	bwn_led_blink_end(void *);
346203945Sweongyostatic void	bwn_rfswitch(void *);
347203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
348203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
349204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
350203945Sweongyo
351203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
352203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
353203945Sweongyo	{ -1,			0,		0 }
354203945Sweongyo};
355203945Sweongyo
356203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
357203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
358203945Sweongyo	{ -1,			0,		0 }
359203945Sweongyo};
360203945Sweongyo
361203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
362203945Sweongyo	.channels = {
363203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
364203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
365203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
366203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
367203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
368203945Sweongyo	.nchannels = 14
369203945Sweongyo};
370203945Sweongyo
371203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
372203945Sweongyo	.channels = {
373203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
374203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
375203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
376203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
377203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
378203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
379203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
380203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
381203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
382203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
383203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
384203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
385203945Sweongyo		{ 6080, 216, 30 } },
386203945Sweongyo	.nchannels = 37
387203945Sweongyo};
388203945Sweongyo
389203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
390203945Sweongyo	.channels = {
391203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
392203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
393203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
394203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
395203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
396203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
397203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
398203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
399203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
400203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
401203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
402203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
403203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
404203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
405203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
406203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
407203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
408203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
409203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
410203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
411203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
412203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
413203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
414203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
415203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
416203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
417203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
418203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
419203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
420203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
421203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
422203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
423203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
424203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
425203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
426203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
427203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
428203945Sweongyo	.nchannels = 110
429203945Sweongyo};
430203945Sweongyo
431203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
432203945Sweongyo{							\
433203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
434203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
435203945Sweongyo}
436203945Sweongyo
437203945Sweongyostatic const struct {
438203945Sweongyo	uint16_t	vid;
439203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
440203945Sweongyo} bwn_vendor_led_act[] = {
441203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
442203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
443203945Sweongyo};
444203945Sweongyo
445203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
446203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
447203945Sweongyo
448203945Sweongyo#undef VENDOR_LED_ACT
449203945Sweongyo
450203945Sweongyostatic const struct {
451203945Sweongyo	int		on_dur;
452203945Sweongyo	int		off_dur;
453203945Sweongyo} bwn_led_duration[109] = {
454203945Sweongyo	[0]	= { 400, 100 },
455203945Sweongyo	[2]	= { 150, 75 },
456203945Sweongyo	[4]	= { 90, 45 },
457203945Sweongyo	[11]	= { 66, 34 },
458203945Sweongyo	[12]	= { 53, 26 },
459203945Sweongyo	[18]	= { 42, 21 },
460203945Sweongyo	[22]	= { 35, 17 },
461203945Sweongyo	[24]	= { 32, 16 },
462203945Sweongyo	[36]	= { 21, 10 },
463203945Sweongyo	[48]	= { 16, 8 },
464203945Sweongyo	[72]	= { 11, 5 },
465203945Sweongyo	[96]	= { 9, 4 },
466203945Sweongyo	[108]	= { 7, 3 }
467203945Sweongyo};
468203945Sweongyo
469203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
470203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
471203945Sweongyo	[1] = BWN_WME_BACKGROUND,
472203945Sweongyo	[2] = BWN_WME_VOICE,
473203945Sweongyo	[3] = BWN_WME_VIDEO,
474203945Sweongyo};
475203945Sweongyo
476203945Sweongyostatic const struct siba_devid bwn_devs[] = {
477203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
478203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
479203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
480203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
481203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
482203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
483203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
484203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
485203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
486203945Sweongyo};
487203945Sweongyo
488203945Sweongyostatic int
489203945Sweongyobwn_probe(device_t dev)
490203945Sweongyo{
491203945Sweongyo	int i;
492203945Sweongyo
493298307Spfg	for (i = 0; i < nitems(bwn_devs); i++) {
494204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
495204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
496204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
497203945Sweongyo			return (BUS_PROBE_DEFAULT);
498203945Sweongyo	}
499203945Sweongyo
500203945Sweongyo	return (ENXIO);
501203945Sweongyo}
502203945Sweongyo
503203945Sweongyostatic int
504203945Sweongyobwn_attach(device_t dev)
505203945Sweongyo{
506203945Sweongyo	struct bwn_mac *mac;
507203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
508203945Sweongyo	int error, i, msic, reg;
509203945Sweongyo
510203945Sweongyo	sc->sc_dev = dev;
511203945Sweongyo#ifdef BWN_DEBUG
512203945Sweongyo	sc->sc_debug = bwn_debug;
513203945Sweongyo#endif
514203945Sweongyo
515203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
516287197Sglebius		bwn_attach_pre(sc);
517204922Sweongyo		bwn_sprom_bugfixes(dev);
518203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
519203945Sweongyo	}
520203945Sweongyo
521203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
522204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
523204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
524204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
525203945Sweongyo			device_printf(sc->sc_dev,
526203945Sweongyo			    "skip 802.11 cores\n");
527203945Sweongyo			return (ENODEV);
528203945Sweongyo		}
529203945Sweongyo	}
530203945Sweongyo
531287197Sglebius	mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO);
532203945Sweongyo	mac->mac_sc = sc;
533203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
534203945Sweongyo	if (bwn_bfp != 0)
535203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
536203945Sweongyo
537203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
538203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
539203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
540203945Sweongyo
541203945Sweongyo	error = bwn_attach_core(mac);
542203945Sweongyo	if (error)
543203945Sweongyo		goto fail0;
544203945Sweongyo	bwn_led_attach(mac);
545203945Sweongyo
546203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
547203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
548204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
549203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
550203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
551203945Sweongyo	    mac->mac_phy.rf_rev);
552203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
553203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
554203945Sweongyo		    mac->mac_method.dma.dmatype);
555203945Sweongyo	else
556203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
557203945Sweongyo
558203945Sweongyo	/*
559203945Sweongyo	 * setup PCI resources and interrupt.
560203945Sweongyo	 */
561219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
562203945Sweongyo		msic = pci_msi_count(dev);
563203945Sweongyo		if (bootverbose)
564203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
565203945Sweongyo	} else
566203945Sweongyo		msic = 0;
567203945Sweongyo
568203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
569203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
570203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
571203945Sweongyo			device_printf(sc->sc_dev,
572203945Sweongyo			    "Using %d MSI messages\n", msic);
573203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
574203945Sweongyo			mac->mac_msi = 1;
575203945Sweongyo		}
576203945Sweongyo	}
577203945Sweongyo
578203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
579203945Sweongyo	    mac->mac_res_irq);
580203945Sweongyo	if (error) {
581203945Sweongyo		device_printf(sc->sc_dev,
582203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
583203945Sweongyo		goto fail1;
584203945Sweongyo	}
585203945Sweongyo
586203945Sweongyo	if (mac->mac_msi == 0)
587203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
588203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
589203945Sweongyo		    &mac->mac_intrhand[0]);
590203945Sweongyo	else {
591203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
592203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
593203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
594203945Sweongyo			    &mac->mac_intrhand[i]);
595203945Sweongyo			if (error != 0) {
596203945Sweongyo				device_printf(sc->sc_dev,
597203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
598203945Sweongyo				break;
599203945Sweongyo			}
600203945Sweongyo		}
601203945Sweongyo	}
602203945Sweongyo
603203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
604203945Sweongyo
605203945Sweongyo	/*
606203945Sweongyo	 * calls attach-post routine
607203945Sweongyo	 */
608203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
609203945Sweongyo		bwn_attach_post(sc);
610203945Sweongyo
611203945Sweongyo	return (0);
612203945Sweongyofail1:
613203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
614203945Sweongyo		pci_release_msi(dev);
615203945Sweongyofail0:
616203945Sweongyo	free(mac, M_DEVBUF);
617203945Sweongyo	return (error);
618203945Sweongyo}
619203945Sweongyo
620203945Sweongyostatic int
621203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
622203945Sweongyo{
623203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
624203945Sweongyo
625203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
626203945Sweongyo		return (FALSE);
627203945Sweongyo
628203945Sweongyo	return (TRUE);
629203945Sweongyo}
630203945Sweongyo
631203945Sweongyostatic int
632203945Sweongyobwn_attach_post(struct bwn_softc *sc)
633203945Sweongyo{
634287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
635203945Sweongyo
636283537Sglebius	ic->ic_softc = sc;
637283527Sglebius	ic->ic_name = device_get_nameunit(sc->sc_dev);
638203945Sweongyo	/* XXX not right but it's not used anywhere important */
639203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
640203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
641203945Sweongyo	ic->ic_caps =
642203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
643203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
644204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
645203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
646203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
647203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
648203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
649203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
650203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
651203945Sweongyo		;
652203945Sweongyo
653205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
654205141Sweongyo
655287197Sglebius	IEEE80211_ADDR_COPY(ic->ic_macaddr,
656204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
657204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
658204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
659203945Sweongyo
660287197Sglebius	/* call MI attach routine. */
661287197Sglebius	ieee80211_ifattach(ic);
662287197Sglebius
663203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
664203945Sweongyo
665203945Sweongyo	/* override default methods */
666203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
667203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
668203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
669203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
670203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
671203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
672203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
673203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
674203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
675287197Sglebius	ic->ic_transmit = bwn_transmit;
676287197Sglebius	ic->ic_parent = bwn_parent;
677203945Sweongyo
678203945Sweongyo	ieee80211_radiotap_attach(ic,
679203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
680203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
681203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
682203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
683203945Sweongyo
684204257Sweongyo	bwn_sysctl_node(sc);
685203945Sweongyo
686203945Sweongyo	if (bootverbose)
687203945Sweongyo		ieee80211_announce(ic);
688203945Sweongyo	return (0);
689203945Sweongyo}
690203945Sweongyo
691203945Sweongyostatic void
692203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
693203945Sweongyo{
694203945Sweongyo
695203945Sweongyo	if (mac->mac_phy.detach != NULL)
696203945Sweongyo		mac->mac_phy.detach(mac);
697203945Sweongyo}
698203945Sweongyo
699203945Sweongyostatic int
700203945Sweongyobwn_detach(device_t dev)
701203945Sweongyo{
702203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
703203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
704287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
705203945Sweongyo	int i;
706203945Sweongyo
707203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
708203945Sweongyo
709203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
710287197Sglebius		BWN_LOCK(sc);
711287197Sglebius		bwn_stop(sc);
712287197Sglebius		BWN_UNLOCK(sc);
713203945Sweongyo		bwn_dma_free(mac);
714203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
715203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
716203945Sweongyo		callout_drain(&sc->sc_task_ch);
717203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
718203945Sweongyo		bwn_phy_detach(mac);
719287197Sglebius		ieee80211_draintask(ic, &mac->mac_hwreset);
720287197Sglebius		ieee80211_draintask(ic, &mac->mac_txpower);
721287197Sglebius		ieee80211_ifdetach(ic);
722203945Sweongyo	}
723203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
724203945Sweongyo	taskqueue_free(sc->sc_tq);
725203945Sweongyo
726203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
727203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
728203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
729203945Sweongyo			    mac->mac_intrhand[i]);
730203945Sweongyo			mac->mac_intrhand[i] = NULL;
731203945Sweongyo		}
732203945Sweongyo	}
733203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
734203945Sweongyo	if (mac->mac_msi != 0)
735203945Sweongyo		pci_release_msi(dev);
736287197Sglebius	mbufq_drain(&sc->sc_snd);
737203945Sweongyo	BWN_LOCK_DESTROY(sc);
738203945Sweongyo	return (0);
739203945Sweongyo}
740203945Sweongyo
741287197Sglebiusstatic void
742203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
743203945Sweongyo{
744203945Sweongyo
745203945Sweongyo	BWN_LOCK_INIT(sc);
746203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
747203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
748203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
749203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
750287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
751203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
752203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
753203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
754203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
755203945Sweongyo}
756203945Sweongyo
757203945Sweongyostatic void
758204922Sweongyobwn_sprom_bugfixes(device_t dev)
759203945Sweongyo{
760203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
761204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
762204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
763204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
764204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
765203945Sweongyo
766204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
767204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
768204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
769204922Sweongyo		siba_sprom_set_bf_lo(dev,
770204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
771204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
772204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
773204922Sweongyo		siba_sprom_set_bf_lo(dev,
774204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
775204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
776203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
777203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
778203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
779203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
780203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
781203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
782203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
783204922Sweongyo			siba_sprom_set_bf_lo(dev,
784204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
785203945Sweongyo	}
786203945Sweongyo#undef	BWN_ISDEV
787203945Sweongyo}
788203945Sweongyo
789287197Sglebiusstatic void
790287197Sglebiusbwn_parent(struct ieee80211com *ic)
791203945Sweongyo{
792287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
793287197Sglebius	int startall = 0;
794203945Sweongyo
795287197Sglebius	BWN_LOCK(sc);
796287197Sglebius	if (ic->ic_nrunning > 0) {
797287197Sglebius		if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
798287197Sglebius			bwn_init(sc);
799287197Sglebius			startall = 1;
800287197Sglebius		} else
801286437Sadrian			bwn_update_promisc(ic);
802287197Sglebius	} else if (sc->sc_flags & BWN_FLAG_RUNNING)
803287197Sglebius		bwn_stop(sc);
804287197Sglebius	BWN_UNLOCK(sc);
805287197Sglebius
806287197Sglebius	if (startall)
807287197Sglebius		ieee80211_start_all(ic);
808203945Sweongyo}
809203945Sweongyo
810287197Sglebiusstatic int
811287197Sglebiusbwn_transmit(struct ieee80211com *ic, struct mbuf *m)
812203945Sweongyo{
813287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
814287197Sglebius	int error;
815203945Sweongyo
816203945Sweongyo	BWN_LOCK(sc);
817287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
818287197Sglebius		BWN_UNLOCK(sc);
819287197Sglebius		return (ENXIO);
820287197Sglebius	}
821287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
822287197Sglebius	if (error) {
823287197Sglebius		BWN_UNLOCK(sc);
824287197Sglebius		return (error);
825287197Sglebius	}
826287197Sglebius	bwn_start(sc);
827203945Sweongyo	BWN_UNLOCK(sc);
828287197Sglebius	return (0);
829203945Sweongyo}
830203945Sweongyo
831203945Sweongyostatic void
832287197Sglebiusbwn_start(struct bwn_softc *sc)
833203945Sweongyo{
834203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
835203945Sweongyo	struct ieee80211_frame *wh;
836203945Sweongyo	struct ieee80211_node *ni;
837203945Sweongyo	struct ieee80211_key *k;
838203945Sweongyo	struct mbuf *m;
839203945Sweongyo
840203945Sweongyo	BWN_ASSERT_LOCKED(sc);
841203945Sweongyo
842287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || mac == NULL ||
843203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
844203945Sweongyo		return;
845203945Sweongyo
846287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
847203945Sweongyo		if (bwn_tx_isfull(sc, m))
848203945Sweongyo			break;
849203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
850203945Sweongyo		if (ni == NULL) {
851203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
852203945Sweongyo			m_freem(m);
853287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
854203945Sweongyo			continue;
855203945Sweongyo		}
856203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
857260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
858203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
859203945Sweongyo			if (k == NULL) {
860287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
861287197Sglebius				    IFCOUNTER_OERRORS, 1);
862203945Sweongyo				ieee80211_free_node(ni);
863203945Sweongyo				m_freem(m);
864203945Sweongyo				continue;
865203945Sweongyo			}
866203945Sweongyo		}
867203945Sweongyo		wh = NULL;	/* Catch any invalid use */
868203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
869287197Sglebius			if (ni != NULL) {
870287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
871287197Sglebius				    IFCOUNTER_OERRORS, 1);
872203945Sweongyo				ieee80211_free_node(ni);
873287197Sglebius			}
874203945Sweongyo			continue;
875203945Sweongyo		}
876203945Sweongyo		sc->sc_watchdog_timer = 5;
877203945Sweongyo	}
878203945Sweongyo}
879203945Sweongyo
880203945Sweongyostatic int
881203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
882203945Sweongyo{
883203945Sweongyo	struct bwn_dma_ring *dr;
884203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
885203945Sweongyo	struct bwn_pio_txqueue *tq;
886203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
887203945Sweongyo
888203945Sweongyo	BWN_ASSERT_LOCKED(sc);
889203945Sweongyo
890203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
891203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
892203945Sweongyo		if (dr->dr_stop == 1 ||
893203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
894203945Sweongyo			dr->dr_stop = 1;
895203945Sweongyo			goto full;
896203945Sweongyo		}
897203945Sweongyo	} else {
898203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
899203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
900287197Sglebius		    pktlen > (tq->tq_size - tq->tq_used))
901203945Sweongyo			goto full;
902203945Sweongyo	}
903203945Sweongyo	return (0);
904203945Sweongyofull:
905287197Sglebius	mbufq_prepend(&sc->sc_snd, m);
906203945Sweongyo	return (1);
907203945Sweongyo}
908203945Sweongyo
909203945Sweongyostatic int
910203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
911203945Sweongyo{
912203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
913203945Sweongyo	int error;
914203945Sweongyo
915203945Sweongyo	BWN_ASSERT_LOCKED(sc);
916203945Sweongyo
917203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
918203945Sweongyo		m_freem(m);
919203945Sweongyo		return (ENXIO);
920203945Sweongyo	}
921203945Sweongyo
922203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
923203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
924203945Sweongyo	if (error) {
925203945Sweongyo		m_freem(m);
926203945Sweongyo		return (error);
927203945Sweongyo	}
928203945Sweongyo	return (0);
929203945Sweongyo}
930203945Sweongyo
931203945Sweongyostatic int
932203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
933203945Sweongyo{
934203945Sweongyo	struct bwn_pio_txpkt *tp;
935203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
936203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
937203945Sweongyo	struct bwn_txhdr txhdr;
938203945Sweongyo	struct mbuf *m_new;
939203945Sweongyo	uint32_t ctl32;
940203945Sweongyo	int error;
941203945Sweongyo	uint16_t ctl16;
942203945Sweongyo
943203945Sweongyo	BWN_ASSERT_LOCKED(sc);
944203945Sweongyo
945203945Sweongyo	/* XXX TODO send packets after DTIM */
946203945Sweongyo
947203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
948203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
949203945Sweongyo	tp->tp_ni = ni;
950203945Sweongyo	tp->tp_m = m;
951203945Sweongyo
952203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
953203945Sweongyo	if (error) {
954203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
955203945Sweongyo		return (error);
956203945Sweongyo	}
957203945Sweongyo
958203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
959203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
960203945Sweongyo	tq->tq_free--;
961203945Sweongyo
962204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
963203945Sweongyo		/*
964203945Sweongyo		 * XXX please removes m_defrag(9)
965203945Sweongyo		 */
966243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
967203945Sweongyo		if (m_new == NULL) {
968203945Sweongyo			device_printf(sc->sc_dev,
969203945Sweongyo			    "%s: can't defrag TX buffer\n",
970203945Sweongyo			    __func__);
971203945Sweongyo			return (ENOBUFS);
972203945Sweongyo		}
973203945Sweongyo		if (m_new->m_next != NULL)
974203945Sweongyo			device_printf(sc->sc_dev,
975203945Sweongyo			    "TODO: fragmented packets for PIO\n");
976203945Sweongyo		tp->tp_m = m_new;
977203945Sweongyo
978203945Sweongyo		/* send HEADER */
979203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
980203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
981203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
982203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
983203945Sweongyo		/* send BODY */
984203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
985203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
986203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
987203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
988203945Sweongyo	} else {
989203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
990203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
991203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
992203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
993203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
994203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
995203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
996203945Sweongyo	}
997203945Sweongyo
998203945Sweongyo	return (0);
999203945Sweongyo}
1000203945Sweongyo
1001203945Sweongyostatic struct bwn_pio_txqueue *
1002203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1003203945Sweongyo{
1004203945Sweongyo
1005203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1006203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1007203945Sweongyo
1008203945Sweongyo	switch (prio) {
1009203945Sweongyo	case 0:
1010203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1011203945Sweongyo	case 1:
1012203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1013203945Sweongyo	case 2:
1014203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1015203945Sweongyo	case 3:
1016203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1017203945Sweongyo	}
1018203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1019204242Simp	return (NULL);
1020203945Sweongyo}
1021203945Sweongyo
1022203945Sweongyostatic int
1023203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1024203945Sweongyo{
1025203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1026203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1027203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1028203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1029203945Sweongyo	struct bwn_dmadesc_generic *desc;
1030203945Sweongyo	struct bwn_dmadesc_meta *mt;
1031203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1032203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1033203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1034203945Sweongyo
1035203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1036203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1037203945Sweongyo
1038203945Sweongyo	/* XXX send after DTIM */
1039203945Sweongyo
1040203945Sweongyo	slot = bwn_dma_getslot(dr);
1041203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1042203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1043203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1044203945Sweongyo
1045203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1046203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1047203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1048203945Sweongyo	if (error)
1049203945Sweongyo		goto fail;
1050203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1051203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1052203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1053203945Sweongyo	if (error) {
1054287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1055203945Sweongyo		    __func__, error);
1056203945Sweongyo		goto fail;
1057203945Sweongyo	}
1058203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1059203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1060203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1061203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1062203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1063203945Sweongyo
1064203945Sweongyo	slot = bwn_dma_getslot(dr);
1065203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1066203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1067203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1068203945Sweongyo	mt->mt_m = m;
1069203945Sweongyo	mt->mt_ni = ni;
1070203945Sweongyo
1071203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1072203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1073203945Sweongyo	if (error && error != EFBIG) {
1074287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1075203945Sweongyo		    __func__, error);
1076203945Sweongyo		goto fail;
1077203945Sweongyo	}
1078203945Sweongyo	if (error) {    /* error == EFBIG */
1079203945Sweongyo		struct mbuf *m_new;
1080203945Sweongyo
1081243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1082203945Sweongyo		if (m_new == NULL) {
1083287197Sglebius			device_printf(sc->sc_dev,
1084287197Sglebius			    "%s: can't defrag TX buffer\n",
1085203945Sweongyo			    __func__);
1086203945Sweongyo			error = ENOBUFS;
1087203945Sweongyo			goto fail;
1088203945Sweongyo		} else {
1089203945Sweongyo			m = m_new;
1090203945Sweongyo		}
1091203945Sweongyo
1092203945Sweongyo		mt->mt_m = m;
1093203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1094203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1095203945Sweongyo		if (error) {
1096287197Sglebius			device_printf(sc->sc_dev,
1097287197Sglebius			    "%s: can't load TX buffer (2) %d\n",
1098203945Sweongyo			    __func__, error);
1099203945Sweongyo			goto fail;
1100203945Sweongyo		}
1101203945Sweongyo	}
1102203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1103203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1104203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1105203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1106203945Sweongyo
1107203945Sweongyo	/* XXX send after DTIM */
1108203945Sweongyo
1109203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1110203945Sweongyo	return (0);
1111203945Sweongyofail:
1112203945Sweongyo	dr->dr_curslot = backup[0];
1113203945Sweongyo	dr->dr_usedslot = backup[1];
1114203945Sweongyo	return (error);
1115203945Sweongyo#undef BWN_GET_TXHDRCACHE
1116203945Sweongyo}
1117203945Sweongyo
1118203945Sweongyostatic void
1119203945Sweongyobwn_watchdog(void *arg)
1120203945Sweongyo{
1121203945Sweongyo	struct bwn_softc *sc = arg;
1122203945Sweongyo
1123203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1124287197Sglebius		device_printf(sc->sc_dev, "device timeout\n");
1125287197Sglebius		counter_u64_add(sc->sc_ic.ic_oerrors, 1);
1126203945Sweongyo	}
1127203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1128203945Sweongyo}
1129203945Sweongyo
1130203945Sweongyostatic int
1131203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1132203945Sweongyo{
1133203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1134203945Sweongyo	int error, have_bg = 0, have_a = 0;
1135203945Sweongyo	uint32_t high;
1136203945Sweongyo
1137204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1138204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1139203945Sweongyo
1140204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1141203945Sweongyo
1142204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1143203945Sweongyo	bwn_reset_core(mac,
1144203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1145203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1146203945Sweongyo	if (error)
1147203945Sweongyo		goto fail;
1148203945Sweongyo
1149203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1150203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1151204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1152204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1153204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1154203945Sweongyo		have_a = have_bg = 0;
1155203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1156203945Sweongyo			have_a = 1;
1157203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1158203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1159203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1160203945Sweongyo			have_bg = 1;
1161203945Sweongyo		else
1162203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1163203945Sweongyo			    mac->mac_phy.type));
1164203945Sweongyo	}
1165203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1166203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1167203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1168203945Sweongyo		have_a = 0;
1169203945Sweongyo		have_bg = 1;
1170203945Sweongyo	}
1171203945Sweongyo
1172203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1173203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1174203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1175203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1176203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1177203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1178203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1179203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1180203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1181203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1182203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1183203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1184203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1185203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1186203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1187203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1188203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1189203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1190203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1191203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1192203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1193203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1194203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1195203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1196203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1197203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1198203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1199203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1200203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1201203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1202203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1203203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1204203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1205203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1206203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1207203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1208203945Sweongyo	} else {
1209203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1210203945Sweongyo		    mac->mac_phy.type);
1211203945Sweongyo		error = ENXIO;
1212203945Sweongyo		goto fail;
1213203945Sweongyo	}
1214203945Sweongyo
1215203945Sweongyo	mac->mac_phy.gmode = have_bg;
1216203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1217203945Sweongyo		error = mac->mac_phy.attach(mac);
1218203945Sweongyo		if (error) {
1219203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1220203945Sweongyo			goto fail;
1221203945Sweongyo		}
1222203945Sweongyo	}
1223203945Sweongyo
1224203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1225203945Sweongyo
1226203945Sweongyo	error = bwn_chiptest(mac);
1227203945Sweongyo	if (error)
1228203945Sweongyo		goto fail;
1229203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1230203945Sweongyo	if (error) {
1231203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1232203945Sweongyo		goto fail;
1233203945Sweongyo	}
1234203945Sweongyo
1235203945Sweongyo	if (sc->sc_curmac == NULL)
1236203945Sweongyo		sc->sc_curmac = mac;
1237203945Sweongyo
1238203945Sweongyo	error = bwn_dma_attach(mac);
1239203945Sweongyo	if (error != 0) {
1240203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1241203945Sweongyo		goto fail;
1242203945Sweongyo	}
1243203945Sweongyo
1244203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1245203945Sweongyo
1246204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1247203945Sweongyofail:
1248204922Sweongyo	siba_powerdown(sc->sc_dev);
1249203945Sweongyo	return (error);
1250203945Sweongyo}
1251203945Sweongyo
1252298948Sadrianvoid
1253203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1254203945Sweongyo{
1255204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1256203945Sweongyo	uint32_t low, ctl;
1257203945Sweongyo
1258203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1259203945Sweongyo
1260204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1261203945Sweongyo	DELAY(2000);
1262203945Sweongyo
1263204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1264203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1265204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1266204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1267203945Sweongyo	DELAY(1000);
1268204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1269204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1270203945Sweongyo	DELAY(1000);
1271203945Sweongyo
1272203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1273203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1274203945Sweongyo
1275203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1276203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1277203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1278203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1279203945Sweongyo}
1280203945Sweongyo
1281203945Sweongyostatic int
1282203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1283203945Sweongyo{
1284203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1285203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1286203945Sweongyo	uint32_t tmp;
1287203945Sweongyo
1288203945Sweongyo	/* PHY */
1289203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1290203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1291203945Sweongyo	phy->rf_on = 1;
1292203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1293203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1294203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1295203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1296203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1297203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1298203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1299203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1300203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1301203945Sweongyo		goto unsupphy;
1302203945Sweongyo
1303203945Sweongyo	/* RADIO */
1304204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1305204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1306203945Sweongyo			tmp = 0x3205017f;
1307204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1308203945Sweongyo			tmp = 0x4205017f;
1309203945Sweongyo		else
1310203945Sweongyo			tmp = 0x5205017f;
1311203945Sweongyo	} else {
1312203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1313203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1314203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1315203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1316203945Sweongyo	}
1317203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1318203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1319203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1320203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1321203945Sweongyo		goto unsupradio;
1322203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1323203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1324203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1325203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1326203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1327203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1328203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1329203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1330203945Sweongyo		goto unsupradio;
1331203945Sweongyo
1332203945Sweongyo	return (0);
1333203945Sweongyounsupphy:
1334203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1335203945Sweongyo	    "analog %#x)\n",
1336203945Sweongyo	    phy->type, phy->rev, phy->analog);
1337203945Sweongyo	return (ENXIO);
1338203945Sweongyounsupradio:
1339203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1340203945Sweongyo	    "rev %#x)\n",
1341203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1342203945Sweongyo	return (ENXIO);
1343203945Sweongyo}
1344203945Sweongyo
1345203945Sweongyostatic int
1346203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1347203945Sweongyo{
1348203945Sweongyo#define	TESTVAL0	0x55aaaa55
1349203945Sweongyo#define	TESTVAL1	0xaa5555aa
1350203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1351203945Sweongyo	uint32_t v, backup;
1352203945Sweongyo
1353203945Sweongyo	BWN_LOCK(sc);
1354203945Sweongyo
1355203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1356203945Sweongyo
1357203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1358203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1359203945Sweongyo		goto error;
1360203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1361203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1362203945Sweongyo		goto error;
1363203945Sweongyo
1364203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1365203945Sweongyo
1366204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1367204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1368203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1369203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1370203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1371203945Sweongyo			goto error;
1372203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1373203945Sweongyo			goto error;
1374203945Sweongyo	}
1375203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1376203945Sweongyo
1377203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1378203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1379203945Sweongyo		goto error;
1380203945Sweongyo
1381203945Sweongyo	BWN_UNLOCK(sc);
1382203945Sweongyo	return (0);
1383203945Sweongyoerror:
1384203945Sweongyo	BWN_UNLOCK(sc);
1385203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1386203945Sweongyo	return (ENODEV);
1387203945Sweongyo}
1388203945Sweongyo
1389203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1390203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1391203945Sweongyo
1392203945Sweongyostatic int
1393203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1394203945Sweongyo{
1395203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1396287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1397203945Sweongyo
1398203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1399203945Sweongyo	ic->ic_nchans = 0;
1400203945Sweongyo
1401203945Sweongyo	if (have_bg)
1402203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1403203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1404203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1405203945Sweongyo		if (have_a)
1406203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1407203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1408203945Sweongyo			    IEEE80211_CHAN_HTA);
1409203945Sweongyo	} else {
1410203945Sweongyo		if (have_a)
1411203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1412203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1413203945Sweongyo			    IEEE80211_CHAN_A);
1414203945Sweongyo	}
1415203945Sweongyo
1416203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1417203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1418203945Sweongyo
1419203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1420203945Sweongyo}
1421203945Sweongyo
1422298948Sadrianuint32_t
1423203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1424203945Sweongyo{
1425203945Sweongyo	uint32_t ret;
1426203945Sweongyo
1427204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1428203945Sweongyo
1429203945Sweongyo	if (way == BWN_SHARED) {
1430203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1431203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1432203945Sweongyo		if (offset & 0x0003) {
1433203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1434203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1435203945Sweongyo			ret <<= 16;
1436203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1437203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1438203945Sweongyo			goto out;
1439203945Sweongyo		}
1440203945Sweongyo		offset >>= 2;
1441203945Sweongyo	}
1442203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1443203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1444203945Sweongyoout:
1445203945Sweongyo	return (ret);
1446203945Sweongyo}
1447203945Sweongyo
1448298948Sadrianuint16_t
1449203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1450203945Sweongyo{
1451203945Sweongyo	uint16_t ret;
1452203945Sweongyo
1453204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1454203945Sweongyo
1455203945Sweongyo	if (way == BWN_SHARED) {
1456203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1457203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1458203945Sweongyo		if (offset & 0x0003) {
1459203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1460203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1461203945Sweongyo			goto out;
1462203945Sweongyo		}
1463203945Sweongyo		offset >>= 2;
1464203945Sweongyo	}
1465203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1466203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1467203945Sweongyoout:
1468203945Sweongyo
1469203945Sweongyo	return (ret);
1470203945Sweongyo}
1471203945Sweongyo
1472203945Sweongyostatic void
1473203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1474203945Sweongyo    uint16_t offset)
1475203945Sweongyo{
1476203945Sweongyo	uint32_t control;
1477203945Sweongyo
1478203945Sweongyo	control = way;
1479203945Sweongyo	control <<= 16;
1480203945Sweongyo	control |= offset;
1481203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1482203945Sweongyo}
1483203945Sweongyo
1484298948Sadrianvoid
1485203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1486203945Sweongyo    uint32_t value)
1487203945Sweongyo{
1488204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1489203945Sweongyo
1490203945Sweongyo	if (way == BWN_SHARED) {
1491203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1492203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1493203945Sweongyo		if (offset & 0x0003) {
1494203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1495203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1496203945Sweongyo				    (value >> 16) & 0xffff);
1497203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1498203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1499203945Sweongyo			return;
1500203945Sweongyo		}
1501203945Sweongyo		offset >>= 2;
1502203945Sweongyo	}
1503203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1504203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1505203945Sweongyo}
1506203945Sweongyo
1507298948Sadrianvoid
1508203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1509203945Sweongyo    uint16_t value)
1510203945Sweongyo{
1511204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1512203945Sweongyo
1513203945Sweongyo	if (way == BWN_SHARED) {
1514203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1515203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1516203945Sweongyo		if (offset & 0x0003) {
1517203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1518203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1519203945Sweongyo			return;
1520203945Sweongyo		}
1521203945Sweongyo		offset >>= 2;
1522203945Sweongyo	}
1523203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1524203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1525203945Sweongyo}
1526203945Sweongyo
1527203945Sweongyostatic void
1528203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1529203945Sweongyo    int txpow)
1530203945Sweongyo{
1531203945Sweongyo
1532203945Sweongyo	c->ic_freq = freq;
1533203945Sweongyo	c->ic_flags = flags;
1534203945Sweongyo	c->ic_ieee = ieee;
1535203945Sweongyo	c->ic_minpower = 0;
1536203945Sweongyo	c->ic_maxpower = 2 * txpow;
1537203945Sweongyo	c->ic_maxregpower = txpow;
1538203945Sweongyo}
1539203945Sweongyo
1540203945Sweongyostatic void
1541203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
1542203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
1543203945Sweongyo{
1544203945Sweongyo	struct ieee80211_channel *c;
1545203945Sweongyo	int i;
1546203945Sweongyo
1547203945Sweongyo	c = &chans[*nchans];
1548203945Sweongyo
1549203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
1550203945Sweongyo		const struct bwn_channel *hc;
1551203945Sweongyo
1552203945Sweongyo		hc = &ci->channels[i];
1553203945Sweongyo		if (*nchans >= maxchans)
1554203945Sweongyo			break;
1555203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
1556203945Sweongyo		c++, (*nchans)++;
1557203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
1558203945Sweongyo			/* g channel have a separate b-only entry */
1559203945Sweongyo			if (*nchans >= maxchans)
1560203945Sweongyo				break;
1561203945Sweongyo			c[0] = c[-1];
1562203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
1563203945Sweongyo			c++, (*nchans)++;
1564203945Sweongyo		}
1565203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
1566203945Sweongyo			/* HT g channel have a separate g-only entry */
1567203945Sweongyo			if (*nchans >= maxchans)
1568203945Sweongyo				break;
1569203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
1570203945Sweongyo			c[0] = c[-1];
1571203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1572203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1573203945Sweongyo			c++, (*nchans)++;
1574203945Sweongyo		}
1575203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
1576203945Sweongyo			/* HT a channel have a separate a-only entry */
1577203945Sweongyo			if (*nchans >= maxchans)
1578203945Sweongyo				break;
1579203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
1580203945Sweongyo			c[0] = c[-1];
1581203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1582203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1583203945Sweongyo			c++, (*nchans)++;
1584203945Sweongyo		}
1585203945Sweongyo	}
1586203945Sweongyo}
1587203945Sweongyo
1588203945Sweongyostatic int
1589203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1590203945Sweongyo	const struct ieee80211_bpf_params *params)
1591203945Sweongyo{
1592203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
1593286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1594203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1595289165Sadrian	int error;
1596203945Sweongyo
1597287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 ||
1598203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
1599203945Sweongyo		m_freem(m);
1600203945Sweongyo		return (ENETDOWN);
1601203945Sweongyo	}
1602203945Sweongyo
1603203945Sweongyo	BWN_LOCK(sc);
1604203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
1605203945Sweongyo		m_freem(m);
1606203945Sweongyo		BWN_UNLOCK(sc);
1607203945Sweongyo		return (ENOBUFS);
1608203945Sweongyo	}
1609203945Sweongyo
1610289165Sadrian	error = bwn_tx_start(sc, ni, m);
1611289165Sadrian	if (error == 0)
1612289165Sadrian		sc->sc_watchdog_timer = 5;
1613203945Sweongyo	BWN_UNLOCK(sc);
1614289165Sadrian	return (error);
1615203945Sweongyo}
1616203945Sweongyo
1617203945Sweongyo/*
1618203945Sweongyo * Callback from the 802.11 layer to update the slot time
1619203945Sweongyo * based on the current setting.  We use it to notify the
1620203945Sweongyo * firmware of ERP changes and the f/w takes care of things
1621203945Sweongyo * like slot time and preamble.
1622203945Sweongyo */
1623203945Sweongyostatic void
1624283540Sglebiusbwn_updateslot(struct ieee80211com *ic)
1625203945Sweongyo{
1626283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1627203945Sweongyo	struct bwn_mac *mac;
1628203945Sweongyo
1629203945Sweongyo	BWN_LOCK(sc);
1630287197Sglebius	if (sc->sc_flags & BWN_FLAG_RUNNING) {
1631203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
1632292165Savos		bwn_set_slot_time(mac, IEEE80211_GET_SLOTTIME(ic));
1633203945Sweongyo	}
1634203945Sweongyo	BWN_UNLOCK(sc);
1635203945Sweongyo}
1636203945Sweongyo
1637203945Sweongyo/*
1638203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
1639203945Sweongyo * Note this interface does not check the operating mode as this
1640203945Sweongyo * is an internal callback and we are expected to honor the current
1641203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
1642203945Sweongyo * mode when operating in hostap mode to do ACS).
1643203945Sweongyo */
1644203945Sweongyostatic void
1645283540Sglebiusbwn_update_promisc(struct ieee80211com *ic)
1646203945Sweongyo{
1647283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1648203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1649203945Sweongyo
1650203945Sweongyo	BWN_LOCK(sc);
1651203945Sweongyo	mac = sc->sc_curmac;
1652203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1653287197Sglebius		if (ic->ic_promisc > 0)
1654203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
1655203945Sweongyo		else
1656203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
1657203945Sweongyo		bwn_set_opmode(mac);
1658203945Sweongyo	}
1659203945Sweongyo	BWN_UNLOCK(sc);
1660203945Sweongyo}
1661203945Sweongyo
1662203945Sweongyo/*
1663203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
1664203945Sweongyo */
1665203945Sweongyostatic int
1666203945Sweongyobwn_wme_update(struct ieee80211com *ic)
1667203945Sweongyo{
1668286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1669203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1670203945Sweongyo	struct wmeParams *wmep;
1671203945Sweongyo	int i;
1672203945Sweongyo
1673203945Sweongyo	BWN_LOCK(sc);
1674203945Sweongyo	mac = sc->sc_curmac;
1675203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1676203945Sweongyo		bwn_mac_suspend(mac);
1677203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
1678203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
1679203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
1680203945Sweongyo		}
1681203945Sweongyo		bwn_mac_enable(mac);
1682203945Sweongyo	}
1683203945Sweongyo	BWN_UNLOCK(sc);
1684203945Sweongyo	return (0);
1685203945Sweongyo}
1686203945Sweongyo
1687203945Sweongyostatic void
1688203945Sweongyobwn_scan_start(struct ieee80211com *ic)
1689203945Sweongyo{
1690286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1691203945Sweongyo	struct bwn_mac *mac;
1692203945Sweongyo
1693203945Sweongyo	BWN_LOCK(sc);
1694203945Sweongyo	mac = sc->sc_curmac;
1695203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1696203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
1697203945Sweongyo		bwn_set_opmode(mac);
1698203945Sweongyo		/* disable CFP update during scan */
1699203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
1700203945Sweongyo	}
1701203945Sweongyo	BWN_UNLOCK(sc);
1702203945Sweongyo}
1703203945Sweongyo
1704203945Sweongyostatic void
1705203945Sweongyobwn_scan_end(struct ieee80211com *ic)
1706203945Sweongyo{
1707286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1708203945Sweongyo	struct bwn_mac *mac;
1709203945Sweongyo
1710203945Sweongyo	BWN_LOCK(sc);
1711203945Sweongyo	mac = sc->sc_curmac;
1712203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1713203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
1714203945Sweongyo		bwn_set_opmode(mac);
1715203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
1716203945Sweongyo	}
1717203945Sweongyo	BWN_UNLOCK(sc);
1718203945Sweongyo}
1719203945Sweongyo
1720203945Sweongyostatic void
1721203945Sweongyobwn_set_channel(struct ieee80211com *ic)
1722203945Sweongyo{
1723286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1724203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1725203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1726203945Sweongyo	int chan, error;
1727203945Sweongyo
1728203945Sweongyo	BWN_LOCK(sc);
1729203945Sweongyo
1730203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
1731203945Sweongyo	if (error)
1732216227Skevlo		goto fail;
1733203945Sweongyo	bwn_mac_suspend(mac);
1734203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
1735203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
1736203945Sweongyo	if (chan != phy->chan)
1737203945Sweongyo		bwn_switch_channel(mac, chan);
1738203945Sweongyo
1739203945Sweongyo	/* TX power level */
1740203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
1741203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
1742203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
1743203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
1744203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
1745203945Sweongyo	}
1746203945Sweongyo
1747203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
1748203945Sweongyo	if (phy->set_antenna)
1749203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
1750203945Sweongyo
1751203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
1752203945Sweongyo		if (sc->sc_rf_enabled) {
1753203945Sweongyo			bwn_rf_turnon(mac);
1754203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
1755203945Sweongyo				device_printf(sc->sc_dev,
1756213719Sjoel				    "please turn on the RF switch\n");
1757203945Sweongyo		} else
1758203945Sweongyo			bwn_rf_turnoff(mac);
1759203945Sweongyo	}
1760203945Sweongyo
1761203945Sweongyo	bwn_mac_enable(mac);
1762203945Sweongyo
1763203945Sweongyofail:
1764203945Sweongyo	/*
1765203945Sweongyo	 * Setup radio tap channel freq and flags
1766203945Sweongyo	 */
1767203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
1768203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
1769203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
1770203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
1771203945Sweongyo
1772203945Sweongyo	BWN_UNLOCK(sc);
1773203945Sweongyo}
1774203945Sweongyo
1775203945Sweongyostatic struct ieee80211vap *
1776228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
1777228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
1778228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
1779287197Sglebius    const uint8_t mac[IEEE80211_ADDR_LEN])
1780203945Sweongyo{
1781203945Sweongyo	struct ieee80211vap *vap;
1782203945Sweongyo	struct bwn_vap *bvp;
1783203945Sweongyo
1784203945Sweongyo	switch (opmode) {
1785203945Sweongyo	case IEEE80211_M_HOSTAP:
1786203945Sweongyo	case IEEE80211_M_MBSS:
1787203945Sweongyo	case IEEE80211_M_STA:
1788203945Sweongyo	case IEEE80211_M_WDS:
1789203945Sweongyo	case IEEE80211_M_MONITOR:
1790203945Sweongyo	case IEEE80211_M_IBSS:
1791203945Sweongyo	case IEEE80211_M_AHDEMO:
1792203945Sweongyo		break;
1793203945Sweongyo	default:
1794203945Sweongyo		return (NULL);
1795203945Sweongyo	}
1796203945Sweongyo
1797287197Sglebius	bvp = malloc(sizeof(struct bwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
1798203945Sweongyo	vap = &bvp->bv_vap;
1799287197Sglebius	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
1800203945Sweongyo	/* override with driver methods */
1801203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
1802203945Sweongyo	vap->iv_newstate = bwn_newstate;
1803203945Sweongyo
1804203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
1805203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
1806203945Sweongyo
1807206358Srpaulo	ieee80211_ratectl_init(vap);
1808203945Sweongyo
1809203945Sweongyo	/* complete setup */
1810203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
1811287197Sglebius	    ieee80211_media_status, mac);
1812203945Sweongyo	return (vap);
1813203945Sweongyo}
1814203945Sweongyo
1815203945Sweongyostatic void
1816203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
1817203945Sweongyo{
1818203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
1819203945Sweongyo
1820206358Srpaulo	ieee80211_ratectl_deinit(vap);
1821203945Sweongyo	ieee80211_vap_detach(vap);
1822203945Sweongyo	free(bvp, M_80211_VAP);
1823203945Sweongyo}
1824203945Sweongyo
1825203945Sweongyostatic int
1826287197Sglebiusbwn_init(struct bwn_softc *sc)
1827203945Sweongyo{
1828203945Sweongyo	struct bwn_mac *mac;
1829203945Sweongyo	int error;
1830203945Sweongyo
1831203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1832203945Sweongyo
1833203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
1834203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
1835203945Sweongyo	sc->sc_filters = 0;
1836203945Sweongyo	bwn_wme_clear(sc);
1837203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
1838203945Sweongyo	sc->sc_rf_enabled = 1;
1839203945Sweongyo
1840203945Sweongyo	mac = sc->sc_curmac;
1841203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
1842203945Sweongyo		error = bwn_core_init(mac);
1843203945Sweongyo		if (error != 0)
1844203945Sweongyo			return (error);
1845203945Sweongyo	}
1846203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
1847203945Sweongyo		bwn_core_start(mac);
1848203945Sweongyo
1849203945Sweongyo	bwn_set_opmode(mac);
1850203945Sweongyo	bwn_set_pretbtt(mac);
1851203945Sweongyo	bwn_spu_setdelay(mac, 0);
1852203945Sweongyo	bwn_set_macaddr(mac);
1853203945Sweongyo
1854287197Sglebius	sc->sc_flags |= BWN_FLAG_RUNNING;
1855203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
1856203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
1857203945Sweongyo
1858203945Sweongyo	return (0);
1859203945Sweongyo}
1860203945Sweongyo
1861203945Sweongyostatic void
1862287197Sglebiusbwn_stop(struct bwn_softc *sc)
1863203945Sweongyo{
1864203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1865203945Sweongyo
1866203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1867203945Sweongyo
1868203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
1869203945Sweongyo		/* XXX FIXME opmode not based on VAP */
1870203945Sweongyo		bwn_set_opmode(mac);
1871203945Sweongyo		bwn_set_macaddr(mac);
1872203945Sweongyo	}
1873203945Sweongyo
1874203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
1875203945Sweongyo		bwn_core_stop(mac);
1876203945Sweongyo
1877203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
1878203945Sweongyo	sc->sc_led_blinking = 0;
1879203945Sweongyo
1880203945Sweongyo	bwn_core_exit(mac);
1881203945Sweongyo	sc->sc_rf_enabled = 0;
1882203945Sweongyo
1883287197Sglebius	sc->sc_flags &= ~BWN_FLAG_RUNNING;
1884203945Sweongyo}
1885203945Sweongyo
1886203945Sweongyostatic void
1887203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
1888203945Sweongyo{
1889203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
1890203945Sweongyo	struct wmeParams *p;
1891203945Sweongyo	unsigned int i;
1892203945Sweongyo
1893203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
1894203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1895203945Sweongyo
1896203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
1897203945Sweongyo		p = &(sc->sc_wmeParams[i]);
1898203945Sweongyo
1899203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
1900203945Sweongyo		case BWN_WME_VOICE:
1901203945Sweongyo			p->wmep_txopLimit = 0;
1902203945Sweongyo			p->wmep_aifsn = 2;
1903203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1904203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1905203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1906203945Sweongyo			break;
1907203945Sweongyo		case BWN_WME_VIDEO:
1908203945Sweongyo			p->wmep_txopLimit = 0;
1909203945Sweongyo			p->wmep_aifsn = 2;
1910203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1911203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1912203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1913203945Sweongyo			break;
1914203945Sweongyo		case BWN_WME_BESTEFFORT:
1915203945Sweongyo			p->wmep_txopLimit = 0;
1916203945Sweongyo			p->wmep_aifsn = 3;
1917203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1918203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1919203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1920203945Sweongyo			break;
1921203945Sweongyo		case BWN_WME_BACKGROUND:
1922203945Sweongyo			p->wmep_txopLimit = 0;
1923203945Sweongyo			p->wmep_aifsn = 7;
1924203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1925203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1926203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1927203945Sweongyo			break;
1928203945Sweongyo		default:
1929203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1930203945Sweongyo		}
1931203945Sweongyo	}
1932203945Sweongyo}
1933203945Sweongyo
1934203945Sweongyostatic int
1935203945Sweongyobwn_core_init(struct bwn_mac *mac)
1936203945Sweongyo{
1937203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1938203945Sweongyo	uint64_t hf;
1939203945Sweongyo	int error;
1940203945Sweongyo
1941203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
1942203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1943203945Sweongyo
1944204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1945204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
1946203945Sweongyo		bwn_reset_core(mac,
1947203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
1948203945Sweongyo
1949203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
1950203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
1951203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
1952203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
1953203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
1954203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
1955203945Sweongyo	mac->mac_stats.link_noise = -95;
1956203945Sweongyo	mac->mac_reason_intr = 0;
1957203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
1958203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
1959203945Sweongyo#ifdef BWN_DEBUG
1960203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
1961203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
1962203945Sweongyo#endif
1963203945Sweongyo	mac->mac_suspended = 1;
1964203945Sweongyo	mac->mac_task_state = 0;
1965203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
1966203945Sweongyo
1967203945Sweongyo	mac->mac_phy.init_pre(mac);
1968203945Sweongyo
1969204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
1970203945Sweongyo
1971204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
1972203945Sweongyo	bwn_bt_disable(mac);
1973203945Sweongyo	if (mac->mac_phy.prepare_hw) {
1974203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
1975203945Sweongyo		if (error)
1976203945Sweongyo			goto fail0;
1977203945Sweongyo	}
1978203945Sweongyo	error = bwn_chip_init(mac);
1979203945Sweongyo	if (error)
1980203945Sweongyo		goto fail0;
1981203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
1982204922Sweongyo	    siba_get_revid(sc->sc_dev));
1983203945Sweongyo	hf = bwn_hf_read(mac);
1984203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1985203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
1986204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
1987203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
1988203945Sweongyo		if (mac->mac_phy.rev == 1)
1989203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
1990203945Sweongyo	}
1991203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
1992203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
1993203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
1994203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
1995203945Sweongyo			hf |= BWN_HF_4318_TSSI;
1996203945Sweongyo	}
1997204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
1998203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
1999204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
2000204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
2001203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
2002203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
2003203945Sweongyo	bwn_hf_write(mac, hf);
2004203945Sweongyo
2005203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2006203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
2007203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
2008203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
2009203945Sweongyo
2010203945Sweongyo	bwn_rate_init(mac);
2011203945Sweongyo	bwn_set_phytxctl(mac);
2012203945Sweongyo
2013203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
2014203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
2015203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
2016203945Sweongyo
2017204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
2018203945Sweongyo		bwn_pio_init(mac);
2019203945Sweongyo	else
2020203945Sweongyo		bwn_dma_init(mac);
2021203945Sweongyo	bwn_wme_init(mac);
2022203945Sweongyo	bwn_spu_setdelay(mac, 1);
2023203945Sweongyo	bwn_bt_enable(mac);
2024203945Sweongyo
2025204922Sweongyo	siba_powerup(sc->sc_dev,
2026204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
2027203945Sweongyo	bwn_set_macaddr(mac);
2028203945Sweongyo	bwn_crypt_init(mac);
2029203945Sweongyo
2030203945Sweongyo	/* XXX LED initializatin */
2031203945Sweongyo
2032203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
2033203945Sweongyo
2034203945Sweongyo	return (error);
2035203945Sweongyo
2036203945Sweongyofail0:
2037204922Sweongyo	siba_powerdown(sc->sc_dev);
2038203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
2039203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2040203945Sweongyo	return (error);
2041203945Sweongyo}
2042203945Sweongyo
2043203945Sweongyostatic void
2044203945Sweongyobwn_core_start(struct bwn_mac *mac)
2045203945Sweongyo{
2046203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2047203945Sweongyo	uint32_t tmp;
2048203945Sweongyo
2049203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
2050203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2051203945Sweongyo
2052204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2053203945Sweongyo		return;
2054203945Sweongyo
2055203945Sweongyo	while (1) {
2056203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
2057203945Sweongyo		if (!(tmp & 0x00000001))
2058203945Sweongyo			break;
2059203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
2060203945Sweongyo	}
2061203945Sweongyo
2062203945Sweongyo	bwn_mac_enable(mac);
2063203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
2064203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
2065203945Sweongyo
2066203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
2067203945Sweongyo}
2068203945Sweongyo
2069203945Sweongyostatic void
2070203945Sweongyobwn_core_exit(struct bwn_mac *mac)
2071203945Sweongyo{
2072204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2073203945Sweongyo	uint32_t macctl;
2074203945Sweongyo
2075204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
2076203945Sweongyo
2077203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
2078203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2079203945Sweongyo
2080203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
2081203945Sweongyo		return;
2082203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
2083203945Sweongyo
2084203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
2085203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
2086203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
2087203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2088203945Sweongyo
2089203945Sweongyo	bwn_dma_stop(mac);
2090203945Sweongyo	bwn_pio_stop(mac);
2091203945Sweongyo	bwn_chip_exit(mac);
2092203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
2093204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
2094204922Sweongyo	siba_powerdown(sc->sc_dev);
2095203945Sweongyo}
2096203945Sweongyo
2097203945Sweongyostatic void
2098203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
2099203945Sweongyo{
2100203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2101203945Sweongyo
2102203945Sweongyo	(void)sc;
2103203945Sweongyo	/* XXX do nothing yet */
2104203945Sweongyo}
2105203945Sweongyo
2106203945Sweongyostatic int
2107203945Sweongyobwn_chip_init(struct bwn_mac *mac)
2108203945Sweongyo{
2109204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2110203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2111203945Sweongyo	uint32_t macctl;
2112203945Sweongyo	int error;
2113203945Sweongyo
2114203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
2115203945Sweongyo	if (phy->gmode)
2116203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
2117203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2118203945Sweongyo
2119203945Sweongyo	error = bwn_fw_fillinfo(mac);
2120203945Sweongyo	if (error)
2121203945Sweongyo		return (error);
2122203945Sweongyo	error = bwn_fw_loaducode(mac);
2123203945Sweongyo	if (error)
2124203945Sweongyo		return (error);
2125203945Sweongyo
2126203945Sweongyo	error = bwn_gpio_init(mac);
2127203945Sweongyo	if (error)
2128203945Sweongyo		return (error);
2129203945Sweongyo
2130203945Sweongyo	error = bwn_fw_loadinitvals(mac);
2131203945Sweongyo	if (error) {
2132204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2133203945Sweongyo		return (error);
2134203945Sweongyo	}
2135203945Sweongyo	phy->switch_analog(mac, 1);
2136203945Sweongyo	error = bwn_phy_init(mac);
2137203945Sweongyo	if (error) {
2138204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2139203945Sweongyo		return (error);
2140203945Sweongyo	}
2141203945Sweongyo	if (phy->set_im)
2142203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
2143203945Sweongyo	if (phy->set_antenna)
2144203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2145203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2146203945Sweongyo
2147203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
2148203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
2149203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
2150204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2151203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
2152203945Sweongyo
2153203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2154203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
2155203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2156203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
2157203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
2158203945Sweongyo
2159203945Sweongyo	bwn_set_opmode(mac);
2160204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
2161203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
2162203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
2163203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
2164203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
2165203945Sweongyo	} else {
2166203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
2167203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
2168203945Sweongyo	}
2169203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
2170203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
2171203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
2172203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
2173203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
2174203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
2175203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
2176204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
2177204922Sweongyo	    siba_read_4(sc->sc_dev, SIBA_TGSLOW) | 0x00100000);
2178204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
2179203945Sweongyo	return (error);
2180203945Sweongyo}
2181203945Sweongyo
2182203945Sweongyo/* read hostflags */
2183298944Sadrianuint64_t
2184203945Sweongyobwn_hf_read(struct bwn_mac *mac)
2185203945Sweongyo{
2186203945Sweongyo	uint64_t ret;
2187203945Sweongyo
2188203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
2189203945Sweongyo	ret <<= 16;
2190203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
2191203945Sweongyo	ret <<= 16;
2192203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
2193203945Sweongyo	return (ret);
2194203945Sweongyo}
2195203945Sweongyo
2196298944Sadrianvoid
2197203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
2198203945Sweongyo{
2199203945Sweongyo
2200203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
2201203945Sweongyo	    (value & 0x00000000ffffull));
2202203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
2203203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
2204203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
2205203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
2206203945Sweongyo}
2207203945Sweongyo
2208203945Sweongyostatic void
2209203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
2210203945Sweongyo{
2211203945Sweongyo
2212203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
2213203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
2214203945Sweongyo}
2215203945Sweongyo
2216203945Sweongyostatic void
2217203945Sweongyobwn_rate_init(struct bwn_mac *mac)
2218203945Sweongyo{
2219203945Sweongyo
2220203945Sweongyo	switch (mac->mac_phy.type) {
2221203945Sweongyo	case BWN_PHYTYPE_A:
2222203945Sweongyo	case BWN_PHYTYPE_G:
2223203945Sweongyo	case BWN_PHYTYPE_LP:
2224203945Sweongyo	case BWN_PHYTYPE_N:
2225203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
2226203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
2227203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
2228203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
2229203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
2230203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
2231203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
2232203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
2233203945Sweongyo			break;
2234203945Sweongyo		/* FALLTHROUGH */
2235203945Sweongyo	case BWN_PHYTYPE_B:
2236203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
2237203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
2238203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
2239203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
2240203945Sweongyo		break;
2241203945Sweongyo	default:
2242203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2243203945Sweongyo	}
2244203945Sweongyo}
2245203945Sweongyo
2246203945Sweongyostatic void
2247203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
2248203945Sweongyo{
2249203945Sweongyo	uint16_t offset;
2250203945Sweongyo
2251203945Sweongyo	if (ofdm) {
2252203945Sweongyo		offset = 0x480;
2253203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
2254203945Sweongyo	} else {
2255203945Sweongyo		offset = 0x4c0;
2256203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
2257203945Sweongyo	}
2258203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
2259203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
2260203945Sweongyo}
2261203945Sweongyo
2262203945Sweongyostatic uint8_t
2263203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
2264203945Sweongyo{
2265203945Sweongyo
2266203945Sweongyo	switch (bitrate) {
2267203945Sweongyo	case BWN_CCK_RATE_1MB:
2268203945Sweongyo		return (0x0a);
2269203945Sweongyo	case BWN_CCK_RATE_2MB:
2270203945Sweongyo		return (0x14);
2271203945Sweongyo	case BWN_CCK_RATE_5MB:
2272203945Sweongyo		return (0x37);
2273203945Sweongyo	case BWN_CCK_RATE_11MB:
2274203945Sweongyo		return (0x6e);
2275203945Sweongyo	}
2276203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2277203945Sweongyo	return (0);
2278203945Sweongyo}
2279203945Sweongyo
2280203945Sweongyostatic uint8_t
2281203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
2282203945Sweongyo{
2283203945Sweongyo
2284203945Sweongyo	switch (bitrate) {
2285203945Sweongyo	case BWN_OFDM_RATE_6MB:
2286203945Sweongyo		return (0xb);
2287203945Sweongyo	case BWN_OFDM_RATE_9MB:
2288203945Sweongyo		return (0xf);
2289203945Sweongyo	case BWN_OFDM_RATE_12MB:
2290203945Sweongyo		return (0xa);
2291203945Sweongyo	case BWN_OFDM_RATE_18MB:
2292203945Sweongyo		return (0xe);
2293203945Sweongyo	case BWN_OFDM_RATE_24MB:
2294203945Sweongyo		return (0x9);
2295203945Sweongyo	case BWN_OFDM_RATE_36MB:
2296203945Sweongyo		return (0xd);
2297203945Sweongyo	case BWN_OFDM_RATE_48MB:
2298203945Sweongyo		return (0x8);
2299203945Sweongyo	case BWN_OFDM_RATE_54MB:
2300203945Sweongyo		return (0xc);
2301203945Sweongyo	}
2302203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2303203945Sweongyo	return (0);
2304203945Sweongyo}
2305203945Sweongyo
2306203945Sweongyostatic void
2307203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
2308203945Sweongyo{
2309203945Sweongyo	uint16_t ctl;
2310203945Sweongyo
2311203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
2312203945Sweongyo	    BWN_TX_PHY_TXPWR);
2313203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
2314203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
2315203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
2316203945Sweongyo}
2317203945Sweongyo
2318203945Sweongyostatic void
2319203945Sweongyobwn_pio_init(struct bwn_mac *mac)
2320203945Sweongyo{
2321203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
2322203945Sweongyo
2323203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
2324203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
2325203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
2326203945Sweongyo
2327203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
2328203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
2329203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
2330203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
2331203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
2332203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
2333203945Sweongyo}
2334203945Sweongyo
2335203945Sweongyostatic void
2336203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2337203945Sweongyo    int index)
2338203945Sweongyo{
2339203945Sweongyo	struct bwn_pio_txpkt *tp;
2340204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2341203945Sweongyo	unsigned int i;
2342203945Sweongyo
2343203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
2344203945Sweongyo	tq->tq_index = index;
2345203945Sweongyo
2346203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
2347204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
2348203945Sweongyo		tq->tq_size = 1920;
2349203945Sweongyo	else {
2350203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
2351203945Sweongyo		tq->tq_size -= 80;
2352203945Sweongyo	}
2353203945Sweongyo
2354203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
2355203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2356203945Sweongyo		tp = &(tq->tq_pkts[i]);
2357203945Sweongyo		tp->tp_index = i;
2358203945Sweongyo		tp->tp_queue = tq;
2359203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
2360203945Sweongyo	}
2361203945Sweongyo}
2362203945Sweongyo
2363203945Sweongyostatic uint16_t
2364203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
2365203945Sweongyo{
2366203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2367203945Sweongyo	static const uint16_t bases[] = {
2368203945Sweongyo		BWN_PIO_BASE0,
2369203945Sweongyo		BWN_PIO_BASE1,
2370203945Sweongyo		BWN_PIO_BASE2,
2371203945Sweongyo		BWN_PIO_BASE3,
2372203945Sweongyo		BWN_PIO_BASE4,
2373203945Sweongyo		BWN_PIO_BASE5,
2374203945Sweongyo		BWN_PIO_BASE6,
2375203945Sweongyo		BWN_PIO_BASE7,
2376203945Sweongyo	};
2377203945Sweongyo	static const uint16_t bases_rev11[] = {
2378203945Sweongyo		BWN_PIO11_BASE0,
2379203945Sweongyo		BWN_PIO11_BASE1,
2380203945Sweongyo		BWN_PIO11_BASE2,
2381203945Sweongyo		BWN_PIO11_BASE3,
2382203945Sweongyo		BWN_PIO11_BASE4,
2383203945Sweongyo		BWN_PIO11_BASE5,
2384203945Sweongyo	};
2385203945Sweongyo
2386204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
2387203945Sweongyo		if (index >= N(bases_rev11))
2388203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
2389203945Sweongyo		return (bases_rev11[index]);
2390203945Sweongyo	}
2391203945Sweongyo	if (index >= N(bases))
2392203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
2393203945Sweongyo	return (bases[index]);
2394203945Sweongyo}
2395203945Sweongyo
2396203945Sweongyostatic void
2397203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
2398203945Sweongyo    int index)
2399203945Sweongyo{
2400204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2401203945Sweongyo
2402203945Sweongyo	prq->prq_mac = mac;
2403204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
2404203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
2405203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
2406203945Sweongyo}
2407203945Sweongyo
2408203945Sweongyostatic void
2409203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
2410203945Sweongyo{
2411203945Sweongyo	if (tq == NULL)
2412203945Sweongyo		return;
2413203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
2414203945Sweongyo}
2415203945Sweongyo
2416203945Sweongyostatic void
2417203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
2418203945Sweongyo{
2419203945Sweongyo
2420203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
2421203945Sweongyo}
2422203945Sweongyo
2423203945Sweongyostatic uint16_t
2424203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2425203945Sweongyo    uint16_t offset)
2426203945Sweongyo{
2427203945Sweongyo
2428203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
2429203945Sweongyo}
2430203945Sweongyo
2431203945Sweongyostatic void
2432203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
2433203945Sweongyo{
2434203945Sweongyo	uint32_t ctl;
2435203945Sweongyo	int type;
2436203945Sweongyo	uint16_t base;
2437203945Sweongyo
2438203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
2439203945Sweongyo	base = bwn_dma_base(type, idx);
2440203945Sweongyo	if (type == BWN_DMA_64BIT) {
2441203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
2442203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
2443203945Sweongyo		if (enable)
2444203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
2445203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
2446203945Sweongyo	} else {
2447203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
2448203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
2449203945Sweongyo		if (enable)
2450203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
2451203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
2452203945Sweongyo	}
2453203945Sweongyo}
2454203945Sweongyo
2455203945Sweongyostatic uint64_t
2456203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
2457203945Sweongyo{
2458203945Sweongyo	uint32_t tmp;
2459203945Sweongyo	uint16_t base;
2460203945Sweongyo
2461203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
2462203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
2463203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
2464203945Sweongyo	base = bwn_dma_base(0, 0);
2465203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
2466203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
2467203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
2468203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
2469203945Sweongyo
2470203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
2471203945Sweongyo}
2472203945Sweongyo
2473203945Sweongyostatic int
2474203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
2475203945Sweongyo{
2476203945Sweongyo
2477203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
2478203945Sweongyo		return (BWN_DMA_30BIT);
2479203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
2480203945Sweongyo		return (BWN_DMA_32BIT);
2481203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
2482203945Sweongyo		return (BWN_DMA_64BIT);
2483203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2484203945Sweongyo	return (BWN_DMA_30BIT);
2485203945Sweongyo}
2486203945Sweongyo
2487203945Sweongyostatic void
2488203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
2489203945Sweongyo{
2490203945Sweongyo	struct bwn_pio_txpkt *tp;
2491203945Sweongyo	unsigned int i;
2492203945Sweongyo
2493203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2494203945Sweongyo		tp = &(tq->tq_pkts[i]);
2495203945Sweongyo		if (tp->tp_m) {
2496203945Sweongyo			m_freem(tp->tp_m);
2497203945Sweongyo			tp->tp_m = NULL;
2498203945Sweongyo		}
2499203945Sweongyo	}
2500203945Sweongyo}
2501203945Sweongyo
2502203945Sweongyostatic uint16_t
2503203945Sweongyobwn_dma_base(int type, int controller_idx)
2504203945Sweongyo{
2505203945Sweongyo	static const uint16_t map64[] = {
2506203945Sweongyo		BWN_DMA64_BASE0,
2507203945Sweongyo		BWN_DMA64_BASE1,
2508203945Sweongyo		BWN_DMA64_BASE2,
2509203945Sweongyo		BWN_DMA64_BASE3,
2510203945Sweongyo		BWN_DMA64_BASE4,
2511203945Sweongyo		BWN_DMA64_BASE5,
2512203945Sweongyo	};
2513203945Sweongyo	static const uint16_t map32[] = {
2514203945Sweongyo		BWN_DMA32_BASE0,
2515203945Sweongyo		BWN_DMA32_BASE1,
2516203945Sweongyo		BWN_DMA32_BASE2,
2517203945Sweongyo		BWN_DMA32_BASE3,
2518203945Sweongyo		BWN_DMA32_BASE4,
2519203945Sweongyo		BWN_DMA32_BASE5,
2520203945Sweongyo	};
2521203945Sweongyo
2522203945Sweongyo	if (type == BWN_DMA_64BIT) {
2523203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
2524203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2525203945Sweongyo		return (map64[controller_idx]);
2526203945Sweongyo	}
2527203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
2528203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2529203945Sweongyo	return (map32[controller_idx]);
2530203945Sweongyo}
2531203945Sweongyo
2532203945Sweongyostatic void
2533203945Sweongyobwn_dma_init(struct bwn_mac *mac)
2534203945Sweongyo{
2535203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2536203945Sweongyo
2537203945Sweongyo	/* setup TX DMA channels. */
2538203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
2539203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
2540203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
2541203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
2542203945Sweongyo	bwn_dma_setup(dma->mcast);
2543203945Sweongyo	/* setup RX DMA channel. */
2544203945Sweongyo	bwn_dma_setup(dma->rx);
2545203945Sweongyo}
2546203945Sweongyo
2547203945Sweongyostatic struct bwn_dma_ring *
2548203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
2549203945Sweongyo    int for_tx, int type)
2550203945Sweongyo{
2551203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2552203945Sweongyo	struct bwn_dma_ring *dr;
2553203945Sweongyo	struct bwn_dmadesc_generic *desc;
2554203945Sweongyo	struct bwn_dmadesc_meta *mt;
2555203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2556203945Sweongyo	int error, i;
2557203945Sweongyo
2558203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
2559203945Sweongyo	if (dr == NULL)
2560203945Sweongyo		goto out;
2561203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
2562203945Sweongyo	if (for_tx)
2563203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
2564203945Sweongyo
2565203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
2566203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
2567203945Sweongyo	if (dr->dr_meta == NULL)
2568203945Sweongyo		goto fail0;
2569203945Sweongyo
2570203945Sweongyo	dr->dr_type = type;
2571203945Sweongyo	dr->dr_mac = mac;
2572203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
2573203945Sweongyo	dr->dr_index = controller_index;
2574203945Sweongyo	if (type == BWN_DMA_64BIT) {
2575203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
2576203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
2577203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
2578203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
2579203945Sweongyo		dr->resume = bwn_dma_64_resume;
2580203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
2581203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
2582203945Sweongyo	} else {
2583203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
2584203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
2585203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
2586203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
2587203945Sweongyo		dr->resume = bwn_dma_32_resume;
2588203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
2589203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
2590203945Sweongyo	}
2591203945Sweongyo	if (for_tx) {
2592203945Sweongyo		dr->dr_tx = 1;
2593203945Sweongyo		dr->dr_curslot = -1;
2594203945Sweongyo	} else {
2595203945Sweongyo		if (dr->dr_index == 0) {
2596203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
2597203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
2598203945Sweongyo		} else
2599203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2600203945Sweongyo	}
2601203945Sweongyo
2602203945Sweongyo	error = bwn_dma_allocringmemory(dr);
2603203945Sweongyo	if (error)
2604203945Sweongyo		goto fail2;
2605203945Sweongyo
2606203945Sweongyo	if (for_tx) {
2607203945Sweongyo		/*
2608203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
2609203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
2610203945Sweongyo		 */
2611203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
2612203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2613203945Sweongyo
2614203945Sweongyo		dr->dr_txhdr_cache =
2615203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
2616203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
2617203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
2618203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2619203945Sweongyo
2620203945Sweongyo		/*
2621203945Sweongyo		 * Create TX ring DMA stuffs
2622203945Sweongyo		 */
2623203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
2624203945Sweongyo				    BWN_ALIGN, 0,
2625203945Sweongyo				    BUS_SPACE_MAXADDR,
2626203945Sweongyo				    BUS_SPACE_MAXADDR,
2627203945Sweongyo				    NULL, NULL,
2628203945Sweongyo				    BWN_HDRSIZE(mac),
2629203945Sweongyo				    1,
2630203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
2631203945Sweongyo				    0,
2632203945Sweongyo				    NULL, NULL,
2633203945Sweongyo				    &dr->dr_txring_dtag);
2634203945Sweongyo		if (error) {
2635203945Sweongyo			device_printf(sc->sc_dev,
2636203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
2637203945Sweongyo			goto fail1;
2638203945Sweongyo		}
2639203945Sweongyo
2640203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
2641203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2642203945Sweongyo
2643203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
2644203945Sweongyo			mt->mt_m = NULL;
2645203945Sweongyo			mt->mt_ni = NULL;
2646203945Sweongyo			mt->mt_islast = 0;
2647203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
2648203945Sweongyo			    &mt->mt_dmap);
2649203945Sweongyo			if (error) {
2650203945Sweongyo				device_printf(sc->sc_dev,
2651203945Sweongyo				     "can't create RX buf DMA map\n");
2652203945Sweongyo				goto fail1;
2653203945Sweongyo			}
2654203945Sweongyo
2655203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
2656203945Sweongyo
2657203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
2658203945Sweongyo			mt->mt_m = NULL;
2659203945Sweongyo			mt->mt_ni = NULL;
2660203945Sweongyo			mt->mt_islast = 1;
2661203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
2662203945Sweongyo			    &mt->mt_dmap);
2663203945Sweongyo			if (error) {
2664203945Sweongyo				device_printf(sc->sc_dev,
2665203945Sweongyo				     "can't create RX buf DMA map\n");
2666203945Sweongyo				goto fail1;
2667203945Sweongyo			}
2668203945Sweongyo		}
2669203945Sweongyo	} else {
2670203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2671203945Sweongyo		    &dr->dr_spare_dmap);
2672203945Sweongyo		if (error) {
2673203945Sweongyo			device_printf(sc->sc_dev,
2674203945Sweongyo			    "can't create RX buf DMA map\n");
2675203945Sweongyo			goto out;		/* XXX wrong! */
2676203945Sweongyo		}
2677203945Sweongyo
2678203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
2679203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2680203945Sweongyo
2681203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2682203945Sweongyo			    &mt->mt_dmap);
2683203945Sweongyo			if (error) {
2684203945Sweongyo				device_printf(sc->sc_dev,
2685203945Sweongyo				    "can't create RX buf DMA map\n");
2686203945Sweongyo				goto out;	/* XXX wrong! */
2687203945Sweongyo			}
2688203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
2689203945Sweongyo			if (error) {
2690203945Sweongyo				device_printf(sc->sc_dev,
2691203945Sweongyo				    "failed to allocate RX buf\n");
2692203945Sweongyo				goto out;	/* XXX wrong! */
2693203945Sweongyo			}
2694203945Sweongyo		}
2695203945Sweongyo
2696203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
2697203945Sweongyo		    BUS_DMASYNC_PREWRITE);
2698203945Sweongyo
2699203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
2700203945Sweongyo	}
2701203945Sweongyo
2702203945Sweongyo      out:
2703203945Sweongyo	return (dr);
2704203945Sweongyo
2705203945Sweongyofail2:
2706203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
2707203945Sweongyofail1:
2708203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
2709203945Sweongyofail0:
2710203945Sweongyo	free(dr, M_DEVBUF);
2711203945Sweongyo	return (NULL);
2712203945Sweongyo}
2713203945Sweongyo
2714203945Sweongyostatic void
2715203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
2716203945Sweongyo{
2717203945Sweongyo
2718203945Sweongyo	if (dr == NULL)
2719203945Sweongyo		return;
2720203945Sweongyo
2721203945Sweongyo	bwn_dma_free_descbufs(*dr);
2722203945Sweongyo	bwn_dma_free_ringmemory(*dr);
2723203945Sweongyo
2724203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
2725203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
2726203945Sweongyo	free(*dr, M_DEVBUF);
2727203945Sweongyo
2728203945Sweongyo	*dr = NULL;
2729203945Sweongyo}
2730203945Sweongyo
2731203945Sweongyostatic void
2732203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
2733203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2734203945Sweongyo{
2735203945Sweongyo	struct bwn_dmadesc32 *desc;
2736203945Sweongyo
2737203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2738203945Sweongyo	desc = dr->dr_ring_descbase;
2739203945Sweongyo	desc = &(desc[slot]);
2740203945Sweongyo
2741203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2742203945Sweongyo}
2743203945Sweongyo
2744203945Sweongyostatic void
2745203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
2746203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2747203945Sweongyo    int start, int end, int irq)
2748203945Sweongyo{
2749203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
2750204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2751203945Sweongyo	uint32_t addr, addrext, ctl;
2752203945Sweongyo	int slot;
2753203945Sweongyo
2754203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
2755203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2756203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2757203945Sweongyo
2758203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
2759203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
2760204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
2761203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
2762203945Sweongyo	if (slot == dr->dr_numslots - 1)
2763203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
2764203945Sweongyo	if (start)
2765203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
2766203945Sweongyo	if (end)
2767203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
2768203945Sweongyo	if (irq)
2769203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
2770203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
2771203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
2772203945Sweongyo
2773203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
2774203945Sweongyo	desc->dma.dma32.address = htole32(addr);
2775203945Sweongyo}
2776203945Sweongyo
2777203945Sweongyostatic void
2778203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
2779203945Sweongyo{
2780203945Sweongyo
2781203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
2782203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
2783203945Sweongyo}
2784203945Sweongyo
2785203945Sweongyostatic void
2786203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
2787203945Sweongyo{
2788203945Sweongyo
2789203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2790203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
2791203945Sweongyo}
2792203945Sweongyo
2793203945Sweongyostatic void
2794203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
2795203945Sweongyo{
2796203945Sweongyo
2797203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2798203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
2799203945Sweongyo}
2800203945Sweongyo
2801203945Sweongyostatic int
2802203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
2803203945Sweongyo{
2804203945Sweongyo	uint32_t val;
2805203945Sweongyo
2806203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
2807203945Sweongyo	val &= BWN_DMA32_RXDPTR;
2808203945Sweongyo
2809203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
2810203945Sweongyo}
2811203945Sweongyo
2812203945Sweongyostatic void
2813203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
2814203945Sweongyo{
2815203945Sweongyo
2816203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
2817203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
2818203945Sweongyo}
2819203945Sweongyo
2820203945Sweongyostatic void
2821203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
2822203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2823203945Sweongyo{
2824203945Sweongyo	struct bwn_dmadesc64 *desc;
2825203945Sweongyo
2826203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2827203945Sweongyo	desc = dr->dr_ring_descbase;
2828203945Sweongyo	desc = &(desc[slot]);
2829203945Sweongyo
2830203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2831203945Sweongyo}
2832203945Sweongyo
2833203945Sweongyostatic void
2834203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
2835203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2836203945Sweongyo    int start, int end, int irq)
2837203945Sweongyo{
2838203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
2839204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2840203945Sweongyo	int slot;
2841203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
2842203945Sweongyo	uint32_t addrlo, addrhi;
2843203945Sweongyo	uint32_t addrext;
2844203945Sweongyo
2845203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
2846203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2847203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2848203945Sweongyo
2849203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
2850203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
2851203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
2852203945Sweongyo	    30;
2853204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
2854203945Sweongyo	if (slot == dr->dr_numslots - 1)
2855203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
2856203945Sweongyo	if (start)
2857203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
2858203945Sweongyo	if (end)
2859203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
2860203945Sweongyo	if (irq)
2861203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
2862203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
2863203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
2864203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
2865203945Sweongyo
2866203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
2867203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
2868203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
2869203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
2870203945Sweongyo}
2871203945Sweongyo
2872203945Sweongyostatic void
2873203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
2874203945Sweongyo{
2875203945Sweongyo
2876203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
2877203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
2878203945Sweongyo}
2879203945Sweongyo
2880203945Sweongyostatic void
2881203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
2882203945Sweongyo{
2883203945Sweongyo
2884203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
2885203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
2886203945Sweongyo}
2887203945Sweongyo
2888203945Sweongyostatic void
2889203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
2890203945Sweongyo{
2891203945Sweongyo
2892203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
2893203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
2894203945Sweongyo}
2895203945Sweongyo
2896203945Sweongyostatic int
2897203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
2898203945Sweongyo{
2899203945Sweongyo	uint32_t val;
2900203945Sweongyo
2901203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
2902203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
2903203945Sweongyo
2904203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
2905203945Sweongyo}
2906203945Sweongyo
2907203945Sweongyostatic void
2908203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
2909203945Sweongyo{
2910203945Sweongyo
2911203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
2912203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
2913203945Sweongyo}
2914203945Sweongyo
2915203945Sweongyostatic int
2916203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
2917203945Sweongyo{
2918203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
2919203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2920203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2921203945Sweongyo	int error;
2922203945Sweongyo
2923203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
2924203945Sweongyo			    BWN_ALIGN, 0,
2925203945Sweongyo			    BUS_SPACE_MAXADDR,
2926203945Sweongyo			    BUS_SPACE_MAXADDR,
2927203945Sweongyo			    NULL, NULL,
2928203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
2929203945Sweongyo			    1,
2930203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
2931203945Sweongyo			    0,
2932203945Sweongyo			    NULL, NULL,
2933203945Sweongyo			    &dr->dr_ring_dtag);
2934203945Sweongyo	if (error) {
2935203945Sweongyo		device_printf(sc->sc_dev,
2936203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
2937203945Sweongyo		return (-1);
2938203945Sweongyo	}
2939203945Sweongyo
2940203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
2941203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
2942203945Sweongyo	    &dr->dr_ring_dmap);
2943203945Sweongyo	if (error) {
2944203945Sweongyo		device_printf(sc->sc_dev,
2945203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
2946203945Sweongyo		return (-1);
2947203945Sweongyo	}
2948203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
2949203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
2950203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
2951203945Sweongyo	if (error) {
2952203945Sweongyo		device_printf(sc->sc_dev,
2953203945Sweongyo		    "can't load DMA mem: TODO free\n");
2954203945Sweongyo		return (-1);
2955203945Sweongyo	}
2956203945Sweongyo
2957203945Sweongyo	return (0);
2958203945Sweongyo}
2959203945Sweongyo
2960203945Sweongyostatic void
2961203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
2962203945Sweongyo{
2963204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2964203945Sweongyo	uint64_t ring64;
2965203945Sweongyo	uint32_t addrext, ring32, value;
2966204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
2967203945Sweongyo
2968203945Sweongyo	if (dr->dr_tx) {
2969203945Sweongyo		dr->dr_curslot = -1;
2970203945Sweongyo
2971203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
2972203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
2973203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
2974203945Sweongyo			    >> 30;
2975203945Sweongyo			value = BWN_DMA64_TXENABLE;
2976203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
2977203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
2978203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
2979203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
2980203945Sweongyo			    (ring64 & 0xffffffff));
2981203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
2982203945Sweongyo			    ((ring64 >> 32) &
2983203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
2984203945Sweongyo		} else {
2985203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
2986203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
2987203945Sweongyo			value = BWN_DMA32_TXENABLE;
2988203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
2989203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
2990203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
2991203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
2992203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
2993203945Sweongyo		}
2994203945Sweongyo		return;
2995203945Sweongyo	}
2996203945Sweongyo
2997203945Sweongyo	/*
2998203945Sweongyo	 * set for RX
2999203945Sweongyo	 */
3000203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
3001203945Sweongyo
3002203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
3003203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
3004203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
3005203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
3006203945Sweongyo		value |= BWN_DMA64_RXENABLE;
3007203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
3008203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
3009203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
3010203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
3011203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
3012203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
3013203945Sweongyo		    | (trans << 1));
3014203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
3015203945Sweongyo		    sizeof(struct bwn_dmadesc64));
3016203945Sweongyo	} else {
3017203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
3018203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
3019203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
3020203945Sweongyo		value |= BWN_DMA32_RXENABLE;
3021203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
3022203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
3023203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
3024203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
3025203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
3026203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
3027203945Sweongyo		    sizeof(struct bwn_dmadesc32));
3028203945Sweongyo	}
3029203945Sweongyo}
3030203945Sweongyo
3031203945Sweongyostatic void
3032203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
3033203945Sweongyo{
3034203945Sweongyo
3035203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
3036203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
3037203945Sweongyo	    dr->dr_ring_dmap);
3038203945Sweongyo}
3039203945Sweongyo
3040203945Sweongyostatic void
3041203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
3042203945Sweongyo{
3043203945Sweongyo
3044203945Sweongyo	if (dr->dr_tx) {
3045203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3046203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3047203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
3048203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
3049203945Sweongyo		} else
3050203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
3051203945Sweongyo	} else {
3052203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3053203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3054203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
3055203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
3056203945Sweongyo		} else
3057203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
3058203945Sweongyo	}
3059203945Sweongyo}
3060203945Sweongyo
3061203945Sweongyostatic void
3062203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
3063203945Sweongyo{
3064203945Sweongyo	struct bwn_dmadesc_generic *desc;
3065203945Sweongyo	struct bwn_dmadesc_meta *meta;
3066203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
3067203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3068203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3069203945Sweongyo	int i;
3070203945Sweongyo
3071203945Sweongyo	if (!dr->dr_usedslot)
3072203945Sweongyo		return;
3073203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
3074203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
3075203945Sweongyo
3076203945Sweongyo		if (meta->mt_m == NULL) {
3077203945Sweongyo			if (!dr->dr_tx)
3078203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
3079203945Sweongyo				    __func__);
3080203945Sweongyo			continue;
3081203945Sweongyo		}
3082203945Sweongyo		if (dr->dr_tx) {
3083203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
3084203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
3085203945Sweongyo				    meta->mt_dmap);
3086203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
3087203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
3088203945Sweongyo				    meta->mt_dmap);
3089203945Sweongyo		} else
3090203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
3091203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
3092203945Sweongyo	}
3093203945Sweongyo}
3094203945Sweongyo
3095203945Sweongyostatic int
3096203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
3097203945Sweongyo    int type)
3098203945Sweongyo{
3099203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3100203945Sweongyo	uint32_t value;
3101203945Sweongyo	int i;
3102203945Sweongyo	uint16_t offset;
3103203945Sweongyo
3104203945Sweongyo	for (i = 0; i < 10; i++) {
3105203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3106203945Sweongyo		    BWN_DMA32_TXSTATUS;
3107203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3108203945Sweongyo		if (type == BWN_DMA_64BIT) {
3109203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3110203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
3111203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
3112203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
3113203945Sweongyo				break;
3114203945Sweongyo		} else {
3115203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3116203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
3117203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
3118203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
3119203945Sweongyo				break;
3120203945Sweongyo		}
3121203945Sweongyo		DELAY(1000);
3122203945Sweongyo	}
3123203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
3124203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3125203945Sweongyo	for (i = 0; i < 10; i++) {
3126203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3127203945Sweongyo						   BWN_DMA32_TXSTATUS;
3128203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3129203945Sweongyo		if (type == BWN_DMA_64BIT) {
3130203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3131203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
3132203945Sweongyo				i = -1;
3133203945Sweongyo				break;
3134203945Sweongyo			}
3135203945Sweongyo		} else {
3136203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3137203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
3138203945Sweongyo				i = -1;
3139203945Sweongyo				break;
3140203945Sweongyo			}
3141203945Sweongyo		}
3142203945Sweongyo		DELAY(1000);
3143203945Sweongyo	}
3144203945Sweongyo	if (i != -1) {
3145203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3146203945Sweongyo		return (ENODEV);
3147203945Sweongyo	}
3148203945Sweongyo	DELAY(1000);
3149203945Sweongyo
3150203945Sweongyo	return (0);
3151203945Sweongyo}
3152203945Sweongyo
3153203945Sweongyostatic int
3154203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
3155203945Sweongyo    int type)
3156203945Sweongyo{
3157203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3158203945Sweongyo	uint32_t value;
3159203945Sweongyo	int i;
3160203945Sweongyo	uint16_t offset;
3161203945Sweongyo
3162203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
3163203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3164203945Sweongyo	for (i = 0; i < 10; i++) {
3165203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
3166203945Sweongyo		    BWN_DMA32_RXSTATUS;
3167203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3168203945Sweongyo		if (type == BWN_DMA_64BIT) {
3169203945Sweongyo			value &= BWN_DMA64_RXSTAT;
3170203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
3171203945Sweongyo				i = -1;
3172203945Sweongyo				break;
3173203945Sweongyo			}
3174203945Sweongyo		} else {
3175203945Sweongyo			value &= BWN_DMA32_RXSTATE;
3176203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
3177203945Sweongyo				i = -1;
3178203945Sweongyo				break;
3179203945Sweongyo			}
3180203945Sweongyo		}
3181203945Sweongyo		DELAY(1000);
3182203945Sweongyo	}
3183203945Sweongyo	if (i != -1) {
3184203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3185203945Sweongyo		return (ENODEV);
3186203945Sweongyo	}
3187203945Sweongyo
3188203945Sweongyo	return (0);
3189203945Sweongyo}
3190203945Sweongyo
3191203945Sweongyostatic void
3192203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
3193203945Sweongyo    struct bwn_dmadesc_meta *meta)
3194203945Sweongyo{
3195203945Sweongyo
3196203945Sweongyo	if (meta->mt_m != NULL) {
3197203945Sweongyo		m_freem(meta->mt_m);
3198203945Sweongyo		meta->mt_m = NULL;
3199203945Sweongyo	}
3200203945Sweongyo	if (meta->mt_ni != NULL) {
3201203945Sweongyo		ieee80211_free_node(meta->mt_ni);
3202203945Sweongyo		meta->mt_ni = NULL;
3203203945Sweongyo	}
3204203945Sweongyo}
3205203945Sweongyo
3206203945Sweongyostatic void
3207203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3208203945Sweongyo{
3209203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
3210203945Sweongyo	unsigned char *frame;
3211203945Sweongyo
3212203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
3213203945Sweongyo	rxhdr->frame_len = 0;
3214203945Sweongyo
3215203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
3216203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
3217203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3218203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
3219203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
3220203945Sweongyo}
3221203945Sweongyo
3222203945Sweongyostatic uint8_t
3223203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3224203945Sweongyo{
3225203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
3226203945Sweongyo
3227203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
3228203945Sweongyo	    == 0xff);
3229203945Sweongyo}
3230203945Sweongyo
3231203945Sweongyostatic void
3232203945Sweongyobwn_wme_init(struct bwn_mac *mac)
3233203945Sweongyo{
3234203945Sweongyo
3235203945Sweongyo	bwn_wme_load(mac);
3236203945Sweongyo
3237203945Sweongyo	/* enable WME support. */
3238203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
3239203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
3240203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
3241203945Sweongyo}
3242203945Sweongyo
3243203945Sweongyostatic void
3244203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
3245203945Sweongyo{
3246203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3247287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3248203945Sweongyo	uint16_t delay;	/* microsec */
3249203945Sweongyo
3250203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
3251203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
3252203945Sweongyo		delay = 500;
3253203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
3254203945Sweongyo		delay = max(delay, (uint16_t)2400);
3255203945Sweongyo
3256203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
3257203945Sweongyo}
3258203945Sweongyo
3259203945Sweongyostatic void
3260203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
3261203945Sweongyo{
3262204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3263203945Sweongyo	uint64_t hf;
3264203945Sweongyo
3265203945Sweongyo	if (bwn_bluetooth == 0)
3266203945Sweongyo		return;
3267204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
3268203945Sweongyo		return;
3269203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
3270203945Sweongyo		return;
3271203945Sweongyo
3272203945Sweongyo	hf = bwn_hf_read(mac);
3273204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
3274203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
3275203945Sweongyo	else
3276203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
3277203945Sweongyo	bwn_hf_write(mac, hf);
3278203945Sweongyo}
3279203945Sweongyo
3280203945Sweongyostatic void
3281203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
3282203945Sweongyo{
3283203945Sweongyo
3284203945Sweongyo	bwn_mac_write_bssid(mac);
3285287197Sglebius	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF,
3286287197Sglebius	    mac->mac_sc->sc_ic.ic_macaddr);
3287203945Sweongyo}
3288203945Sweongyo
3289203945Sweongyostatic void
3290203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
3291203945Sweongyo{
3292203945Sweongyo	int i;
3293203945Sweongyo
3294203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
3295203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
3296203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3297203945Sweongyo
3298203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
3299203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
3300203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
3301203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
3302203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
3303203945Sweongyo		}
3304203945Sweongyo		mac->mac_key[i].keyconf = NULL;
3305203945Sweongyo	}
3306203945Sweongyo}
3307203945Sweongyo
3308203945Sweongyostatic void
3309203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
3310203945Sweongyo{
3311204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3312203945Sweongyo
3313204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
3314203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
3315203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3316203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
3317203945Sweongyo	mac->mac_ktp *= 2;
3318204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
3319204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
3320203945Sweongyo	bwn_clear_keys(mac);
3321203945Sweongyo}
3322203945Sweongyo
3323203945Sweongyostatic void
3324203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
3325203945Sweongyo{
3326204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3327203945Sweongyo
3328203945Sweongyo	bwn_phy_exit(mac);
3329204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
3330203945Sweongyo}
3331203945Sweongyo
3332203945Sweongyostatic int
3333203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
3334203945Sweongyo{
3335203945Sweongyo	int error;
3336203945Sweongyo
3337203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
3338203945Sweongyo	if (error == 0)
3339203945Sweongyo		return (0);
3340203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
3341203945Sweongyo	if (error == 0)
3342203945Sweongyo		return (0);
3343203945Sweongyo	return (error);
3344203945Sweongyo}
3345203945Sweongyo
3346203945Sweongyostatic int
3347203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
3348203945Sweongyo{
3349204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3350204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
3351203945Sweongyo
3352203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3353203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
3354203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
3355203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
3356203945Sweongyo
3357204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
3358203945Sweongyo		mask |= 0x0060;
3359203945Sweongyo		set |= 0x0060;
3360203945Sweongyo	}
3361204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
3362203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
3363203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
3364203945Sweongyo		mask |= 0x0200;
3365203945Sweongyo		set |= 0x0200;
3366203945Sweongyo	}
3367204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
3368203945Sweongyo		mask |= 0x0010;
3369204922Sweongyo
3370204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
3371204922Sweongyo	if (value == -1)
3372203945Sweongyo		return (0);
3373204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
3374203945Sweongyo
3375203945Sweongyo	return (0);
3376203945Sweongyo}
3377203945Sweongyo
3378203945Sweongyostatic int
3379203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
3380203945Sweongyo{
3381203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
3382203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
3383203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
3384203945Sweongyo	const struct bwn_fwhdr *hdr;
3385203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3386203945Sweongyo	int error;
3387203945Sweongyo
3388203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
3389203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
3390203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
3391203945Sweongyo	if (error)
3392203945Sweongyo		return (error);
3393203945Sweongyo	if (fw->initvals_band.fw) {
3394203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
3395203945Sweongyo		error = bwn_fwinitvals_write(mac,
3396203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
3397203945Sweongyo		    be32toh(hdr->size),
3398203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
3399203945Sweongyo	}
3400203945Sweongyo	return (error);
3401203945Sweongyo#undef GETFWOFFSET
3402203945Sweongyo}
3403203945Sweongyo
3404203945Sweongyostatic int
3405203945Sweongyobwn_phy_init(struct bwn_mac *mac)
3406203945Sweongyo{
3407203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3408203945Sweongyo	int error;
3409203945Sweongyo
3410203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
3411203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
3412203945Sweongyo	error = mac->mac_phy.init(mac);
3413203945Sweongyo	if (error) {
3414203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
3415203945Sweongyo		goto fail0;
3416203945Sweongyo	}
3417203945Sweongyo	error = bwn_switch_channel(mac,
3418203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
3419203945Sweongyo	if (error) {
3420203945Sweongyo		device_printf(sc->sc_dev,
3421203945Sweongyo		    "failed to switch default channel\n");
3422203945Sweongyo		goto fail1;
3423203945Sweongyo	}
3424203945Sweongyo	return (0);
3425203945Sweongyofail1:
3426203945Sweongyo	if (mac->mac_phy.exit)
3427203945Sweongyo		mac->mac_phy.exit(mac);
3428203945Sweongyofail0:
3429203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
3430203945Sweongyo
3431203945Sweongyo	return (error);
3432203945Sweongyo}
3433203945Sweongyo
3434203945Sweongyostatic void
3435203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
3436203945Sweongyo{
3437203945Sweongyo	uint16_t ant;
3438203945Sweongyo	uint16_t tmp;
3439203945Sweongyo
3440203945Sweongyo	ant = bwn_ant2phy(antenna);
3441203945Sweongyo
3442203945Sweongyo	/* For ACK/CTS */
3443203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
3444203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3445203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
3446203945Sweongyo	/* For Probe Resposes */
3447203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
3448203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3449203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
3450203945Sweongyo}
3451203945Sweongyo
3452203945Sweongyostatic void
3453203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
3454203945Sweongyo{
3455203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3456287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3457203945Sweongyo	uint32_t ctl;
3458203945Sweongyo	uint16_t cfp_pretbtt;
3459203945Sweongyo
3460203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
3461203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
3462203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
3463203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
3464203945Sweongyo	ctl |= BWN_MACCTL_STA;
3465203945Sweongyo
3466203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
3467203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
3468203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
3469203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
3470203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
3471203945Sweongyo	ctl |= sc->sc_filters;
3472203945Sweongyo
3473204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
3474203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
3475203945Sweongyo
3476203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
3477203945Sweongyo
3478203945Sweongyo	cfp_pretbtt = 2;
3479203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
3480204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
3481204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
3482203945Sweongyo			cfp_pretbtt = 100;
3483203945Sweongyo		else
3484203945Sweongyo			cfp_pretbtt = 50;
3485203945Sweongyo	}
3486203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
3487203945Sweongyo}
3488203945Sweongyo
3489203945Sweongyostatic int
3490203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
3491203945Sweongyo{
3492203945Sweongyo	uint32_t tmp;
3493203945Sweongyo	uint16_t base;
3494203945Sweongyo
3495203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3496203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3497203945Sweongyo		return (BWN_DMA_64BIT);
3498203945Sweongyo	base = bwn_dma_base(0, 0);
3499203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3500203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3501203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3502203945Sweongyo		return (BWN_DMA_32BIT);
3503203945Sweongyo
3504203945Sweongyo	return (BWN_DMA_30BIT);
3505203945Sweongyo}
3506203945Sweongyo
3507203945Sweongyostatic void
3508203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
3509203945Sweongyo{
3510203945Sweongyo	if (!error) {
3511203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
3512203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
3513203945Sweongyo	}
3514203945Sweongyo}
3515203945Sweongyo
3516298948Sadrianvoid
3517298952Sadrianbwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
3518298952Sadrian{
3519298952Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3520298952Sadrian	struct bwn_softc *sc = mac->mac_sc;
3521298952Sadrian	unsigned int i, max_loop;
3522298952Sadrian	uint16_t value;
3523298952Sadrian	uint32_t buffer[5] = {
3524298952Sadrian		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
3525298952Sadrian	};
3526298952Sadrian
3527298952Sadrian	if (ofdm) {
3528298952Sadrian		max_loop = 0x1e;
3529298952Sadrian		buffer[0] = 0x000201cc;
3530298952Sadrian	} else {
3531298952Sadrian		max_loop = 0xfa;
3532298952Sadrian		buffer[0] = 0x000b846e;
3533298952Sadrian	}
3534298952Sadrian
3535298952Sadrian	BWN_ASSERT_LOCKED(mac->mac_sc);
3536298952Sadrian
3537298952Sadrian	for (i = 0; i < 5; i++)
3538298952Sadrian		bwn_ram_write(mac, i * 4, buffer[i]);
3539298952Sadrian
3540298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0000);
3541298952Sadrian	BWN_WRITE_2(mac, 0x07c0,
3542298952Sadrian	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
3543298954Sadrian
3544298954Sadrian	value = (ofdm ? 0x41 : 0x40);
3545298952Sadrian	BWN_WRITE_2(mac, 0x050c, value);
3546298954Sadrian
3547298954Sadrian	if (phy->type == BWN_PHYTYPE_N || phy->type == BWN_PHYTYPE_LP ||
3548298954Sadrian	    phy->type == BWN_PHYTYPE_LCN)
3549298952Sadrian		BWN_WRITE_2(mac, 0x0514, 0x1a02);
3550298952Sadrian	BWN_WRITE_2(mac, 0x0508, 0x0000);
3551298952Sadrian	BWN_WRITE_2(mac, 0x050a, 0x0000);
3552298952Sadrian	BWN_WRITE_2(mac, 0x054c, 0x0000);
3553298952Sadrian	BWN_WRITE_2(mac, 0x056a, 0x0014);
3554298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0826);
3555298952Sadrian	BWN_WRITE_2(mac, 0x0500, 0x0000);
3556298954Sadrian
3557298954Sadrian	/* XXX TODO: n phy pa override? */
3558298954Sadrian
3559298954Sadrian	switch (phy->type) {
3560298954Sadrian	case BWN_PHYTYPE_N:
3561298954Sadrian	case BWN_PHYTYPE_LCN:
3562298954Sadrian		BWN_WRITE_2(mac, 0x0502, 0x00d0);
3563298954Sadrian		break;
3564298954Sadrian	case BWN_PHYTYPE_LP:
3565298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0050);
3566298954Sadrian		break;
3567298954Sadrian	default:
3568298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0030);
3569298954Sadrian		break;
3570298954Sadrian	}
3571298952Sadrian
3572298954Sadrian	/* flush */
3573298954Sadrian	BWN_READ_2(mac, 0x0502);
3574298954Sadrian
3575298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3576298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0017);
3577298952Sadrian	for (i = 0x00; i < max_loop; i++) {
3578298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3579298952Sadrian		if (value & 0x0080)
3580298952Sadrian			break;
3581298952Sadrian		DELAY(10);
3582298952Sadrian	}
3583298952Sadrian	for (i = 0x00; i < 0x0a; i++) {
3584298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3585298952Sadrian		if (value & 0x0400)
3586298952Sadrian			break;
3587298952Sadrian		DELAY(10);
3588298952Sadrian	}
3589298952Sadrian	for (i = 0x00; i < 0x19; i++) {
3590298952Sadrian		value = BWN_READ_2(mac, 0x0690);
3591298952Sadrian		if (!(value & 0x0100))
3592298952Sadrian			break;
3593298952Sadrian		DELAY(10);
3594298952Sadrian	}
3595298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3596298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0037);
3597298952Sadrian}
3598298952Sadrian
3599298952Sadrianvoid
3600203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
3601203945Sweongyo{
3602203945Sweongyo	uint32_t macctl;
3603203945Sweongyo
3604203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
3605203945Sweongyo
3606203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3607203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
3608203945Sweongyo		printf("TODO: need swap\n");
3609203945Sweongyo
3610203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
3611203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
3612203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
3613203945Sweongyo}
3614203945Sweongyo
3615298944Sadrianvoid
3616203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
3617203945Sweongyo{
3618203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3619203945Sweongyo	int i;
3620203945Sweongyo	uint32_t tmp;
3621203945Sweongyo
3622203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3623203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3624203945Sweongyo
3625203945Sweongyo	if (mac->mac_suspended == 0) {
3626203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
3627203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3628203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
3629203945Sweongyo			    & ~BWN_MACCTL_ON);
3630203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3631203945Sweongyo		for (i = 35; i; i--) {
3632203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3633203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3634203945Sweongyo				goto out;
3635203945Sweongyo			DELAY(10);
3636203945Sweongyo		}
3637203945Sweongyo		for (i = 40; i; i--) {
3638203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3639203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3640203945Sweongyo				goto out;
3641203945Sweongyo			DELAY(1000);
3642203945Sweongyo		}
3643203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
3644203945Sweongyo	}
3645203945Sweongyoout:
3646203945Sweongyo	mac->mac_suspended++;
3647203945Sweongyo}
3648203945Sweongyo
3649298944Sadrianvoid
3650203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
3651203945Sweongyo{
3652203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3653203945Sweongyo	uint16_t state;
3654203945Sweongyo
3655203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
3656203945Sweongyo	    BWN_SHARED_UCODESTAT);
3657203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
3658203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
3659203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
3660203945Sweongyo
3661203945Sweongyo	mac->mac_suspended--;
3662203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3663203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3664203945Sweongyo	if (mac->mac_suspended == 0) {
3665203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3666203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
3667203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
3668203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3669203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
3670203945Sweongyo		bwn_psctl(mac, 0);
3671203945Sweongyo	}
3672203945Sweongyo}
3673203945Sweongyo
3674298948Sadrianvoid
3675203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
3676203945Sweongyo{
3677204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3678203945Sweongyo	int i;
3679203945Sweongyo	uint16_t ucstat;
3680203945Sweongyo
3681203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
3682203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3683203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
3684203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3685203945Sweongyo
3686203945Sweongyo	/* XXX forcibly awake and hwps-off */
3687203945Sweongyo
3688203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3689203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
3690203945Sweongyo	    ~BWN_MACCTL_HWPS);
3691203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
3692204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
3693203945Sweongyo		for (i = 0; i < 100; i++) {
3694203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
3695203945Sweongyo			    BWN_SHARED_UCODESTAT);
3696203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
3697203945Sweongyo				break;
3698203945Sweongyo			DELAY(10);
3699203945Sweongyo		}
3700203945Sweongyo	}
3701203945Sweongyo}
3702203945Sweongyo
3703203945Sweongyostatic int
3704203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
3705203945Sweongyo{
3706203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3707203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3708204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
3709203945Sweongyo	const char *filename;
3710203945Sweongyo	uint32_t high;
3711203945Sweongyo	int error;
3712203945Sweongyo
3713203945Sweongyo	/* microcode */
3714203945Sweongyo	if (rev >= 5 && rev <= 10)
3715203945Sweongyo		filename = "ucode5";
3716203945Sweongyo	else if (rev >= 11 && rev <= 12)
3717203945Sweongyo		filename = "ucode11";
3718203945Sweongyo	else if (rev == 13)
3719203945Sweongyo		filename = "ucode13";
3720203945Sweongyo	else if (rev == 14)
3721203945Sweongyo		filename = "ucode14";
3722203945Sweongyo	else if (rev >= 15)
3723203945Sweongyo		filename = "ucode15";
3724203945Sweongyo	else {
3725203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
3726203945Sweongyo		bwn_release_firmware(mac);
3727203945Sweongyo		return (EOPNOTSUPP);
3728203945Sweongyo	}
3729203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
3730203945Sweongyo	if (error) {
3731203945Sweongyo		bwn_release_firmware(mac);
3732203945Sweongyo		return (error);
3733203945Sweongyo	}
3734203945Sweongyo
3735203945Sweongyo	/* PCM */
3736203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
3737203945Sweongyo	if (rev >= 5 && rev <= 10) {
3738203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
3739203945Sweongyo		if (error == ENOENT)
3740203945Sweongyo			fw->no_pcmfile = 1;
3741203945Sweongyo		else if (error) {
3742203945Sweongyo			bwn_release_firmware(mac);
3743203945Sweongyo			return (error);
3744203945Sweongyo		}
3745203945Sweongyo	} else if (rev < 11) {
3746203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
3747203945Sweongyo		return (EOPNOTSUPP);
3748203945Sweongyo	}
3749203945Sweongyo
3750203945Sweongyo	/* initvals */
3751204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
3752203945Sweongyo	switch (mac->mac_phy.type) {
3753203945Sweongyo	case BWN_PHYTYPE_A:
3754203945Sweongyo		if (rev < 5 || rev > 10)
3755203945Sweongyo			goto fail1;
3756203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
3757203945Sweongyo			filename = "a0g1initvals5";
3758203945Sweongyo		else
3759203945Sweongyo			filename = "a0g0initvals5";
3760203945Sweongyo		break;
3761203945Sweongyo	case BWN_PHYTYPE_G:
3762203945Sweongyo		if (rev >= 5 && rev <= 10)
3763203945Sweongyo			filename = "b0g0initvals5";
3764203945Sweongyo		else if (rev >= 13)
3765203945Sweongyo			filename = "b0g0initvals13";
3766203945Sweongyo		else
3767203945Sweongyo			goto fail1;
3768203945Sweongyo		break;
3769203945Sweongyo	case BWN_PHYTYPE_LP:
3770203945Sweongyo		if (rev == 13)
3771203945Sweongyo			filename = "lp0initvals13";
3772203945Sweongyo		else if (rev == 14)
3773203945Sweongyo			filename = "lp0initvals14";
3774203945Sweongyo		else if (rev >= 15)
3775203945Sweongyo			filename = "lp0initvals15";
3776203945Sweongyo		else
3777203945Sweongyo			goto fail1;
3778203945Sweongyo		break;
3779203945Sweongyo	case BWN_PHYTYPE_N:
3780203945Sweongyo		if (rev >= 11 && rev <= 12)
3781203945Sweongyo			filename = "n0initvals11";
3782203945Sweongyo		else
3783203945Sweongyo			goto fail1;
3784203945Sweongyo		break;
3785203945Sweongyo	default:
3786203945Sweongyo		goto fail1;
3787203945Sweongyo	}
3788203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
3789203945Sweongyo	if (error) {
3790203945Sweongyo		bwn_release_firmware(mac);
3791203945Sweongyo		return (error);
3792203945Sweongyo	}
3793203945Sweongyo
3794203945Sweongyo	/* bandswitch initvals */
3795203945Sweongyo	switch (mac->mac_phy.type) {
3796203945Sweongyo	case BWN_PHYTYPE_A:
3797203945Sweongyo		if (rev >= 5 && rev <= 10) {
3798203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
3799203945Sweongyo				filename = "a0g1bsinitvals5";
3800203945Sweongyo			else
3801203945Sweongyo				filename = "a0g0bsinitvals5";
3802203945Sweongyo		} else if (rev >= 11)
3803203945Sweongyo			filename = NULL;
3804203945Sweongyo		else
3805203945Sweongyo			goto fail1;
3806203945Sweongyo		break;
3807203945Sweongyo	case BWN_PHYTYPE_G:
3808203945Sweongyo		if (rev >= 5 && rev <= 10)
3809203945Sweongyo			filename = "b0g0bsinitvals5";
3810203945Sweongyo		else if (rev >= 11)
3811203945Sweongyo			filename = NULL;
3812203945Sweongyo		else
3813203945Sweongyo			goto fail1;
3814203945Sweongyo		break;
3815203945Sweongyo	case BWN_PHYTYPE_LP:
3816203945Sweongyo		if (rev == 13)
3817203945Sweongyo			filename = "lp0bsinitvals13";
3818203945Sweongyo		else if (rev == 14)
3819203945Sweongyo			filename = "lp0bsinitvals14";
3820203945Sweongyo		else if (rev >= 15)
3821203945Sweongyo			filename = "lp0bsinitvals15";
3822203945Sweongyo		else
3823203945Sweongyo			goto fail1;
3824203945Sweongyo		break;
3825203945Sweongyo	case BWN_PHYTYPE_N:
3826203945Sweongyo		if (rev >= 11 && rev <= 12)
3827203945Sweongyo			filename = "n0bsinitvals11";
3828203945Sweongyo		else
3829203945Sweongyo			goto fail1;
3830203945Sweongyo		break;
3831203945Sweongyo	default:
3832203945Sweongyo		goto fail1;
3833203945Sweongyo	}
3834203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
3835203945Sweongyo	if (error) {
3836203945Sweongyo		bwn_release_firmware(mac);
3837203945Sweongyo		return (error);
3838203945Sweongyo	}
3839203945Sweongyo	return (0);
3840203945Sweongyofail1:
3841203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
3842203945Sweongyo	bwn_release_firmware(mac);
3843203945Sweongyo	return (EOPNOTSUPP);
3844203945Sweongyo}
3845203945Sweongyo
3846203945Sweongyostatic int
3847203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
3848203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
3849203945Sweongyo{
3850203945Sweongyo	const struct bwn_fwhdr *hdr;
3851203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3852203945Sweongyo	const struct firmware *fw;
3853203945Sweongyo	char namebuf[64];
3854203945Sweongyo
3855203945Sweongyo	if (name == NULL) {
3856203945Sweongyo		bwn_do_release_fw(bfw);
3857203945Sweongyo		return (0);
3858203945Sweongyo	}
3859203945Sweongyo	if (bfw->filename != NULL) {
3860203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
3861203945Sweongyo			return (0);
3862203945Sweongyo		bwn_do_release_fw(bfw);
3863203945Sweongyo	}
3864203945Sweongyo
3865204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
3866204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
3867204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
3868203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
3869203945Sweongyo	fw = firmware_get(namebuf);
3870203945Sweongyo	if (fw == NULL) {
3871203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
3872203945Sweongyo		    namebuf);
3873203945Sweongyo		return (ENOENT);
3874203945Sweongyo	}
3875203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
3876203945Sweongyo		goto fail;
3877203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
3878203945Sweongyo	switch (hdr->type) {
3879203945Sweongyo	case BWN_FWTYPE_UCODE:
3880203945Sweongyo	case BWN_FWTYPE_PCM:
3881203945Sweongyo		if (be32toh(hdr->size) !=
3882203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
3883203945Sweongyo			goto fail;
3884203945Sweongyo		/* FALLTHROUGH */
3885203945Sweongyo	case BWN_FWTYPE_IV:
3886203945Sweongyo		if (hdr->ver != 1)
3887203945Sweongyo			goto fail;
3888203945Sweongyo		break;
3889203945Sweongyo	default:
3890203945Sweongyo		goto fail;
3891203945Sweongyo	}
3892203945Sweongyo	bfw->filename = name;
3893203945Sweongyo	bfw->fw = fw;
3894203945Sweongyo	bfw->type = type;
3895203945Sweongyo	return (0);
3896203945Sweongyofail:
3897203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
3898203945Sweongyo	if (fw != NULL)
3899203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
3900203945Sweongyo	return (EPROTO);
3901203945Sweongyo}
3902203945Sweongyo
3903203945Sweongyostatic void
3904203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
3905203945Sweongyo{
3906203945Sweongyo
3907203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
3908203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
3909203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
3910203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
3911203945Sweongyo}
3912203945Sweongyo
3913203945Sweongyostatic void
3914203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
3915203945Sweongyo{
3916203945Sweongyo
3917203945Sweongyo	if (bfw->fw != NULL)
3918203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
3919203945Sweongyo	bfw->fw = NULL;
3920203945Sweongyo	bfw->filename = NULL;
3921203945Sweongyo}
3922203945Sweongyo
3923203945Sweongyostatic int
3924203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
3925203945Sweongyo{
3926203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
3927203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
3928203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
3929203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
3930203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3931203945Sweongyo	const uint32_t *data;
3932203945Sweongyo	unsigned int i;
3933203945Sweongyo	uint32_t ctl;
3934203945Sweongyo	uint16_t date, fwcaps, time;
3935203945Sweongyo	int error = 0;
3936203945Sweongyo
3937203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
3938203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
3939203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
3940203945Sweongyo	    __LINE__));
3941203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
3942203945Sweongyo	for (i = 0; i < 64; i++)
3943203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
3944203945Sweongyo	for (i = 0; i < 4096; i += 2)
3945203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
3946203945Sweongyo
3947203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
3948203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
3949203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
3950203945Sweongyo	     i++) {
3951203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
3952203945Sweongyo		DELAY(10);
3953203945Sweongyo	}
3954203945Sweongyo
3955203945Sweongyo	if (mac->mac_fw.pcm.fw) {
3956203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
3957203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
3958203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
3959203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
3960203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
3961203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
3962203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
3963203945Sweongyo			DELAY(10);
3964203945Sweongyo		}
3965203945Sweongyo	}
3966203945Sweongyo
3967203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
3968203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3969203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
3970203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
3971203945Sweongyo
3972203945Sweongyo	for (i = 0; i < 21; i++) {
3973203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
3974203945Sweongyo			break;
3975203945Sweongyo		if (i >= 20) {
3976203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
3977203945Sweongyo			error = ENXIO;
3978203945Sweongyo			goto error;
3979203945Sweongyo		}
3980203945Sweongyo		DELAY(50000);
3981203945Sweongyo	}
3982203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
3983203945Sweongyo
3984203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
3985203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
3986203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
3987203945Sweongyo		error = EOPNOTSUPP;
3988203945Sweongyo		goto error;
3989203945Sweongyo	}
3990299110Sadrian
3991299110Sadrian	/*
3992299110Sadrian	 * Determine firmware header version; needed for TX/RX packet
3993299110Sadrian	 * handling.
3994299110Sadrian	 */
3995299110Sadrian	if (mac->mac_fw.rev >= 598)
3996299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_598;
3997299110Sadrian	else if (mac->mac_fw.rev >= 410)
3998299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_410;
3999299110Sadrian	else
4000299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_351;
4001299110Sadrian
4002299110Sadrian	/*
4003299110Sadrian	 * We don't support rev 598 or later; that requires
4004299110Sadrian	 * another round of changes to the TX/RX descriptor
4005299110Sadrian	 * and status layout.
4006299110Sadrian	 *
4007299110Sadrian	 * So, complain this is the case and exit out, rather
4008299110Sadrian	 * than attaching and then failing.
4009299110Sadrian	 */
4010299110Sadrian	if (mac->mac_fw.fw_hdr_format == BWN_FW_HDR_598) {
4011299110Sadrian		device_printf(sc->sc_dev,
4012299110Sadrian		    "firmware is too new (>=598); not supported\n");
4013299110Sadrian		error = EOPNOTSUPP;
4014299110Sadrian		goto error;
4015299110Sadrian	}
4016299110Sadrian
4017203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
4018203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
4019203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
4020203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
4021203945Sweongyo	if (bwn_wme != 0)
4022203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
4023203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
4024203945Sweongyo
4025203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
4026203945Sweongyo	if (mac->mac_fw.opensource == 0) {
4027203945Sweongyo		device_printf(sc->sc_dev,
4028203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
4029203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
4030203945Sweongyo		if (mac->mac_fw.no_pcmfile)
4031203945Sweongyo			device_printf(sc->sc_dev,
4032203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
4033203945Sweongyo	} else {
4034203945Sweongyo		mac->mac_fw.patch = time;
4035203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
4036203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
4037203945Sweongyo			device_printf(sc->sc_dev,
4038203945Sweongyo			    "disabling HW crypto acceleration\n");
4039203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
4040203945Sweongyo		}
4041203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
4042203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
4043203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
4044203945Sweongyo		}
4045203945Sweongyo	}
4046203945Sweongyo
4047203945Sweongyo	if (BWN_ISOLDFMT(mac))
4048203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
4049203945Sweongyo
4050203945Sweongyo	return (0);
4051203945Sweongyo
4052203945Sweongyoerror:
4053203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4054203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
4055203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
4056203945Sweongyo
4057203945Sweongyo	return (error);
4058203945Sweongyo#undef GETFWSIZE
4059203945Sweongyo#undef GETFWOFFSET
4060203945Sweongyo}
4061203945Sweongyo
4062203945Sweongyo/* OpenFirmware only */
4063203945Sweongyostatic uint16_t
4064203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
4065203945Sweongyo{
4066203945Sweongyo
4067203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
4068203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4069203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
4070203945Sweongyo}
4071203945Sweongyo
4072203945Sweongyostatic int
4073203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
4074203945Sweongyo    size_t count, size_t array_size)
4075203945Sweongyo{
4076203945Sweongyo#define	GET_NEXTIV16(iv)						\
4077203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4078203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
4079203945Sweongyo#define	GET_NEXTIV32(iv)						\
4080203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4081203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
4082203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4083203945Sweongyo	const struct bwn_fwinitvals *iv;
4084203945Sweongyo	uint16_t offset;
4085203945Sweongyo	size_t i;
4086203945Sweongyo	uint8_t bit32;
4087203945Sweongyo
4088203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
4089203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4090203945Sweongyo	iv = ivals;
4091203945Sweongyo	for (i = 0; i < count; i++) {
4092203945Sweongyo		if (array_size < sizeof(iv->offset_size))
4093203945Sweongyo			goto fail;
4094203945Sweongyo		array_size -= sizeof(iv->offset_size);
4095203945Sweongyo		offset = be16toh(iv->offset_size);
4096203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
4097203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
4098203945Sweongyo		if (offset >= 0x1000)
4099203945Sweongyo			goto fail;
4100203945Sweongyo		if (bit32) {
4101203945Sweongyo			if (array_size < sizeof(iv->data.d32))
4102203945Sweongyo				goto fail;
4103203945Sweongyo			array_size -= sizeof(iv->data.d32);
4104203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
4105203945Sweongyo			iv = GET_NEXTIV32(iv);
4106203945Sweongyo		} else {
4107203945Sweongyo
4108203945Sweongyo			if (array_size < sizeof(iv->data.d16))
4109203945Sweongyo				goto fail;
4110203945Sweongyo			array_size -= sizeof(iv->data.d16);
4111203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
4112203945Sweongyo
4113203945Sweongyo			iv = GET_NEXTIV16(iv);
4114203945Sweongyo		}
4115203945Sweongyo	}
4116203945Sweongyo	if (array_size != 0)
4117203945Sweongyo		goto fail;
4118203945Sweongyo	return (0);
4119203945Sweongyofail:
4120203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
4121203945Sweongyo	return (EPROTO);
4122203945Sweongyo#undef GET_NEXTIV16
4123203945Sweongyo#undef GET_NEXTIV32
4124203945Sweongyo}
4125203945Sweongyo
4126298948Sadrianint
4127203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
4128203945Sweongyo{
4129203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
4130203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4131287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4132203945Sweongyo	uint16_t channelcookie, savedcookie;
4133203945Sweongyo	int error;
4134203945Sweongyo
4135203945Sweongyo	if (chan == 0xffff)
4136203945Sweongyo		chan = phy->get_default_chan(mac);
4137203945Sweongyo
4138203945Sweongyo	channelcookie = chan;
4139203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
4140203945Sweongyo		channelcookie |= 0x100;
4141203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
4142203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
4143203945Sweongyo	error = phy->switch_channel(mac, chan);
4144203945Sweongyo	if (error)
4145203945Sweongyo		goto fail;
4146203945Sweongyo
4147203945Sweongyo	mac->mac_phy.chan = chan;
4148203945Sweongyo	DELAY(8000);
4149203945Sweongyo	return (0);
4150203945Sweongyofail:
4151203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
4152203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
4153203945Sweongyo	return (error);
4154203945Sweongyo}
4155203945Sweongyo
4156203945Sweongyostatic uint16_t
4157203945Sweongyobwn_ant2phy(int antenna)
4158203945Sweongyo{
4159203945Sweongyo
4160203945Sweongyo	switch (antenna) {
4161203945Sweongyo	case BWN_ANT0:
4162203945Sweongyo		return (BWN_TX_PHY_ANT0);
4163203945Sweongyo	case BWN_ANT1:
4164203945Sweongyo		return (BWN_TX_PHY_ANT1);
4165203945Sweongyo	case BWN_ANT2:
4166203945Sweongyo		return (BWN_TX_PHY_ANT2);
4167203945Sweongyo	case BWN_ANT3:
4168203945Sweongyo		return (BWN_TX_PHY_ANT3);
4169203945Sweongyo	case BWN_ANTAUTO:
4170203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
4171203945Sweongyo	}
4172203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4173203945Sweongyo	return (0);
4174203945Sweongyo}
4175203945Sweongyo
4176203945Sweongyostatic void
4177203945Sweongyobwn_wme_load(struct bwn_mac *mac)
4178203945Sweongyo{
4179203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4180203945Sweongyo	int i;
4181203945Sweongyo
4182203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
4183203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4184203945Sweongyo
4185203945Sweongyo	bwn_mac_suspend(mac);
4186203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
4187203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
4188203945Sweongyo		    bwn_wme_shm_offsets[i]);
4189203945Sweongyo	bwn_mac_enable(mac);
4190203945Sweongyo}
4191203945Sweongyo
4192203945Sweongyostatic void
4193203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
4194203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
4195203945Sweongyo{
4196203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
4197203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4198203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
4199203945Sweongyo	int slot, tmp;
4200203945Sweongyo	unsigned int i;
4201203945Sweongyo
4202203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
4203203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4204203945Sweongyo
4205203945Sweongyo	memset(&params, 0, sizeof(params));
4206203945Sweongyo
4207203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
4208203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
4209203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
4210203945Sweongyo
4211203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
4212203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4213203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
4214203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4215203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
4216203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
4217203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
4218203945Sweongyo
4219203945Sweongyo	for (i = 0; i < N(params); i++) {
4220203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
4221203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
4222203945Sweongyo			    shm_offset + (i * 2));
4223203945Sweongyo			tmp |= 0x100;
4224203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4225203945Sweongyo			    tmp);
4226203945Sweongyo		} else {
4227203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4228203945Sweongyo			    params[i]);
4229203945Sweongyo		}
4230203945Sweongyo	}
4231203945Sweongyo}
4232203945Sweongyo
4233203945Sweongyostatic void
4234203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
4235203945Sweongyo{
4236203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4237203945Sweongyo	uint32_t tmp;
4238203945Sweongyo	int i;
4239203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
4240203945Sweongyo
4241203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
4242287197Sglebius	memcpy(mac_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
4243203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
4244203945Sweongyo	    IEEE80211_ADDR_LEN);
4245203945Sweongyo
4246203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
4247203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
4248203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
4249203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
4250203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
4251203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
4252203945Sweongyo	}
4253203945Sweongyo}
4254203945Sweongyo
4255203945Sweongyostatic void
4256203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
4257203945Sweongyo    const uint8_t *macaddr)
4258203945Sweongyo{
4259203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
4260203945Sweongyo	uint16_t data;
4261203945Sweongyo
4262203945Sweongyo	if (!mac)
4263203945Sweongyo		macaddr = zero;
4264203945Sweongyo
4265203945Sweongyo	offset |= 0x0020;
4266203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
4267203945Sweongyo
4268203945Sweongyo	data = macaddr[0];
4269203945Sweongyo	data |= macaddr[1] << 8;
4270203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4271203945Sweongyo	data = macaddr[2];
4272203945Sweongyo	data |= macaddr[3] << 8;
4273203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4274203945Sweongyo	data = macaddr[4];
4275203945Sweongyo	data |= macaddr[5] << 8;
4276203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4277203945Sweongyo}
4278203945Sweongyo
4279203945Sweongyostatic void
4280203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4281203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
4282203945Sweongyo{
4283203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
4284203945Sweongyo	uint8_t per_sta_keys_start = 8;
4285203945Sweongyo
4286203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4287203945Sweongyo		per_sta_keys_start = 4;
4288203945Sweongyo
4289203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
4290203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4291203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
4292203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4293203945Sweongyo
4294203945Sweongyo	if (index >= per_sta_keys_start)
4295203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
4296203945Sweongyo	if (key)
4297203945Sweongyo		memcpy(buf, key, key_len);
4298203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
4299203945Sweongyo	if (index >= per_sta_keys_start)
4300203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
4301203945Sweongyo
4302203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
4303203945Sweongyo}
4304203945Sweongyo
4305203945Sweongyostatic void
4306203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
4307203945Sweongyo{
4308204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4309203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
4310203945Sweongyo	uint8_t start = 8;
4311203945Sweongyo
4312203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4313203945Sweongyo		start = 4;
4314203945Sweongyo
4315203945Sweongyo	KASSERT(index >= start,
4316203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4317203945Sweongyo	index -= start;
4318203945Sweongyo
4319203945Sweongyo	if (addr) {
4320203945Sweongyo		addrtmp[0] = addr[0];
4321203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
4322203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
4323203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
4324203945Sweongyo		addrtmp[1] = addr[4];
4325203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
4326203945Sweongyo	}
4327203945Sweongyo
4328204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
4329203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
4330203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
4331203945Sweongyo	} else {
4332203945Sweongyo		if (index >= 8) {
4333203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
4334203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
4335203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
4336203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
4337203945Sweongyo		}
4338203945Sweongyo	}
4339203945Sweongyo}
4340203945Sweongyo
4341203945Sweongyostatic void
4342203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4343203945Sweongyo    const uint8_t *key)
4344203945Sweongyo{
4345203945Sweongyo	unsigned int i;
4346203945Sweongyo	uint32_t offset;
4347203945Sweongyo	uint16_t kidx, value;
4348203945Sweongyo
4349203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
4350203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
4351203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
4352203945Sweongyo
4353203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
4354203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
4355203945Sweongyo		value = key[i];
4356203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
4357203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
4358203945Sweongyo	}
4359203945Sweongyo}
4360203945Sweongyo
4361203945Sweongyostatic void
4362203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
4363203945Sweongyo{
4364203945Sweongyo
4365203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4366203945Sweongyo	if (mac->mac_phy.exit != NULL)
4367203945Sweongyo		mac->mac_phy.exit(mac);
4368203945Sweongyo}
4369203945Sweongyo
4370203945Sweongyostatic void
4371203945Sweongyobwn_dma_free(struct bwn_mac *mac)
4372203945Sweongyo{
4373203945Sweongyo	struct bwn_dma *dma;
4374203945Sweongyo
4375203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
4376203945Sweongyo		return;
4377203945Sweongyo	dma = &mac->mac_method.dma;
4378203945Sweongyo
4379203945Sweongyo	bwn_dma_ringfree(&dma->rx);
4380203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
4381203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
4382203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
4383203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
4384203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
4385203945Sweongyo}
4386203945Sweongyo
4387203945Sweongyostatic void
4388203945Sweongyobwn_core_stop(struct bwn_mac *mac)
4389203945Sweongyo{
4390203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4391203945Sweongyo
4392203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4393203945Sweongyo
4394203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
4395203945Sweongyo		return;
4396203945Sweongyo
4397203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
4398203945Sweongyo	callout_stop(&sc->sc_task_ch);
4399203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
4400203945Sweongyo	sc->sc_watchdog_timer = 0;
4401203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4402203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
4403203945Sweongyo	bwn_mac_suspend(mac);
4404203945Sweongyo
4405203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
4406203945Sweongyo}
4407203945Sweongyo
4408203945Sweongyostatic int
4409203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
4410203945Sweongyo{
4411203945Sweongyo	struct bwn_mac *up_dev = NULL;
4412203945Sweongyo	struct bwn_mac *down_dev;
4413203945Sweongyo	struct bwn_mac *mac;
4414203945Sweongyo	int err, status;
4415203945Sweongyo	uint8_t gmode;
4416203945Sweongyo
4417203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4418203945Sweongyo
4419203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
4420203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
4421203945Sweongyo		    mac->mac_phy.supports_2ghz) {
4422203945Sweongyo			up_dev = mac;
4423203945Sweongyo			gmode = 1;
4424203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
4425203945Sweongyo		    mac->mac_phy.supports_5ghz) {
4426203945Sweongyo			up_dev = mac;
4427203945Sweongyo			gmode = 0;
4428203945Sweongyo		} else {
4429203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4430203945Sweongyo			return (EINVAL);
4431203945Sweongyo		}
4432203945Sweongyo		if (up_dev != NULL)
4433203945Sweongyo			break;
4434203945Sweongyo	}
4435203945Sweongyo	if (up_dev == NULL) {
4436203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
4437203945Sweongyo		return (ENODEV);
4438203945Sweongyo	}
4439203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
4440203945Sweongyo		return (0);
4441203945Sweongyo
4442203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
4443203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4444203945Sweongyo
4445216227Skevlo	down_dev = sc->sc_curmac;
4446203945Sweongyo	status = down_dev->mac_status;
4447203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4448203945Sweongyo		bwn_core_stop(down_dev);
4449203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
4450203945Sweongyo		bwn_core_exit(down_dev);
4451203945Sweongyo
4452203945Sweongyo	if (down_dev != up_dev)
4453203945Sweongyo		bwn_phy_reset(down_dev);
4454203945Sweongyo
4455203945Sweongyo	up_dev->mac_phy.gmode = gmode;
4456203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
4457203945Sweongyo		err = bwn_core_init(up_dev);
4458203945Sweongyo		if (err) {
4459203945Sweongyo			device_printf(sc->sc_dev,
4460203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
4461203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4462203945Sweongyo			goto fail;
4463203945Sweongyo		}
4464203945Sweongyo	}
4465203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4466203945Sweongyo		bwn_core_start(up_dev);
4467203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
4468203945Sweongyo	sc->sc_curmac = up_dev;
4469203945Sweongyo
4470203945Sweongyo	return (0);
4471203945Sweongyofail:
4472203945Sweongyo	sc->sc_curmac = NULL;
4473203945Sweongyo	return (err);
4474203945Sweongyo}
4475203945Sweongyo
4476203945Sweongyostatic void
4477203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
4478203945Sweongyo{
4479203945Sweongyo
4480203945Sweongyo	bwn_mac_suspend(mac);
4481203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4482203945Sweongyo	mac->mac_phy.rf_on = 1;
4483203945Sweongyo	bwn_mac_enable(mac);
4484203945Sweongyo}
4485203945Sweongyo
4486203945Sweongyostatic void
4487203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
4488203945Sweongyo{
4489203945Sweongyo
4490203945Sweongyo	bwn_mac_suspend(mac);
4491203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4492203945Sweongyo	mac->mac_phy.rf_on = 0;
4493203945Sweongyo	bwn_mac_enable(mac);
4494203945Sweongyo}
4495203945Sweongyo
4496203945Sweongyostatic void
4497203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
4498203945Sweongyo{
4499204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4500203945Sweongyo
4501204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4502204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
4503203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
4504203945Sweongyo	DELAY(1000);
4505204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4506204922Sweongyo	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
4507203945Sweongyo	    BWN_TGSLOW_PHYRESET);
4508203945Sweongyo	DELAY(1000);
4509203945Sweongyo}
4510203945Sweongyo
4511203945Sweongyostatic int
4512203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
4513203945Sweongyo{
4514203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
4515203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
4516203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
4517286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
4518203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
4519203945Sweongyo	int error;
4520203945Sweongyo
4521203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
4522203945Sweongyo	    ieee80211_state_name[vap->iv_state],
4523203945Sweongyo	    ieee80211_state_name[nstate]);
4524203945Sweongyo
4525203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
4526203945Sweongyo	if (error != 0)
4527203945Sweongyo		return (error);
4528203945Sweongyo
4529203945Sweongyo	BWN_LOCK(sc);
4530203945Sweongyo
4531203945Sweongyo	bwn_led_newstate(mac, nstate);
4532203945Sweongyo
4533203945Sweongyo	/*
4534203945Sweongyo	 * Clear the BSSID when we stop a STA
4535203945Sweongyo	 */
4536203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
4537203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
4538203945Sweongyo			/*
4539203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
4540203945Sweongyo			 * the same AP, this will reinialize things
4541203945Sweongyo			 * correctly...
4542203945Sweongyo			 */
4543203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
4544203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
4545203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
4546203945Sweongyo				bwn_set_macaddr(mac);
4547203945Sweongyo			}
4548203945Sweongyo		}
4549203945Sweongyo	}
4550203945Sweongyo
4551204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
4552204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
4553203945Sweongyo		/* XXX nothing to do? */
4554203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
4555203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
4556203945Sweongyo		bwn_set_opmode(mac);
4557203945Sweongyo		bwn_set_pretbtt(mac);
4558203945Sweongyo		bwn_spu_setdelay(mac, 0);
4559203945Sweongyo		bwn_set_macaddr(mac);
4560203945Sweongyo	}
4561203945Sweongyo
4562203945Sweongyo	BWN_UNLOCK(sc);
4563203945Sweongyo
4564203945Sweongyo	return (error);
4565203945Sweongyo}
4566203945Sweongyo
4567203945Sweongyostatic void
4568203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
4569203945Sweongyo{
4570203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4571287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4572203945Sweongyo	uint16_t pretbtt;
4573203945Sweongyo
4574203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
4575203945Sweongyo		pretbtt = 2;
4576203945Sweongyo	else
4577203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
4578203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
4579203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
4580203945Sweongyo}
4581203945Sweongyo
4582203945Sweongyostatic int
4583203945Sweongyobwn_intr(void *arg)
4584203945Sweongyo{
4585203945Sweongyo	struct bwn_mac *mac = arg;
4586203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4587203945Sweongyo	uint32_t reason;
4588203945Sweongyo
4589204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4590204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
4591203945Sweongyo		return (FILTER_STRAY);
4592203945Sweongyo
4593203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
4594203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
4595203945Sweongyo		return (FILTER_STRAY);
4596203945Sweongyo	reason &= mac->mac_intr_mask;
4597203945Sweongyo	if (reason == 0)
4598203945Sweongyo		return (FILTER_HANDLED);
4599203945Sweongyo
4600203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
4601203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
4602203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
4603203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
4604203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
4605203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
4606203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
4607203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
4608203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
4609203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
4610203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
4611203945Sweongyo
4612203945Sweongyo	/* Disable interrupts. */
4613203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4614203945Sweongyo
4615203945Sweongyo	mac->mac_reason_intr = reason;
4616203945Sweongyo
4617203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4618203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4619203945Sweongyo
4620296272Sjhb	taskqueue_enqueue(sc->sc_tq, &mac->mac_intrtask);
4621203945Sweongyo	return (FILTER_HANDLED);
4622203945Sweongyo}
4623203945Sweongyo
4624203945Sweongyostatic void
4625203945Sweongyobwn_intrtask(void *arg, int npending)
4626203945Sweongyo{
4627203945Sweongyo	struct bwn_mac *mac = arg;
4628203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4629203945Sweongyo	uint32_t merged = 0;
4630203945Sweongyo	int i, tx = 0, rx = 0;
4631203945Sweongyo
4632203945Sweongyo	BWN_LOCK(sc);
4633204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4634204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
4635203945Sweongyo		BWN_UNLOCK(sc);
4636203945Sweongyo		return;
4637203945Sweongyo	}
4638203945Sweongyo
4639203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
4640203945Sweongyo		merged |= mac->mac_reason[i];
4641203945Sweongyo
4642203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
4643203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
4644203945Sweongyo
4645203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
4646203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
4647203945Sweongyo		mac->mac_phy.txerrors--;
4648203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
4649203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
4650203945Sweongyo			bwn_restart(mac, "PHY TX errors");
4651203945Sweongyo		}
4652203945Sweongyo	}
4653203945Sweongyo
4654203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
4655203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
4656203945Sweongyo			device_printf(sc->sc_dev,
4657203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
4658203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4659203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4660203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4661203945Sweongyo			bwn_restart(mac, "DMA error");
4662203945Sweongyo			BWN_UNLOCK(sc);
4663203945Sweongyo			return;
4664203945Sweongyo		}
4665203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
4666203945Sweongyo			device_printf(sc->sc_dev,
4667203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
4668203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4669203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4670203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4671203945Sweongyo		}
4672203945Sweongyo	}
4673203945Sweongyo
4674203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
4675203945Sweongyo		bwn_intr_ucode_debug(mac);
4676203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
4677203945Sweongyo		bwn_intr_tbtt_indication(mac);
4678203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
4679203945Sweongyo		bwn_intr_atim_end(mac);
4680203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
4681203945Sweongyo		bwn_intr_beacon(mac);
4682203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
4683203945Sweongyo		bwn_intr_pmq(mac);
4684203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
4685203945Sweongyo		bwn_intr_noise(mac);
4686203945Sweongyo
4687203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
4688203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
4689203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
4690203945Sweongyo			rx = 1;
4691203945Sweongyo		}
4692203945Sweongyo	} else
4693203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
4694203945Sweongyo
4695203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4696203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4697203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4698203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4699203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4700203945Sweongyo
4701203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
4702203945Sweongyo		bwn_intr_txeof(mac);
4703203945Sweongyo		tx = 1;
4704203945Sweongyo	}
4705203945Sweongyo
4706203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
4707203945Sweongyo
4708203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
4709203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
4710203945Sweongyo
4711203945Sweongyo		if (tx && rx) {
4712203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
4713203945Sweongyo				evt = BWN_LED_EVENT_RX;
4714203945Sweongyo			else
4715203945Sweongyo				evt = BWN_LED_EVENT_TX;
4716203945Sweongyo		} else if (tx) {
4717203945Sweongyo			evt = BWN_LED_EVENT_TX;
4718203945Sweongyo		} else if (rx) {
4719203945Sweongyo			evt = BWN_LED_EVENT_RX;
4720203945Sweongyo		} else if (rx == 0) {
4721203945Sweongyo			evt = BWN_LED_EVENT_POLL;
4722203945Sweongyo		}
4723203945Sweongyo
4724203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
4725203945Sweongyo			bwn_led_event(mac, evt);
4726203945Sweongyo       }
4727203945Sweongyo
4728287197Sglebius	if (mbufq_first(&sc->sc_snd) != NULL)
4729287197Sglebius		bwn_start(sc);
4730203945Sweongyo
4731203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4732203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4733203945Sweongyo
4734203945Sweongyo	BWN_UNLOCK(sc);
4735203945Sweongyo}
4736203945Sweongyo
4737203945Sweongyostatic void
4738203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
4739203945Sweongyo{
4740203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4741287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4742203945Sweongyo
4743203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
4744203945Sweongyo		return;
4745203945Sweongyo
4746203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
4747203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
4748203945Sweongyo}
4749203945Sweongyo
4750203945Sweongyostatic void
4751203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
4752203945Sweongyo{
4753203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4754203945Sweongyo	uint16_t reason;
4755203945Sweongyo
4756203945Sweongyo	if (mac->mac_fw.opensource == 0)
4757203945Sweongyo		return;
4758203945Sweongyo
4759203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
4760203945Sweongyo	switch (reason) {
4761203945Sweongyo	case BWN_DEBUGINTR_PANIC:
4762203945Sweongyo		bwn_handle_fwpanic(mac);
4763203945Sweongyo		break;
4764203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
4765203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
4766203945Sweongyo		break;
4767203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
4768203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
4769203945Sweongyo		break;
4770203945Sweongyo	case BWN_DEBUGINTR_MARKER:
4771203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
4772203945Sweongyo		break;
4773203945Sweongyo	default:
4774203945Sweongyo		device_printf(sc->sc_dev,
4775203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
4776203945Sweongyo	}
4777203945Sweongyo
4778203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
4779203945Sweongyo	    BWN_DEBUGINTR_ACK);
4780203945Sweongyo}
4781203945Sweongyo
4782203945Sweongyostatic void
4783203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
4784203945Sweongyo{
4785203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4786287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4787203945Sweongyo
4788203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
4789203945Sweongyo		bwn_psctl(mac, 0);
4790203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
4791203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
4792203945Sweongyo}
4793203945Sweongyo
4794203945Sweongyostatic void
4795203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
4796203945Sweongyo{
4797203945Sweongyo
4798203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
4799203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
4800203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
4801203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
4802203945Sweongyo	}
4803203945Sweongyo}
4804203945Sweongyo
4805203945Sweongyostatic void
4806203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
4807203945Sweongyo{
4808203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4809287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4810203945Sweongyo	uint32_t cmd, beacon0, beacon1;
4811203945Sweongyo
4812203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4813203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4814203945Sweongyo		return;
4815203945Sweongyo
4816203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
4817203945Sweongyo
4818203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
4819203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
4820203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
4821203945Sweongyo
4822203945Sweongyo	if (beacon0 && beacon1) {
4823203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
4824203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
4825203945Sweongyo		return;
4826203945Sweongyo	}
4827203945Sweongyo
4828203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
4829203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
4830203945Sweongyo		bwn_load_beacon0(mac);
4831203945Sweongyo		bwn_load_beacon1(mac);
4832203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
4833203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
4834203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4835203945Sweongyo	} else {
4836203945Sweongyo		if (!beacon0) {
4837203945Sweongyo			bwn_load_beacon0(mac);
4838203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
4839203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
4840203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4841203945Sweongyo		} else if (!beacon1) {
4842203945Sweongyo			bwn_load_beacon1(mac);
4843203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
4844203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
4845203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
4846203945Sweongyo		}
4847203945Sweongyo	}
4848203945Sweongyo}
4849203945Sweongyo
4850203945Sweongyostatic void
4851203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
4852203945Sweongyo{
4853203945Sweongyo	uint32_t tmp;
4854203945Sweongyo
4855203945Sweongyo	while (1) {
4856203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
4857203945Sweongyo		if (!(tmp & 0x00000008))
4858203945Sweongyo			break;
4859203945Sweongyo	}
4860203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
4861203945Sweongyo}
4862203945Sweongyo
4863203945Sweongyostatic void
4864203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
4865203945Sweongyo{
4866203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
4867203945Sweongyo	uint16_t tmp;
4868203945Sweongyo	uint8_t noise[4];
4869203945Sweongyo	uint8_t i, j;
4870203945Sweongyo	int32_t average;
4871203945Sweongyo
4872203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
4873203945Sweongyo		return;
4874203945Sweongyo
4875203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
4876203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
4877203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
4878203945Sweongyo	    noise[3] == 0x7f)
4879203945Sweongyo		goto new;
4880203945Sweongyo
4881203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
4882203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4883203945Sweongyo	i = mac->mac_noise.noi_nsamples;
4884203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
4885203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
4886203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
4887203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
4888203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
4889203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
4890203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
4891203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
4892203945Sweongyo	mac->mac_noise.noi_nsamples++;
4893203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
4894203945Sweongyo		average = 0;
4895203945Sweongyo		for (i = 0; i < 8; i++) {
4896203945Sweongyo			for (j = 0; j < 4; j++)
4897203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
4898203945Sweongyo		}
4899203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
4900203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
4901203945Sweongyo		if (tmp >= 8)
4902203945Sweongyo			average += 2;
4903203945Sweongyo		else
4904203945Sweongyo			average -= 25;
4905203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
4906203945Sweongyo
4907203945Sweongyo		mac->mac_stats.link_noise = average;
4908203945Sweongyo		mac->mac_noise.noi_running = 0;
4909203945Sweongyo		return;
4910203945Sweongyo	}
4911203945Sweongyonew:
4912203945Sweongyo	bwn_noise_gensample(mac);
4913203945Sweongyo}
4914203945Sweongyo
4915203945Sweongyostatic int
4916203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
4917203945Sweongyo{
4918203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
4919203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4920203945Sweongyo	unsigned int i;
4921203945Sweongyo
4922203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4923203945Sweongyo
4924203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
4925203945Sweongyo		return (0);
4926203945Sweongyo
4927203945Sweongyo	for (i = 0; i < 5000; i++) {
4928203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
4929203945Sweongyo			break;
4930203945Sweongyo	}
4931203945Sweongyo	if (i >= 5000)
4932203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
4933203945Sweongyo	return ((i > 0) ? 1 : 0);
4934203945Sweongyo}
4935203945Sweongyo
4936203945Sweongyostatic void
4937203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
4938203945Sweongyo{
4939203945Sweongyo	int slot, curslot;
4940203945Sweongyo
4941203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
4942203945Sweongyo	curslot = dr->get_curslot(dr);
4943203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
4944203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4945203945Sweongyo
4946203945Sweongyo	slot = dr->dr_curslot;
4947203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
4948203945Sweongyo		bwn_dma_rxeof(dr, &slot);
4949203945Sweongyo
4950203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
4951203945Sweongyo	    BUS_DMASYNC_PREWRITE);
4952203945Sweongyo
4953203945Sweongyo	dr->set_curslot(dr, slot);
4954203945Sweongyo	dr->dr_curslot = slot;
4955203945Sweongyo}
4956203945Sweongyo
4957203945Sweongyostatic void
4958203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
4959203945Sweongyo{
4960203945Sweongyo	struct bwn_txstatus stat;
4961203945Sweongyo	uint32_t stat0, stat1;
4962203945Sweongyo	uint16_t tmp;
4963203945Sweongyo
4964203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
4965203945Sweongyo
4966203945Sweongyo	while (1) {
4967203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
4968203945Sweongyo		if (!(stat0 & 0x00000001))
4969203945Sweongyo			break;
4970203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
4971203945Sweongyo
4972299036Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT,
4973299036Sadrian		    "%s: stat0=0x%08x, stat1=0x%08x\n",
4974299036Sadrian		    __func__,
4975299036Sadrian		    stat0,
4976299036Sadrian		    stat1);
4977299036Sadrian
4978203945Sweongyo		stat.cookie = (stat0 >> 16);
4979203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
4980203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
4981203945Sweongyo		tmp = (stat0 & 0x0000ffff);
4982203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
4983203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
4984203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
4985203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
4986203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
4987203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
4988203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
4989203945Sweongyo
4990203945Sweongyo		bwn_handle_txeof(mac, &stat);
4991203945Sweongyo	}
4992203945Sweongyo}
4993203945Sweongyo
4994203945Sweongyostatic void
4995203945Sweongyobwn_hwreset(void *arg, int npending)
4996203945Sweongyo{
4997203945Sweongyo	struct bwn_mac *mac = arg;
4998203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4999203945Sweongyo	int error = 0;
5000203945Sweongyo	int prev_status;
5001203945Sweongyo
5002203945Sweongyo	BWN_LOCK(sc);
5003203945Sweongyo
5004203945Sweongyo	prev_status = mac->mac_status;
5005203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5006203945Sweongyo		bwn_core_stop(mac);
5007203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
5008203945Sweongyo		bwn_core_exit(mac);
5009203945Sweongyo
5010203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
5011203945Sweongyo		error = bwn_core_init(mac);
5012203945Sweongyo		if (error)
5013203945Sweongyo			goto out;
5014203945Sweongyo	}
5015203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5016203945Sweongyo		bwn_core_start(mac);
5017203945Sweongyoout:
5018203945Sweongyo	if (error) {
5019203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
5020203945Sweongyo		sc->sc_curmac = NULL;
5021203945Sweongyo	}
5022203945Sweongyo	BWN_UNLOCK(sc);
5023203945Sweongyo}
5024203945Sweongyo
5025203945Sweongyostatic void
5026203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
5027203945Sweongyo{
5028203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5029203945Sweongyo	uint16_t reason;
5030203945Sweongyo
5031203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
5032203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
5033203945Sweongyo
5034203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
5035203945Sweongyo		bwn_restart(mac, "ucode panic");
5036203945Sweongyo}
5037203945Sweongyo
5038203945Sweongyostatic void
5039203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
5040203945Sweongyo{
5041203945Sweongyo
5042203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5043203945Sweongyo}
5044203945Sweongyo
5045203945Sweongyostatic void
5046203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
5047203945Sweongyo{
5048203945Sweongyo
5049203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5050203945Sweongyo}
5051203945Sweongyo
5052203945Sweongyostatic uint32_t
5053203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
5054203945Sweongyo{
5055203945Sweongyo	uint32_t val = 0;
5056203945Sweongyo
5057203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
5058203945Sweongyo	val <<= 16;
5059203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
5060203945Sweongyo
5061203945Sweongyo	return (val);
5062203945Sweongyo}
5063203945Sweongyo
5064203945Sweongyostatic void
5065203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
5066203945Sweongyo{
5067203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
5068203945Sweongyo
5069203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
5070203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
5071203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
5072203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
5073203945Sweongyo}
5074203945Sweongyo
5075203945Sweongyostatic int
5076203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
5077203945Sweongyo{
5078204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5079203945Sweongyo
5080203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
5081203945Sweongyo}
5082203945Sweongyo
5083203945Sweongyostatic int
5084203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
5085203945Sweongyo{
5086204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5087203945Sweongyo
5088203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
5089203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5090203945Sweongyo	if (slot == dr->dr_numslots - 1)
5091203945Sweongyo		return (0);
5092203945Sweongyo	return (slot + 1);
5093203945Sweongyo}
5094203945Sweongyo
5095203945Sweongyostatic void
5096203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
5097203945Sweongyo{
5098203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5099203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5100203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5101203945Sweongyo	struct bwn_dmadesc_generic *desc;
5102203945Sweongyo	struct bwn_dmadesc_meta *meta;
5103203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
5104203945Sweongyo	struct mbuf *m;
5105203945Sweongyo	uint32_t macstat;
5106203945Sweongyo	int32_t tmp;
5107203945Sweongyo	int cnt = 0;
5108203945Sweongyo	uint16_t len;
5109203945Sweongyo
5110203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
5111203945Sweongyo
5112203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
5113203945Sweongyo	m = meta->mt_m;
5114203945Sweongyo
5115203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
5116287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5117203945Sweongyo		return;
5118203945Sweongyo	}
5119203945Sweongyo
5120203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
5121203945Sweongyo	len = le16toh(rxhdr->frame_len);
5122203945Sweongyo	if (len <= 0) {
5123287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5124203945Sweongyo		return;
5125203945Sweongyo	}
5126203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
5127203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
5128203945Sweongyo		bwn_dma_set_redzone(dr, m);
5129203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5130203945Sweongyo		    BUS_DMASYNC_PREWRITE);
5131203945Sweongyo		return;
5132203945Sweongyo	}
5133203945Sweongyo	if (len > dr->dr_rx_bufsize) {
5134203945Sweongyo		tmp = len;
5135203945Sweongyo		while (1) {
5136203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
5137203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
5138203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5139203945Sweongyo			    BUS_DMASYNC_PREWRITE);
5140203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
5141203945Sweongyo			cnt++;
5142203945Sweongyo			tmp -= dr->dr_rx_bufsize;
5143203945Sweongyo			if (tmp <= 0)
5144203945Sweongyo				break;
5145203945Sweongyo		}
5146203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
5147203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
5148203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
5149203945Sweongyo		return;
5150203945Sweongyo	}
5151203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
5152203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5153203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5154203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
5155203945Sweongyo			return;
5156203945Sweongyo		}
5157203945Sweongyo	}
5158203945Sweongyo
5159203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
5160203945Sweongyo	m_adj(m, dr->dr_frameoffset);
5161203945Sweongyo
5162203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
5163203945Sweongyo}
5164203945Sweongyo
5165203945Sweongyostatic void
5166203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
5167203945Sweongyo{
5168203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5169204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
5170203945Sweongyo
5171203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
5172203945Sweongyo
5173203945Sweongyo	if (status->im)
5174203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
5175203945Sweongyo	if (status->ampdu)
5176203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
5177203945Sweongyo	if (status->rtscnt) {
5178203945Sweongyo		if (status->rtscnt == 0xf)
5179204257Sweongyo			stats->rtsfail++;
5180203945Sweongyo		else
5181204257Sweongyo			stats->rts++;
5182203945Sweongyo	}
5183203945Sweongyo
5184203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
5185203945Sweongyo		bwn_dma_handle_txeof(mac, status);
5186203945Sweongyo	} else {
5187203945Sweongyo		bwn_pio_handle_txeof(mac, status);
5188203945Sweongyo	}
5189203945Sweongyo
5190203945Sweongyo	bwn_phy_txpower_check(mac, 0);
5191203945Sweongyo}
5192203945Sweongyo
5193203945Sweongyostatic uint8_t
5194203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
5195203945Sweongyo{
5196203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
5197203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5198203945Sweongyo	struct bwn_rxhdr4 rxhdr;
5199203945Sweongyo	struct mbuf *m;
5200203945Sweongyo	uint32_t ctl32, macstat, v32;
5201203945Sweongyo	unsigned int i, padding;
5202209888Sweongyo	uint16_t ctl16, len, totlen, v16;
5203203945Sweongyo	unsigned char *mp;
5204203945Sweongyo	char *data;
5205203945Sweongyo
5206203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
5207203945Sweongyo
5208203945Sweongyo	if (prq->prq_rev >= 8) {
5209203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5210203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
5211203945Sweongyo			return (0);
5212203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5213203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
5214203945Sweongyo		for (i = 0; i < 10; i++) {
5215203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5216203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
5217203945Sweongyo				goto ready;
5218203945Sweongyo			DELAY(10);
5219203945Sweongyo		}
5220203945Sweongyo	} else {
5221203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5222203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
5223203945Sweongyo			return (0);
5224203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
5225203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
5226203945Sweongyo		for (i = 0; i < 10; i++) {
5227203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5228203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
5229203945Sweongyo				goto ready;
5230203945Sweongyo			DELAY(10);
5231203945Sweongyo		}
5232203945Sweongyo	}
5233203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
5234203945Sweongyo	return (1);
5235203945Sweongyoready:
5236203945Sweongyo	if (prq->prq_rev >= 8)
5237204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5238203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5239203945Sweongyo	else
5240204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5241203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5242203945Sweongyo	len = le16toh(rxhdr.frame_len);
5243203945Sweongyo	if (len > 0x700) {
5244203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
5245203945Sweongyo		goto error;
5246203945Sweongyo	}
5247203945Sweongyo	if (len == 0) {
5248203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
5249203945Sweongyo		goto error;
5250203945Sweongyo	}
5251203945Sweongyo
5252203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
5253203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5254203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5255203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
5256203945Sweongyo			goto error;
5257203945Sweongyo		}
5258203945Sweongyo	}
5259203945Sweongyo
5260203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5261209888Sweongyo	totlen = len + padding;
5262209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
5263243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5264203945Sweongyo	if (m == NULL) {
5265203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
5266203945Sweongyo		goto error;
5267203945Sweongyo	}
5268203945Sweongyo	mp = mtod(m, unsigned char *);
5269203945Sweongyo	if (prq->prq_rev >= 8) {
5270209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
5271203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5272209888Sweongyo		if (totlen & 3) {
5273203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
5274209888Sweongyo			data = &(mp[totlen - 1]);
5275209888Sweongyo			switch (totlen & 3) {
5276203945Sweongyo			case 3:
5277203945Sweongyo				*data = (v32 >> 16);
5278203945Sweongyo				data--;
5279203945Sweongyo			case 2:
5280203945Sweongyo				*data = (v32 >> 8);
5281203945Sweongyo				data--;
5282203945Sweongyo			case 1:
5283203945Sweongyo				*data = v32;
5284203945Sweongyo			}
5285203945Sweongyo		}
5286203945Sweongyo	} else {
5287209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
5288203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5289209888Sweongyo		if (totlen & 1) {
5290203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
5291209888Sweongyo			mp[totlen - 1] = v16;
5292203945Sweongyo		}
5293203945Sweongyo	}
5294203945Sweongyo
5295209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
5296203945Sweongyo
5297203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
5298203945Sweongyo
5299203945Sweongyo	return (1);
5300203945Sweongyoerror:
5301203945Sweongyo	if (prq->prq_rev >= 8)
5302203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5303203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
5304203945Sweongyo	else
5305203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
5306203945Sweongyo	return (1);
5307203945Sweongyo}
5308203945Sweongyo
5309203945Sweongyostatic int
5310203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
5311203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
5312203945Sweongyo{
5313203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5314203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5315203945Sweongyo	struct bwn_rxhdr4 *hdr;
5316203945Sweongyo	bus_dmamap_t map;
5317203945Sweongyo	bus_addr_t paddr;
5318203945Sweongyo	struct mbuf *m;
5319203945Sweongyo	int error;
5320203945Sweongyo
5321243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5322203945Sweongyo	if (m == NULL) {
5323203945Sweongyo		error = ENOBUFS;
5324203945Sweongyo
5325203945Sweongyo		/*
5326203945Sweongyo		 * If the NIC is up and running, we need to:
5327203945Sweongyo		 * - Clear RX buffer's header.
5328203945Sweongyo		 * - Restore RX descriptor settings.
5329203945Sweongyo		 */
5330203945Sweongyo		if (init)
5331203945Sweongyo			return (error);
5332203945Sweongyo		else
5333203945Sweongyo			goto back;
5334203945Sweongyo	}
5335203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
5336203945Sweongyo
5337203945Sweongyo	bwn_dma_set_redzone(dr, m);
5338203945Sweongyo
5339203945Sweongyo	/*
5340203945Sweongyo	 * Try to load RX buf into temporary DMA map
5341203945Sweongyo	 */
5342203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
5343203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
5344203945Sweongyo	if (error) {
5345203945Sweongyo		m_freem(m);
5346203945Sweongyo
5347203945Sweongyo		/*
5348203945Sweongyo		 * See the comment above
5349203945Sweongyo		 */
5350203945Sweongyo		if (init)
5351203945Sweongyo			return (error);
5352203945Sweongyo		else
5353203945Sweongyo			goto back;
5354203945Sweongyo	}
5355203945Sweongyo
5356203945Sweongyo	if (!init)
5357203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
5358203945Sweongyo	meta->mt_m = m;
5359203945Sweongyo	meta->mt_paddr = paddr;
5360203945Sweongyo
5361203945Sweongyo	/*
5362203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
5363203945Sweongyo	 */
5364203945Sweongyo	map = meta->mt_dmap;
5365203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
5366203945Sweongyo	dr->dr_spare_dmap = map;
5367203945Sweongyo
5368203945Sweongyoback:
5369203945Sweongyo	/*
5370203945Sweongyo	 * Clear RX buf header
5371203945Sweongyo	 */
5372203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
5373203945Sweongyo	bzero(hdr, sizeof(*hdr));
5374203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5375203945Sweongyo	    BUS_DMASYNC_PREWRITE);
5376203945Sweongyo
5377203945Sweongyo	/*
5378203945Sweongyo	 * Setup RX buf descriptor
5379203945Sweongyo	 */
5380250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
5381203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
5382203945Sweongyo	return (error);
5383203945Sweongyo}
5384203945Sweongyo
5385203945Sweongyostatic void
5386203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
5387203945Sweongyo		 bus_size_t mapsz __unused, int error)
5388203945Sweongyo{
5389203945Sweongyo
5390203945Sweongyo	if (!error) {
5391203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
5392203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
5393203945Sweongyo	}
5394203945Sweongyo}
5395203945Sweongyo
5396203945Sweongyostatic int
5397203945Sweongyobwn_hwrate2ieeerate(int rate)
5398203945Sweongyo{
5399203945Sweongyo
5400203945Sweongyo	switch (rate) {
5401203945Sweongyo	case BWN_CCK_RATE_1MB:
5402203945Sweongyo		return (2);
5403203945Sweongyo	case BWN_CCK_RATE_2MB:
5404203945Sweongyo		return (4);
5405203945Sweongyo	case BWN_CCK_RATE_5MB:
5406203945Sweongyo		return (11);
5407203945Sweongyo	case BWN_CCK_RATE_11MB:
5408203945Sweongyo		return (22);
5409203945Sweongyo	case BWN_OFDM_RATE_6MB:
5410203945Sweongyo		return (12);
5411203945Sweongyo	case BWN_OFDM_RATE_9MB:
5412203945Sweongyo		return (18);
5413203945Sweongyo	case BWN_OFDM_RATE_12MB:
5414203945Sweongyo		return (24);
5415203945Sweongyo	case BWN_OFDM_RATE_18MB:
5416203945Sweongyo		return (36);
5417203945Sweongyo	case BWN_OFDM_RATE_24MB:
5418203945Sweongyo		return (48);
5419203945Sweongyo	case BWN_OFDM_RATE_36MB:
5420203945Sweongyo		return (72);
5421203945Sweongyo	case BWN_OFDM_RATE_48MB:
5422203945Sweongyo		return (96);
5423203945Sweongyo	case BWN_OFDM_RATE_54MB:
5424203945Sweongyo		return (108);
5425203945Sweongyo	default:
5426203945Sweongyo		printf("Ooops\n");
5427203945Sweongyo		return (0);
5428203945Sweongyo	}
5429203945Sweongyo}
5430203945Sweongyo
5431299110Sadrian/*
5432299110Sadrian * Post process the RX provided RSSI.
5433299110Sadrian *
5434299110Sadrian * Valid for A, B, G, LP PHYs.
5435299110Sadrian */
5436299110Sadrianstatic int8_t
5437299131Sadrianbwn_rx_rssi_calc(struct bwn_mac *mac, uint8_t in_rssi,
5438299110Sadrian    int ofdm, int adjust_2053, int adjust_2050)
5439299110Sadrian{
5440299110Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5441299110Sadrian	struct bwn_phy_g *gphy = &phy->phy_g;
5442299110Sadrian	int tmp;
5443299110Sadrian
5444299110Sadrian	switch (phy->rf_ver) {
5445299110Sadrian	case 0x2050:
5446299110Sadrian		if (ofdm) {
5447299110Sadrian			tmp = in_rssi;
5448299110Sadrian			if (tmp > 127)
5449299110Sadrian				tmp -= 256;
5450299110Sadrian			tmp = tmp * 73 / 64;
5451299110Sadrian			if (adjust_2050)
5452299110Sadrian				tmp += 25;
5453299110Sadrian			else
5454299110Sadrian				tmp -= 3;
5455299110Sadrian		} else {
5456299110Sadrian			if (siba_sprom_get_bf_lo(mac->mac_sc->sc_dev)
5457299110Sadrian			    & BWN_BFL_RSSI) {
5458299110Sadrian				if (in_rssi > 63)
5459299110Sadrian					in_rssi = 63;
5460299110Sadrian				tmp = gphy->pg_nrssi_lt[in_rssi];
5461299110Sadrian				tmp = (31 - tmp) * -131 / 128 - 57;
5462299110Sadrian			} else {
5463299110Sadrian				tmp = in_rssi;
5464299110Sadrian				tmp = (31 - tmp) * -149 / 128 - 68;
5465299110Sadrian			}
5466299110Sadrian			if (phy->type == BWN_PHYTYPE_G && adjust_2050)
5467299110Sadrian				tmp += 25;
5468299110Sadrian		}
5469299110Sadrian		break;
5470299110Sadrian	case 0x2060:
5471299110Sadrian		if (in_rssi > 127)
5472299110Sadrian			tmp = in_rssi - 256;
5473299110Sadrian		else
5474299110Sadrian			tmp = in_rssi;
5475299110Sadrian		break;
5476299110Sadrian	default:
5477299110Sadrian		tmp = in_rssi;
5478299110Sadrian		tmp = (tmp - 11) * 103 / 64;
5479299110Sadrian		if (adjust_2053)
5480299110Sadrian			tmp -= 109;
5481299110Sadrian		else
5482299110Sadrian			tmp -= 83;
5483299110Sadrian	}
5484299110Sadrian
5485299110Sadrian	return (tmp);
5486299110Sadrian}
5487299110Sadrian
5488203945Sweongyostatic void
5489203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
5490203945Sweongyo{
5491203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
5492203945Sweongyo	struct bwn_plcp6 *plcp;
5493203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5494203945Sweongyo	struct ieee80211_frame_min *wh;
5495203945Sweongyo	struct ieee80211_node *ni;
5496287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5497203945Sweongyo	uint32_t macstat;
5498204242Simp	int padding, rate, rssi = 0, noise = 0, type;
5499203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
5500203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
5501204242Simp	static int rx_mac_dec_rpt = 0;
5502203945Sweongyo
5503203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5504203945Sweongyo
5505203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
5506203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
5507299110Sadrian
5508299110Sadrian	/* XXX Note: mactime, macstat, chanstat need fixing for fw 598 */
5509203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
5510203945Sweongyo	chanstat = le16toh(rxhdr->channel);
5511299110Sadrian
5512203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
5513203945Sweongyo
5514203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
5515203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
5516203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
5517203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
5518203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
5519203945Sweongyo		goto drop;
5520203945Sweongyo
5521203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5522203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
5523204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5524204081Sweongyo		    m->m_pkthdr.len);
5525203945Sweongyo		goto drop;
5526203945Sweongyo	}
5527203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
5528203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
5529203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
5530204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5531204081Sweongyo		    m->m_pkthdr.len);
5532203945Sweongyo		goto drop;
5533203945Sweongyo	}
5534203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
5535203945Sweongyo
5536204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
5537204081Sweongyo		device_printf(sc->sc_dev,
5538204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
5539204081Sweongyo		    BWN_ISOLDFMT(mac),
5540204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
5541203945Sweongyo
5542203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
5543203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
5544203945Sweongyo		    phytype == BWN_PHYTYPE_A);
5545203945Sweongyo	else
5546203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
5547203945Sweongyo	if (rate == -1) {
5548203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
5549203945Sweongyo			goto drop;
5550203945Sweongyo	}
5551203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
5552203945Sweongyo
5553299110Sadrian	/* rssi/noise */
5554299110Sadrian	switch (phytype) {
5555299110Sadrian	case BWN_PHYTYPE_A:
5556299110Sadrian	case BWN_PHYTYPE_B:
5557299110Sadrian	case BWN_PHYTYPE_G:
5558299110Sadrian	case BWN_PHYTYPE_LP:
5559299110Sadrian		rssi = bwn_rx_rssi_calc(mac, rxhdr->phy.abg.rssi,
5560299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_OFDM),
5561299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_GAINCTL),
5562299110Sadrian		    !! (phystat3 & BWN_RX_PHYST3_TRSTATE));
5563299110Sadrian		break;
5564299110Sadrian	default:
5565299110Sadrian		/* XXX TODO: implement rssi for other PHYs */
5566299110Sadrian		break;
5567299110Sadrian	}
5568299110Sadrian
5569299110Sadrian	noise = mac->mac_stats.link_noise;
5570299110Sadrian
5571203945Sweongyo	/* RX radio tap */
5572203945Sweongyo	if (ieee80211_radiotap_active(ic))
5573203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
5574203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
5575203945Sweongyo
5576203945Sweongyo	BWN_UNLOCK(sc);
5577203945Sweongyo
5578203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
5579203945Sweongyo	if (ni != NULL) {
5580203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
5581203945Sweongyo		ieee80211_free_node(ni);
5582203945Sweongyo	} else
5583203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
5584203945Sweongyo
5585203945Sweongyo	BWN_LOCK(sc);
5586203945Sweongyo	return;
5587203945Sweongyodrop:
5588203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
5589203945Sweongyo}
5590203945Sweongyo
5591203945Sweongyostatic void
5592203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
5593203945Sweongyo    const struct bwn_txstatus *status)
5594203945Sweongyo{
5595203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5596203945Sweongyo	struct bwn_dma_ring *dr;
5597203945Sweongyo	struct bwn_dmadesc_generic *desc;
5598203945Sweongyo	struct bwn_dmadesc_meta *meta;
5599203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5600203945Sweongyo	int slot;
5601299032Sadrian	int retrycnt = 0;
5602203945Sweongyo
5603203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5604203945Sweongyo
5605203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
5606203945Sweongyo	if (dr == NULL) {
5607203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
5608203945Sweongyo		return;
5609203945Sweongyo	}
5610203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
5611203945Sweongyo
5612203945Sweongyo	while (1) {
5613203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
5614203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5615203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
5616203945Sweongyo
5617203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
5618203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
5619203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
5620203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
5621203945Sweongyo
5622203945Sweongyo		if (meta->mt_islast) {
5623203945Sweongyo			KASSERT(meta->mt_m != NULL,
5624203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5625203945Sweongyo
5626299036Sadrian			/* Just count full frame retries for now */
5627299036Sadrian			retrycnt = status->framecnt - 1;
5628299032Sadrian			ieee80211_ratectl_tx_complete(meta->mt_ni->ni_vap, meta->mt_ni,
5629299032Sadrian			    status->ack ?
5630299032Sadrian			      IEEE80211_RATECTL_TX_SUCCESS :
5631299032Sadrian			      IEEE80211_RATECTL_TX_FAILURE,
5632299032Sadrian			    &retrycnt, 0);
5633287197Sglebius			ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
5634287197Sglebius			meta->mt_ni = NULL;
5635203945Sweongyo			meta->mt_m = NULL;
5636287197Sglebius		} else
5637203945Sweongyo			KASSERT(meta->mt_m == NULL,
5638203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5639203945Sweongyo
5640203945Sweongyo		dr->dr_usedslot--;
5641287197Sglebius		if (meta->mt_islast)
5642203945Sweongyo			break;
5643203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
5644203945Sweongyo	}
5645203945Sweongyo	sc->sc_watchdog_timer = 0;
5646203945Sweongyo	if (dr->dr_stop) {
5647203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
5648203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5649203945Sweongyo		dr->dr_stop = 0;
5650203945Sweongyo	}
5651203945Sweongyo}
5652203945Sweongyo
5653203945Sweongyostatic void
5654203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
5655203945Sweongyo    const struct bwn_txstatus *status)
5656203945Sweongyo{
5657203945Sweongyo	struct bwn_pio_txqueue *tq;
5658203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
5659203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5660299032Sadrian	int retrycnt = 0;
5661203945Sweongyo
5662203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5663203945Sweongyo
5664203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
5665203945Sweongyo	if (tq == NULL)
5666203945Sweongyo		return;
5667203945Sweongyo
5668203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
5669203945Sweongyo	tq->tq_free++;
5670203945Sweongyo
5671203945Sweongyo	if (tp->tp_ni != NULL) {
5672203945Sweongyo		/*
5673203945Sweongyo		 * Do any tx complete callback.  Note this must
5674203945Sweongyo		 * be done before releasing the node reference.
5675203945Sweongyo		 */
5676299032Sadrian
5677299036Sadrian		/* Just count full frame retries for now */
5678299036Sadrian		retrycnt = status->framecnt - 1;
5679299032Sadrian		ieee80211_ratectl_tx_complete(tp->tp_ni->ni_vap, tp->tp_ni,
5680299032Sadrian		    status->ack ?
5681299032Sadrian		      IEEE80211_RATECTL_TX_SUCCESS :
5682299032Sadrian		      IEEE80211_RATECTL_TX_FAILURE,
5683299032Sadrian		    &retrycnt, 0);
5684299032Sadrian
5685203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
5686203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
5687203945Sweongyo		ieee80211_free_node(tp->tp_ni);
5688203945Sweongyo		tp->tp_ni = NULL;
5689203945Sweongyo	}
5690203945Sweongyo	m_freem(tp->tp_m);
5691203945Sweongyo	tp->tp_m = NULL;
5692203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
5693203945Sweongyo
5694203945Sweongyo	sc->sc_watchdog_timer = 0;
5695203945Sweongyo}
5696203945Sweongyo
5697203945Sweongyostatic void
5698203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
5699203945Sweongyo{
5700203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5701203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5702287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5703203945Sweongyo	unsigned long now;
5704203945Sweongyo	int result;
5705203945Sweongyo
5706203945Sweongyo	BWN_GETTIME(now);
5707203945Sweongyo
5708297409Sadrian	if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime))
5709203945Sweongyo		return;
5710203945Sweongyo	phy->nexttime = now + 2 * 1000;
5711203945Sweongyo
5712204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
5713204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
5714203945Sweongyo		return;
5715203945Sweongyo
5716203945Sweongyo	if (phy->recalc_txpwr != NULL) {
5717203945Sweongyo		result = phy->recalc_txpwr(mac,
5718203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
5719203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
5720203945Sweongyo			return;
5721203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
5722203945Sweongyo		    ("%s: fail", __func__));
5723203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
5724203945Sweongyo
5725203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
5726203945Sweongyo	}
5727203945Sweongyo}
5728203945Sweongyo
5729203945Sweongyostatic uint16_t
5730203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
5731203945Sweongyo{
5732203945Sweongyo
5733203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
5734203945Sweongyo}
5735203945Sweongyo
5736203945Sweongyostatic uint32_t
5737203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
5738203945Sweongyo{
5739203945Sweongyo
5740203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
5741203945Sweongyo}
5742203945Sweongyo
5743203945Sweongyostatic void
5744203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
5745203945Sweongyo{
5746203945Sweongyo
5747203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
5748203945Sweongyo}
5749203945Sweongyo
5750203945Sweongyostatic void
5751203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
5752203945Sweongyo{
5753203945Sweongyo
5754203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
5755203945Sweongyo}
5756203945Sweongyo
5757203945Sweongyostatic int
5758203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
5759203945Sweongyo{
5760203945Sweongyo
5761203945Sweongyo	switch (rate) {
5762203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
5763203945Sweongyo	case 12:
5764203945Sweongyo		return (BWN_OFDM_RATE_6MB);
5765203945Sweongyo	case 18:
5766203945Sweongyo		return (BWN_OFDM_RATE_9MB);
5767203945Sweongyo	case 24:
5768203945Sweongyo		return (BWN_OFDM_RATE_12MB);
5769203945Sweongyo	case 36:
5770203945Sweongyo		return (BWN_OFDM_RATE_18MB);
5771203945Sweongyo	case 48:
5772203945Sweongyo		return (BWN_OFDM_RATE_24MB);
5773203945Sweongyo	case 72:
5774203945Sweongyo		return (BWN_OFDM_RATE_36MB);
5775203945Sweongyo	case 96:
5776203945Sweongyo		return (BWN_OFDM_RATE_48MB);
5777203945Sweongyo	case 108:
5778203945Sweongyo		return (BWN_OFDM_RATE_54MB);
5779203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
5780203945Sweongyo	case 2:
5781203945Sweongyo		return (BWN_CCK_RATE_1MB);
5782203945Sweongyo	case 4:
5783203945Sweongyo		return (BWN_CCK_RATE_2MB);
5784203945Sweongyo	case 11:
5785203945Sweongyo		return (BWN_CCK_RATE_5MB);
5786203945Sweongyo	case 22:
5787203945Sweongyo		return (BWN_CCK_RATE_11MB);
5788203945Sweongyo	}
5789203945Sweongyo
5790203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
5791203945Sweongyo	return (BWN_CCK_RATE_1MB);
5792203945Sweongyo}
5793203945Sweongyo
5794203945Sweongyostatic int
5795203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
5796203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
5797203945Sweongyo{
5798203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
5799203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5800203945Sweongyo	struct ieee80211_frame *wh;
5801203945Sweongyo	struct ieee80211_frame *protwh;
5802203945Sweongyo	struct ieee80211_frame_cts *cts;
5803203945Sweongyo	struct ieee80211_frame_rts *rts;
5804203945Sweongyo	const struct ieee80211_txparam *tp;
5805203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
5806287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5807203945Sweongyo	struct mbuf *mprot;
5808203945Sweongyo	unsigned int len;
5809203945Sweongyo	uint32_t macctl = 0;
5810203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
5811203945Sweongyo	uint16_t phyctl = 0;
5812203945Sweongyo	uint8_t rate, rate_fb;
5813203945Sweongyo
5814203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
5815203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
5816203945Sweongyo
5817203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
5818203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
5819203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
5820203945Sweongyo
5821203945Sweongyo	/*
5822203945Sweongyo	 * Find TX rate
5823203945Sweongyo	 */
5824203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
5825203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
5826203945Sweongyo		rate = rate_fb = tp->mgmtrate;
5827203945Sweongyo	else if (ismcast)
5828203945Sweongyo		rate = rate_fb = tp->mcastrate;
5829203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
5830203945Sweongyo		rate = rate_fb = tp->ucastrate;
5831203945Sweongyo	else {
5832299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
5833206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
5834203945Sweongyo		rate = ni->ni_txrate;
5835203945Sweongyo
5836203945Sweongyo		if (rix > 0)
5837203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
5838203945Sweongyo			    IEEE80211_RATE_VAL;
5839203945Sweongyo		else
5840203945Sweongyo			rate_fb = rate;
5841203945Sweongyo	}
5842203945Sweongyo
5843203945Sweongyo	sc->sc_tx_rate = rate;
5844203945Sweongyo
5845299032Sadrian	/* Note: this maps the select ieee80211 rate to hardware rate */
5846203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
5847203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
5848203945Sweongyo
5849203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
5850203945Sweongyo	    bwn_plcp_getcck(rate);
5851203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
5852203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
5853203945Sweongyo
5854299032Sadrian	/* XXX rate/rate_fb is the hardware rate */
5855203945Sweongyo	if ((rate_fb == rate) ||
5856203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
5857203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
5858203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
5859203945Sweongyo	else
5860203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
5861203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
5862203945Sweongyo
5863203945Sweongyo	/* XXX TX encryption */
5864203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
5865203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
5866203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
5867203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
5868203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
5869203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
5870203945Sweongyo
5871203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
5872203945Sweongyo	    BWN_TX_EFT_FB_CCK;
5873203945Sweongyo	txhdr->chan = phy->chan;
5874203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
5875203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
5876299032Sadrian	/* XXX preamble? obey net80211 */
5877203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
5878203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
5879203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
5880203945Sweongyo
5881203945Sweongyo	/* XXX TX antenna selection */
5882203945Sweongyo
5883203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
5884203945Sweongyo	case 0:
5885203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
5886203945Sweongyo		break;
5887203945Sweongyo	case 1:
5888203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
5889203945Sweongyo		break;
5890203945Sweongyo	case 2:
5891203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
5892203945Sweongyo		break;
5893203945Sweongyo	case 3:
5894203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
5895203945Sweongyo		break;
5896203945Sweongyo	case 4:
5897203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
5898203945Sweongyo		break;
5899203945Sweongyo	default:
5900203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5901203945Sweongyo	}
5902203945Sweongyo
5903203945Sweongyo	if (!ismcast)
5904203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
5905203945Sweongyo
5906203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
5907203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
5908203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
5909203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
5910203945Sweongyo
5911203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
5912203945Sweongyo		/* XXX RTS rate is always 1MB??? */
5913299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
5914203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
5915203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
5916203945Sweongyo
5917299032Sadrian		/* XXX 'rate' here is hardware rate now, not the net80211 rate */
5918203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
5919203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
5920203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
5921203945Sweongyo
5922203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
5923203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
5924203945Sweongyo			    (txhdr->body.old.rts_frame) :
5925203945Sweongyo			    (txhdr->body.new.rts_frame));
5926203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
5927203945Sweongyo			    protdur);
5928203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
5929203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
5930203945Sweongyo			    mprot->m_pkthdr.len);
5931203945Sweongyo			m_freem(mprot);
5932203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
5933203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
5934203945Sweongyo		} else {
5935203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
5936203945Sweongyo			    (txhdr->body.old.rts_frame) :
5937203945Sweongyo			    (txhdr->body.new.rts_frame));
5938299032Sadrian			/* XXX rate/rate_fb is the hardware rate */
5939203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
5940203945Sweongyo			    isshort);
5941203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
5942203945Sweongyo			    wh->i_addr2, protdur);
5943203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
5944203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
5945203945Sweongyo			    mprot->m_pkthdr.len);
5946203945Sweongyo			m_freem(mprot);
5947203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
5948203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
5949203945Sweongyo		}
5950203945Sweongyo		len += IEEE80211_CRC_LEN;
5951203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
5952203945Sweongyo		    &txhdr->body.old.rts_plcp :
5953203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
5954203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
5955203945Sweongyo		    rts_rate_fb);
5956203945Sweongyo
5957203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
5958203945Sweongyo		    (&txhdr->body.old.rts_frame) :
5959203945Sweongyo		    (&txhdr->body.new.rts_frame));
5960203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
5961203945Sweongyo
5962203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
5963203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
5964203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
5965203945Sweongyo		} else {
5966203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
5967203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
5968203945Sweongyo		}
5969203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
5970203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
5971203945Sweongyo	}
5972203945Sweongyo
5973203945Sweongyo	if (BWN_ISOLDFMT(mac))
5974203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
5975203945Sweongyo	else
5976203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
5977203945Sweongyo
5978203945Sweongyo	txhdr->macctl = htole32(macctl);
5979203945Sweongyo	txhdr->phyctl = htole16(phyctl);
5980203945Sweongyo
5981203945Sweongyo	/*
5982203945Sweongyo	 * TX radio tap
5983203945Sweongyo	 */
5984203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
5985203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
5986260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
5987203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
5988203945Sweongyo		if (isshort &&
5989203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
5990203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
5991203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
5992203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
5993203945Sweongyo
5994203945Sweongyo		ieee80211_radiotap_tx(vap, m);
5995203945Sweongyo	}
5996203945Sweongyo
5997203945Sweongyo	return (0);
5998203945Sweongyo}
5999203945Sweongyo
6000203945Sweongyostatic void
6001203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
6002203945Sweongyo    const uint8_t rate)
6003203945Sweongyo{
6004203945Sweongyo	uint32_t d, plen;
6005203945Sweongyo	uint8_t *raw = plcp->o.raw;
6006203945Sweongyo
6007203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
6008203945Sweongyo		d = bwn_plcp_getofdm(rate);
6009203945Sweongyo		KASSERT(!(octets & 0xf000),
6010203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6011203945Sweongyo		d |= (octets << 5);
6012203945Sweongyo		plcp->o.data = htole32(d);
6013203945Sweongyo	} else {
6014203945Sweongyo		plen = octets * 16 / rate;
6015203945Sweongyo		if ((octets * 16 % rate) > 0) {
6016203945Sweongyo			plen++;
6017203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
6018203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
6019203945Sweongyo				raw[1] = 0x84;
6020203945Sweongyo			} else
6021203945Sweongyo				raw[1] = 0x04;
6022203945Sweongyo		} else
6023203945Sweongyo			raw[1] = 0x04;
6024203945Sweongyo		plcp->o.data |= htole32(plen << 16);
6025203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
6026203945Sweongyo	}
6027203945Sweongyo}
6028203945Sweongyo
6029203945Sweongyostatic uint8_t
6030203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
6031203945Sweongyo{
6032204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6033203945Sweongyo	uint8_t mask;
6034203945Sweongyo
6035203945Sweongyo	if (n == 0)
6036203945Sweongyo		return (0);
6037203945Sweongyo	if (mac->mac_phy.gmode)
6038204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
6039203945Sweongyo	else
6040204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
6041203945Sweongyo	if (!(mask & (1 << (n - 1))))
6042203945Sweongyo		return (0);
6043203945Sweongyo	return (n);
6044203945Sweongyo}
6045203945Sweongyo
6046299028Sadrian/*
6047299028Sadrian * Return a fallback rate for the given rate.
6048299028Sadrian *
6049299028Sadrian * Note: Don't fall back from OFDM to CCK.
6050299028Sadrian */
6051203945Sweongyostatic uint8_t
6052203945Sweongyobwn_get_fbrate(uint8_t bitrate)
6053203945Sweongyo{
6054203945Sweongyo	switch (bitrate) {
6055299028Sadrian	/* CCK */
6056203945Sweongyo	case BWN_CCK_RATE_1MB:
6057203945Sweongyo		return (BWN_CCK_RATE_1MB);
6058203945Sweongyo	case BWN_CCK_RATE_2MB:
6059203945Sweongyo		return (BWN_CCK_RATE_1MB);
6060203945Sweongyo	case BWN_CCK_RATE_5MB:
6061203945Sweongyo		return (BWN_CCK_RATE_2MB);
6062203945Sweongyo	case BWN_CCK_RATE_11MB:
6063203945Sweongyo		return (BWN_CCK_RATE_5MB);
6064299028Sadrian
6065299028Sadrian	/* OFDM */
6066203945Sweongyo	case BWN_OFDM_RATE_6MB:
6067299028Sadrian		return (BWN_OFDM_RATE_6MB);
6068203945Sweongyo	case BWN_OFDM_RATE_9MB:
6069203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6070203945Sweongyo	case BWN_OFDM_RATE_12MB:
6071203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6072203945Sweongyo	case BWN_OFDM_RATE_18MB:
6073203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6074203945Sweongyo	case BWN_OFDM_RATE_24MB:
6075203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6076203945Sweongyo	case BWN_OFDM_RATE_36MB:
6077203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6078203945Sweongyo	case BWN_OFDM_RATE_48MB:
6079203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6080203945Sweongyo	case BWN_OFDM_RATE_54MB:
6081203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6082203945Sweongyo	}
6083203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6084203945Sweongyo	return (0);
6085203945Sweongyo}
6086203945Sweongyo
6087203945Sweongyostatic uint32_t
6088203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6089203945Sweongyo    uint32_t ctl, const void *_data, int len)
6090203945Sweongyo{
6091204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6092203945Sweongyo	uint32_t value = 0;
6093203945Sweongyo	const uint8_t *data = _data;
6094203945Sweongyo
6095203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
6096203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
6097203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6098203945Sweongyo
6099204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
6100203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
6101203945Sweongyo	if (len & 3) {
6102203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
6103203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
6104203945Sweongyo		data = &(data[len - 1]);
6105203945Sweongyo		switch (len & 3) {
6106203945Sweongyo		case 3:
6107203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
6108203945Sweongyo			value |= (uint32_t)(*data) << 16;
6109203945Sweongyo			data--;
6110203945Sweongyo		case 2:
6111203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
6112203945Sweongyo			value |= (uint32_t)(*data) << 8;
6113203945Sweongyo			data--;
6114203945Sweongyo		case 1:
6115203945Sweongyo			value |= (uint32_t)(*data);
6116203945Sweongyo		}
6117203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6118203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
6119203945Sweongyo	}
6120203945Sweongyo
6121203945Sweongyo	return (ctl);
6122203945Sweongyo}
6123203945Sweongyo
6124203945Sweongyostatic void
6125203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6126203945Sweongyo    uint16_t offset, uint32_t value)
6127203945Sweongyo{
6128203945Sweongyo
6129203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
6130203945Sweongyo}
6131203945Sweongyo
6132203945Sweongyostatic uint16_t
6133203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6134203945Sweongyo    uint16_t ctl, const void *_data, int len)
6135203945Sweongyo{
6136204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6137203945Sweongyo	const uint8_t *data = _data;
6138203945Sweongyo
6139203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6140203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6141203945Sweongyo
6142204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
6143203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
6144203945Sweongyo	if (len & 1) {
6145203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6146203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6147203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
6148203945Sweongyo	}
6149203945Sweongyo
6150203945Sweongyo	return (ctl);
6151203945Sweongyo}
6152203945Sweongyo
6153203945Sweongyostatic uint16_t
6154203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6155203945Sweongyo    uint16_t ctl, struct mbuf *m0)
6156203945Sweongyo{
6157203945Sweongyo	int i, j = 0;
6158203945Sweongyo	uint16_t data = 0;
6159203945Sweongyo	const uint8_t *buf;
6160203945Sweongyo	struct mbuf *m = m0;
6161203945Sweongyo
6162203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6163203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6164203945Sweongyo
6165203945Sweongyo	for (; m != NULL; m = m->m_next) {
6166203945Sweongyo		buf = mtod(m, const uint8_t *);
6167203945Sweongyo		for (i = 0; i < m->m_len; i++) {
6168203945Sweongyo			if (!((j++) % 2))
6169203945Sweongyo				data |= buf[i];
6170203945Sweongyo			else {
6171203945Sweongyo				data |= (buf[i] << 8);
6172203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6173203945Sweongyo				data = 0;
6174203945Sweongyo			}
6175203945Sweongyo		}
6176203945Sweongyo	}
6177203945Sweongyo	if (m0->m_pkthdr.len % 2) {
6178203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6179203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6180203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6181203945Sweongyo	}
6182203945Sweongyo
6183203945Sweongyo	return (ctl);
6184203945Sweongyo}
6185203945Sweongyo
6186203945Sweongyostatic void
6187203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
6188203945Sweongyo{
6189203945Sweongyo
6190203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
6191203945Sweongyo		return;
6192203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
6193203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
6194203945Sweongyo}
6195203945Sweongyo
6196203945Sweongyostatic struct bwn_dma_ring *
6197203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
6198203945Sweongyo{
6199203945Sweongyo
6200203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
6201203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6202203945Sweongyo
6203203945Sweongyo	switch (prio) {
6204203945Sweongyo	case 3:
6205203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
6206203945Sweongyo	case 2:
6207203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
6208203945Sweongyo	case 0:
6209203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6210203945Sweongyo	case 1:
6211203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
6212203945Sweongyo	}
6213203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6214204242Simp	return (NULL);
6215203945Sweongyo}
6216203945Sweongyo
6217203945Sweongyostatic int
6218203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
6219203945Sweongyo{
6220203945Sweongyo	int slot;
6221203945Sweongyo
6222204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
6223203945Sweongyo
6224203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
6225203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
6226203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
6227203945Sweongyo
6228203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
6229203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
6230203945Sweongyo	dr->dr_curslot = slot;
6231203945Sweongyo	dr->dr_usedslot++;
6232203945Sweongyo
6233203945Sweongyo	return (slot);
6234203945Sweongyo}
6235203945Sweongyo
6236203945Sweongyostatic struct bwn_pio_txqueue *
6237203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
6238203945Sweongyo    struct bwn_pio_txpkt **pack)
6239203945Sweongyo{
6240203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
6241203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
6242203945Sweongyo	unsigned int index;
6243203945Sweongyo
6244203945Sweongyo	switch (cookie & 0xf000) {
6245203945Sweongyo	case 0x1000:
6246203945Sweongyo		tq = &pio->wme[WME_AC_BK];
6247203945Sweongyo		break;
6248203945Sweongyo	case 0x2000:
6249203945Sweongyo		tq = &pio->wme[WME_AC_BE];
6250203945Sweongyo		break;
6251203945Sweongyo	case 0x3000:
6252203945Sweongyo		tq = &pio->wme[WME_AC_VI];
6253203945Sweongyo		break;
6254203945Sweongyo	case 0x4000:
6255203945Sweongyo		tq = &pio->wme[WME_AC_VO];
6256203945Sweongyo		break;
6257203945Sweongyo	case 0x5000:
6258203945Sweongyo		tq = &pio->mcast;
6259203945Sweongyo		break;
6260203945Sweongyo	}
6261203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
6262203945Sweongyo	if (tq == NULL)
6263203945Sweongyo		return (NULL);
6264203945Sweongyo	index = (cookie & 0x0fff);
6265203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
6266203945Sweongyo	if (index >= N(tq->tq_pkts))
6267203945Sweongyo		return (NULL);
6268203945Sweongyo	*pack = &tq->tq_pkts[index];
6269203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
6270203945Sweongyo	return (tq);
6271203945Sweongyo}
6272203945Sweongyo
6273203945Sweongyostatic void
6274203945Sweongyobwn_txpwr(void *arg, int npending)
6275203945Sweongyo{
6276203945Sweongyo	struct bwn_mac *mac = arg;
6277203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6278203945Sweongyo
6279203945Sweongyo	BWN_LOCK(sc);
6280203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
6281203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
6282203945Sweongyo		mac->mac_phy.set_txpwr(mac);
6283203945Sweongyo	BWN_UNLOCK(sc);
6284203945Sweongyo}
6285203945Sweongyo
6286203945Sweongyostatic void
6287203945Sweongyobwn_task_15s(struct bwn_mac *mac)
6288203945Sweongyo{
6289203945Sweongyo	uint16_t reg;
6290203945Sweongyo
6291203945Sweongyo	if (mac->mac_fw.opensource) {
6292203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
6293203945Sweongyo		if (reg) {
6294203945Sweongyo			bwn_restart(mac, "fw watchdog");
6295203945Sweongyo			return;
6296203945Sweongyo		}
6297203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
6298203945Sweongyo	}
6299203945Sweongyo	if (mac->mac_phy.task_15s)
6300203945Sweongyo		mac->mac_phy.task_15s(mac);
6301203945Sweongyo
6302203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
6303203945Sweongyo}
6304203945Sweongyo
6305203945Sweongyostatic void
6306203945Sweongyobwn_task_30s(struct bwn_mac *mac)
6307203945Sweongyo{
6308203945Sweongyo
6309203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
6310203945Sweongyo		return;
6311203945Sweongyo	mac->mac_noise.noi_running = 1;
6312203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
6313203945Sweongyo
6314203945Sweongyo	bwn_noise_gensample(mac);
6315203945Sweongyo}
6316203945Sweongyo
6317203945Sweongyostatic void
6318203945Sweongyobwn_task_60s(struct bwn_mac *mac)
6319203945Sweongyo{
6320203945Sweongyo
6321203945Sweongyo	if (mac->mac_phy.task_60s)
6322203945Sweongyo		mac->mac_phy.task_60s(mac);
6323203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
6324203945Sweongyo}
6325203945Sweongyo
6326203945Sweongyostatic void
6327203945Sweongyobwn_tasks(void *arg)
6328203945Sweongyo{
6329203945Sweongyo	struct bwn_mac *mac = arg;
6330203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6331203945Sweongyo
6332203945Sweongyo	BWN_ASSERT_LOCKED(sc);
6333203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
6334203945Sweongyo		return;
6335203945Sweongyo
6336203945Sweongyo	if (mac->mac_task_state % 4 == 0)
6337203945Sweongyo		bwn_task_60s(mac);
6338203945Sweongyo	if (mac->mac_task_state % 2 == 0)
6339203945Sweongyo		bwn_task_30s(mac);
6340203945Sweongyo	bwn_task_15s(mac);
6341203945Sweongyo
6342203945Sweongyo	mac->mac_task_state++;
6343203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
6344203945Sweongyo}
6345203945Sweongyo
6346203945Sweongyostatic int
6347203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
6348203945Sweongyo{
6349203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6350203945Sweongyo
6351203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
6352203945Sweongyo
6353203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
6354203945Sweongyo	case 0xb:
6355203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6356203945Sweongyo	case 0xf:
6357203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6358203945Sweongyo	case 0xa:
6359203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6360203945Sweongyo	case 0xe:
6361203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6362203945Sweongyo	case 0x9:
6363203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6364203945Sweongyo	case 0xd:
6365203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6366203945Sweongyo	case 0x8:
6367203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6368203945Sweongyo	case 0xc:
6369203945Sweongyo		return (BWN_OFDM_RATE_54MB);
6370203945Sweongyo	}
6371203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
6372203945Sweongyo	    plcp->o.raw[0] & 0xf);
6373203945Sweongyo	return (-1);
6374203945Sweongyo}
6375203945Sweongyo
6376203945Sweongyostatic int
6377203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
6378203945Sweongyo{
6379203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6380203945Sweongyo
6381203945Sweongyo	switch (plcp->o.raw[0]) {
6382203945Sweongyo	case 0x0a:
6383203945Sweongyo		return (BWN_CCK_RATE_1MB);
6384203945Sweongyo	case 0x14:
6385203945Sweongyo		return (BWN_CCK_RATE_2MB);
6386203945Sweongyo	case 0x37:
6387203945Sweongyo		return (BWN_CCK_RATE_5MB);
6388203945Sweongyo	case 0x6e:
6389203945Sweongyo		return (BWN_CCK_RATE_11MB);
6390203945Sweongyo	}
6391203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
6392203945Sweongyo	return (-1);
6393203945Sweongyo}
6394203945Sweongyo
6395203945Sweongyostatic void
6396203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
6397203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
6398203945Sweongyo    int rssi, int noise)
6399203945Sweongyo{
6400203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6401203945Sweongyo	const struct ieee80211_frame_min *wh;
6402203945Sweongyo	uint64_t tsf;
6403203945Sweongyo	uint16_t low_mactime_now;
6404203945Sweongyo
6405203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
6406203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
6407203945Sweongyo
6408203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
6409260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
6410203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
6411203945Sweongyo
6412203945Sweongyo	bwn_tsf_read(mac, &tsf);
6413203945Sweongyo	low_mactime_now = tsf;
6414203945Sweongyo	tsf = tsf & ~0xffffULL;
6415203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
6416203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
6417203945Sweongyo		tsf -= 0x10000;
6418203945Sweongyo
6419203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
6420203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
6421203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
6422203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
6423203945Sweongyo}
6424203945Sweongyo
6425203945Sweongyostatic void
6426203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
6427203945Sweongyo{
6428203945Sweongyo	uint32_t low, high;
6429203945Sweongyo
6430204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
6431203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6432203945Sweongyo
6433203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
6434203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
6435203945Sweongyo	*tsf = high;
6436203945Sweongyo	*tsf <<= 32;
6437203945Sweongyo	*tsf |= low;
6438203945Sweongyo}
6439203945Sweongyo
6440203945Sweongyostatic int
6441203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
6442203945Sweongyo{
6443203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
6444203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6445203945Sweongyo	bus_addr_t lowaddr = 0;
6446203945Sweongyo	int error;
6447203945Sweongyo
6448204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
6449203945Sweongyo		return (0);
6450203945Sweongyo
6451204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
6452203945Sweongyo
6453203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
6454203945Sweongyo
6455203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
6456203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
6457203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
6458203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
6459203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
6460203945Sweongyo	else
6461203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
6462203945Sweongyo
6463203945Sweongyo	/*
6464203945Sweongyo	 * Create top level DMA tag
6465203945Sweongyo	 */
6466203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
6467203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
6468203945Sweongyo			       lowaddr,			/* lowaddr */
6469203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
6470203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
6471280347Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
6472203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
6473203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
6474203945Sweongyo			       0,			/* flags */
6475203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
6476203945Sweongyo			       &dma->parent_dtag);
6477203945Sweongyo	if (error) {
6478203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
6479203945Sweongyo		return (error);
6480203945Sweongyo	}
6481203945Sweongyo
6482203945Sweongyo	/*
6483203945Sweongyo	 * Create TX/RX mbuf DMA tag
6484203945Sweongyo	 */
6485203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6486203945Sweongyo				1,
6487203945Sweongyo				0,
6488203945Sweongyo				BUS_SPACE_MAXADDR,
6489203945Sweongyo				BUS_SPACE_MAXADDR,
6490203945Sweongyo				NULL, NULL,
6491203945Sweongyo				MCLBYTES,
6492203945Sweongyo				1,
6493203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6494203945Sweongyo				0,
6495203945Sweongyo				NULL, NULL,
6496203945Sweongyo				&dma->rxbuf_dtag);
6497203945Sweongyo	if (error) {
6498203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
6499203945Sweongyo		goto fail0;
6500203945Sweongyo	}
6501203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6502203945Sweongyo				1,
6503203945Sweongyo				0,
6504203945Sweongyo				BUS_SPACE_MAXADDR,
6505203945Sweongyo				BUS_SPACE_MAXADDR,
6506203945Sweongyo				NULL, NULL,
6507203945Sweongyo				MCLBYTES,
6508203945Sweongyo				1,
6509203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6510203945Sweongyo				0,
6511203945Sweongyo				NULL, NULL,
6512203945Sweongyo				&dma->txbuf_dtag);
6513203945Sweongyo	if (error) {
6514203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
6515203945Sweongyo		goto fail1;
6516203945Sweongyo	}
6517203945Sweongyo
6518203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
6519203945Sweongyo	if (!dma->wme[WME_AC_BK])
6520203945Sweongyo		goto fail2;
6521203945Sweongyo
6522203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
6523203945Sweongyo	if (!dma->wme[WME_AC_BE])
6524203945Sweongyo		goto fail3;
6525203945Sweongyo
6526203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
6527203945Sweongyo	if (!dma->wme[WME_AC_VI])
6528203945Sweongyo		goto fail4;
6529203945Sweongyo
6530203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
6531203945Sweongyo	if (!dma->wme[WME_AC_VO])
6532203945Sweongyo		goto fail5;
6533203945Sweongyo
6534203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
6535203945Sweongyo	if (!dma->mcast)
6536203945Sweongyo		goto fail6;
6537203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
6538203945Sweongyo	if (!dma->rx)
6539203945Sweongyo		goto fail7;
6540203945Sweongyo
6541203945Sweongyo	return (error);
6542203945Sweongyo
6543203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
6544203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
6545203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
6546203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
6547203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
6548203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
6549203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
6550203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
6551203945Sweongyo	return (error);
6552203945Sweongyo}
6553203945Sweongyo
6554203945Sweongyostatic struct bwn_dma_ring *
6555203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
6556203945Sweongyo    uint16_t cookie, int *slot)
6557203945Sweongyo{
6558203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
6559203945Sweongyo	struct bwn_dma_ring *dr;
6560203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6561203945Sweongyo
6562203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
6563203945Sweongyo
6564203945Sweongyo	switch (cookie & 0xf000) {
6565203945Sweongyo	case 0x1000:
6566203945Sweongyo		dr = dma->wme[WME_AC_BK];
6567203945Sweongyo		break;
6568203945Sweongyo	case 0x2000:
6569203945Sweongyo		dr = dma->wme[WME_AC_BE];
6570203945Sweongyo		break;
6571203945Sweongyo	case 0x3000:
6572203945Sweongyo		dr = dma->wme[WME_AC_VI];
6573203945Sweongyo		break;
6574203945Sweongyo	case 0x4000:
6575203945Sweongyo		dr = dma->wme[WME_AC_VO];
6576203945Sweongyo		break;
6577203945Sweongyo	case 0x5000:
6578203945Sweongyo		dr = dma->mcast;
6579203945Sweongyo		break;
6580203945Sweongyo	default:
6581204242Simp		dr = NULL;
6582203945Sweongyo		KASSERT(0 == 1,
6583203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
6584203945Sweongyo	}
6585203945Sweongyo	*slot = (cookie & 0x0fff);
6586203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
6587203945Sweongyo		/*
6588203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
6589203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
6590203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
6591203945Sweongyo		 */
6592203945Sweongyo		KASSERT(status->seq == dma->lastseq,
6593203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6594203945Sweongyo		device_printf(sc->sc_dev,
6595203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
6596203945Sweongyo		    dr->dr_numslots);
6597203945Sweongyo		return (NULL);
6598203945Sweongyo	}
6599203945Sweongyo	dma->lastseq = status->seq;
6600203945Sweongyo	return (dr);
6601203945Sweongyo}
6602203945Sweongyo
6603203945Sweongyostatic void
6604203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
6605203945Sweongyo{
6606203945Sweongyo	struct bwn_dma *dma;
6607203945Sweongyo
6608203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
6609203945Sweongyo		return;
6610203945Sweongyo	dma = &mac->mac_method.dma;
6611203945Sweongyo
6612203945Sweongyo	bwn_dma_ringstop(&dma->rx);
6613203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
6614203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
6615203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
6616203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
6617203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
6618203945Sweongyo}
6619203945Sweongyo
6620203945Sweongyostatic void
6621203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
6622203945Sweongyo{
6623203945Sweongyo
6624203945Sweongyo	if (dr == NULL)
6625203945Sweongyo		return;
6626203945Sweongyo
6627203945Sweongyo	bwn_dma_cleanup(*dr);
6628203945Sweongyo}
6629203945Sweongyo
6630203945Sweongyostatic void
6631203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
6632203945Sweongyo{
6633203945Sweongyo	struct bwn_pio *pio;
6634203945Sweongyo
6635203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
6636203945Sweongyo		return;
6637203945Sweongyo	pio = &mac->mac_method.pio;
6638203945Sweongyo
6639203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
6640203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
6641203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
6642203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
6643203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
6644203945Sweongyo}
6645203945Sweongyo
6646203945Sweongyostatic void
6647203945Sweongyobwn_led_attach(struct bwn_mac *mac)
6648203945Sweongyo{
6649203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6650203945Sweongyo	const uint8_t *led_act = NULL;
6651203945Sweongyo	uint16_t val[BWN_LED_MAX];
6652203945Sweongyo	int i;
6653203945Sweongyo
6654203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
6655203945Sweongyo	sc->sc_led_blink = 1;
6656203945Sweongyo
6657203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
6658204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
6659204922Sweongyo		    bwn_vendor_led_act[i].vid) {
6660203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
6661203945Sweongyo			break;
6662203945Sweongyo		}
6663203945Sweongyo	}
6664203945Sweongyo	if (led_act == NULL)
6665203945Sweongyo		led_act = bwn_default_led_act;
6666203945Sweongyo
6667204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
6668204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
6669204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
6670204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
6671203945Sweongyo
6672203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
6673203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
6674203945Sweongyo
6675203945Sweongyo		if (val[i] == 0xff) {
6676203945Sweongyo			led->led_act = led_act[i];
6677203945Sweongyo		} else {
6678203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
6679203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
6680203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
6681203945Sweongyo		}
6682203945Sweongyo		led->led_mask = (1 << i);
6683203945Sweongyo
6684203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
6685203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
6686203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
6687203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
6688203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
6689203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
6690203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
6691203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
6692203945Sweongyo
6693203945Sweongyo			if (sc->sc_blink_led == NULL) {
6694203945Sweongyo				sc->sc_blink_led = led;
6695203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
6696203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
6697203945Sweongyo			}
6698203945Sweongyo		}
6699203945Sweongyo
6700203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
6701203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
6702203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
6703203945Sweongyo	}
6704203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
6705203945Sweongyo}
6706203945Sweongyo
6707203945Sweongyostatic __inline uint16_t
6708203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
6709203945Sweongyo{
6710203945Sweongyo
6711203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
6712203945Sweongyo		on = !on;
6713203945Sweongyo	if (on)
6714203945Sweongyo		val |= led->led_mask;
6715203945Sweongyo	else
6716203945Sweongyo		val &= ~led->led_mask;
6717203945Sweongyo	return val;
6718203945Sweongyo}
6719203945Sweongyo
6720203945Sweongyostatic void
6721203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
6722203945Sweongyo{
6723203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6724287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
6725203945Sweongyo	uint16_t val;
6726203945Sweongyo	int i;
6727203945Sweongyo
6728203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
6729203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
6730203945Sweongyo		sc->sc_led_blinking = 0;
6731203945Sweongyo	}
6732203945Sweongyo
6733287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0)
6734203945Sweongyo		return;
6735203945Sweongyo
6736203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
6737203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
6738203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
6739203945Sweongyo		int on;
6740203945Sweongyo
6741203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
6742203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
6743203945Sweongyo			continue;
6744203945Sweongyo
6745203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
6746203945Sweongyo		    nstate != IEEE80211_S_INIT)
6747203945Sweongyo			continue;
6748203945Sweongyo
6749203945Sweongyo		switch (led->led_act) {
6750203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
6751203945Sweongyo			on = 1;
6752203945Sweongyo			break;
6753203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
6754203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
6755203945Sweongyo			on = 0;
6756203945Sweongyo			break;
6757203945Sweongyo		default:
6758203945Sweongyo			on = 1;
6759203945Sweongyo			switch (nstate) {
6760203945Sweongyo			case IEEE80211_S_INIT:
6761203945Sweongyo				on = 0;
6762203945Sweongyo				break;
6763203945Sweongyo			case IEEE80211_S_RUN:
6764203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
6765203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
6766203945Sweongyo					on = 0;
6767203945Sweongyo				break;
6768203945Sweongyo			default:
6769203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
6770203945Sweongyo					on = 0;
6771203945Sweongyo				break;
6772203945Sweongyo			}
6773203945Sweongyo			break;
6774203945Sweongyo		}
6775203945Sweongyo
6776203945Sweongyo		val = bwn_led_onoff(led, val, on);
6777203945Sweongyo	}
6778203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
6779203945Sweongyo}
6780203945Sweongyo
6781203945Sweongyostatic void
6782203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
6783203945Sweongyo{
6784203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6785204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
6786204922Sweongyo	int rate;
6787203945Sweongyo
6788204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
6789204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
6790204922Sweongyo			return;
6791204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
6792204922Sweongyo			return;
6793204922Sweongyo	}
6794203945Sweongyo
6795204922Sweongyo	sc->sc_led_ticks = ticks;
6796204922Sweongyo	if (sc->sc_led_blinking)
6797204922Sweongyo		return;
6798203945Sweongyo
6799204922Sweongyo	switch (event) {
6800204922Sweongyo	case BWN_LED_EVENT_RX:
6801204922Sweongyo		rate = sc->sc_rx_rate;
6802204922Sweongyo		break;
6803204922Sweongyo	case BWN_LED_EVENT_TX:
6804204922Sweongyo		rate = sc->sc_tx_rate;
6805204922Sweongyo		break;
6806204922Sweongyo	case BWN_LED_EVENT_POLL:
6807204922Sweongyo		rate = 0;
6808204922Sweongyo		break;
6809204922Sweongyo	default:
6810204922Sweongyo		panic("unknown LED event %d\n", event);
6811204922Sweongyo		break;
6812204922Sweongyo	}
6813204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
6814204922Sweongyo	    bwn_led_duration[rate].off_dur);
6815203945Sweongyo}
6816203945Sweongyo
6817203945Sweongyostatic void
6818203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
6819203945Sweongyo{
6820203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6821204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
6822204922Sweongyo	uint16_t val;
6823203945Sweongyo
6824204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
6825204922Sweongyo	val = bwn_led_onoff(led, val, 1);
6826204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
6827203945Sweongyo
6828204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
6829204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
6830204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
6831204922Sweongyo	}
6832203945Sweongyo
6833204922Sweongyo	sc->sc_led_blinking = 1;
6834204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
6835203945Sweongyo
6836204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
6837203945Sweongyo}
6838203945Sweongyo
6839203945Sweongyostatic void
6840203945Sweongyobwn_led_blink_next(void *arg)
6841203945Sweongyo{
6842203945Sweongyo	struct bwn_mac *mac = arg;
6843204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6844204922Sweongyo	uint16_t val;
6845203945Sweongyo
6846204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
6847204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
6848204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
6849203945Sweongyo
6850204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
6851204922Sweongyo	    bwn_led_blink_end, mac);
6852203945Sweongyo}
6853203945Sweongyo
6854203945Sweongyostatic void
6855203945Sweongyobwn_led_blink_end(void *arg)
6856203945Sweongyo{
6857203945Sweongyo	struct bwn_mac *mac = arg;
6858204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6859203945Sweongyo
6860204922Sweongyo	sc->sc_led_blinking = 0;
6861203945Sweongyo}
6862203945Sweongyo
6863203945Sweongyostatic int
6864203945Sweongyobwn_suspend(device_t dev)
6865203945Sweongyo{
6866203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
6867203945Sweongyo
6868287197Sglebius	BWN_LOCK(sc);
6869287197Sglebius	bwn_stop(sc);
6870287197Sglebius	BWN_UNLOCK(sc);
6871203945Sweongyo	return (0);
6872203945Sweongyo}
6873203945Sweongyo
6874203945Sweongyostatic int
6875203945Sweongyobwn_resume(device_t dev)
6876203945Sweongyo{
6877203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
6878287197Sglebius	int error = EDOOFUS;
6879203945Sweongyo
6880287197Sglebius	BWN_LOCK(sc);
6881287197Sglebius	if (sc->sc_ic.ic_nrunning > 0)
6882287197Sglebius		error = bwn_init(sc);
6883287197Sglebius	BWN_UNLOCK(sc);
6884287197Sglebius	if (error == 0)
6885287197Sglebius		ieee80211_start_all(&sc->sc_ic);
6886203945Sweongyo	return (0);
6887203945Sweongyo}
6888203945Sweongyo
6889203945Sweongyostatic void
6890203945Sweongyobwn_rfswitch(void *arg)
6891203945Sweongyo{
6892203945Sweongyo	struct bwn_softc *sc = arg;
6893203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
6894203945Sweongyo	int cur = 0, prev = 0;
6895203945Sweongyo
6896203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
6897203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
6898203945Sweongyo
6899285436Sadrian	if (mac->mac_phy.rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
6900203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
6901203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
6902203945Sweongyo			cur = 1;
6903203945Sweongyo	} else {
6904203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
6905203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
6906203945Sweongyo			cur = 1;
6907203945Sweongyo	}
6908203945Sweongyo
6909203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
6910203945Sweongyo		prev = 1;
6911203945Sweongyo
6912203945Sweongyo	if (cur != prev) {
6913203945Sweongyo		if (cur)
6914203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
6915203945Sweongyo		else
6916203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
6917203945Sweongyo
6918203945Sweongyo		device_printf(sc->sc_dev,
6919203945Sweongyo		    "status of RF switch is changed to %s\n",
6920203945Sweongyo		    cur ? "ON" : "OFF");
6921203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
6922203945Sweongyo			if (cur)
6923203945Sweongyo				bwn_rf_turnon(mac);
6924203945Sweongyo			else
6925203945Sweongyo				bwn_rf_turnoff(mac);
6926203945Sweongyo		}
6927203945Sweongyo	}
6928203945Sweongyo
6929203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
6930203945Sweongyo}
6931203945Sweongyo
6932203945Sweongyostatic void
6933204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
6934204257Sweongyo{
6935204257Sweongyo	device_t dev = sc->sc_dev;
6936204257Sweongyo	struct bwn_mac *mac;
6937204257Sweongyo	struct bwn_stats *stats;
6938204257Sweongyo
6939204257Sweongyo	/* XXX assume that count of MAC is only 1. */
6940204257Sweongyo
6941204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
6942204257Sweongyo		return;
6943204257Sweongyo	stats = &mac->mac_stats;
6944204257Sweongyo
6945217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
6946204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
6947204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
6948217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
6949204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
6950204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
6951217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
6952204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
6953204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
6954204257Sweongyo
6955204257Sweongyo#ifdef BWN_DEBUG
6956204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
6957204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
6958204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
6959204257Sweongyo#endif
6960204257Sweongyo}
6961204257Sweongyo
6962203945Sweongyostatic device_method_t bwn_methods[] = {
6963203945Sweongyo	/* Device interface */
6964203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
6965203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
6966203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
6967203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
6968203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
6969227848Smarius	DEVMETHOD_END
6970203945Sweongyo};
6971203945Sweongyostatic driver_t bwn_driver = {
6972203945Sweongyo	"bwn",
6973203945Sweongyo	bwn_methods,
6974203945Sweongyo	sizeof(struct bwn_softc)
6975203945Sweongyo};
6976203945Sweongyostatic devclass_t bwn_devclass;
6977203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
6978203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
6979203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
6980203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
6981203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
6982299097SadrianMODULE_VERSION(bwn, 1);
6983